// libstd features
pub debug_jemalloc: bool,
pub use_jemalloc: bool,
+ pub backtrace: bool, // support for RUST_BACKTRACE
// misc
pub channel: String,
debuginfo: Option<bool>,
debug_jemalloc: Option<bool>,
use_jemalloc: Option<bool>,
+ backtrace: Option<bool>,
default_linker: Option<String>,
default_ar: Option<String>,
channel: Option<String>,
let mut config = Config::default();
config.llvm_optimize = true;
config.use_jemalloc = true;
+ config.backtrace = true;
config.rust_optimize = true;
config.rust_optimize_tests = true;
config.submodules = true;
set(&mut config.rust_rpath, rust.rpath);
set(&mut config.debug_jemalloc, rust.debug_jemalloc);
set(&mut config.use_jemalloc, rust.use_jemalloc);
+ set(&mut config.backtrace, rust.backtrace);
set(&mut config.channel, rust.channel.clone());
config.rustc_default_linker = rust.default_linker.clone();
config.rustc_default_ar = rust.default_ar.clone();
# Whether or not jemalloc is built with its debug option set
#debug-jemalloc = false
+# Whether or not `panic!`s generate backtraces (RUST_BACKTRACE)
+#backtrace = true
+
# The default linker that will be used by the generated compiler. Note that this
# is not the linker used to link said compiler.
#default-linker = "cc"
if self.config.use_jemalloc {
features.push_str(" jemalloc");
}
+ if self.config.backtrace {
+ features.push_str(" backtrace");
+ }
return features
}
pub fn check(build: &mut Build) {
let mut checked = HashSet::new();
let path = env::var_os("PATH").unwrap_or(OsString::new());
+ // On Windows, quotes are invalid characters for filename paths, and if
+ // one is present as part of the PATH then that can lead to the system
+ // being unable to identify the files properly. See
+ // https://github.com/rust-lang/rust/issues/34959 for more details.
+ if cfg!(windows) {
+ if path.to_string_lossy().contains("\"") {
+ panic!("PATH contains invalid character '\"'");
+ }
+ }
let mut need_cmd = |cmd: &OsStr| {
if !checked.insert(cmd.to_owned()) {
return
# some_closure(1) }
```
-Because `Fn` is a trait, we can bound our generic with it. In this case, our
-closure takes a `i32` as an argument and returns an `i32`, and so the generic
-bound we use is `Fn(i32) -> i32`.
+Because `Fn` is a trait, we can use it as a bound for our generic type. In
+this case, our closure takes a `i32` as an argument and returns an `i32`, and
+so the generic bound we use is `Fn(i32) -> i32`.
There’s one other key point here: because we’re bounding a generic with a
trait, this will get monomorphized, and therefore, we’ll be doing static
# The "nullable pointer optimization"
-Certain types are defined to not be NULL. This includes references (`&T`,
-`&mut T`), boxes (`Box<T>`), and function pointers (`extern "abi" fn()`).
-When interfacing with C, pointers that might be NULL are often used.
-As a special case, a generic `enum` that contains exactly two variants, one of
-which contains no data and the other containing a single field, is eligible
-for the "nullable pointer optimization". When such an enum is instantiated
-with one of the non-nullable types, it is represented as a single pointer,
-and the non-data variant is represented as the NULL pointer. So
-`Option<extern "C" fn(c_int) -> c_int>` is how one represents a nullable
-function pointer using the C ABI.
+Certain Rust types are defined to never be `null`. This includes references (`&T`,
+`&mut T`), boxes (`Box<T>`), and function pointers (`extern "abi" fn()`). When
+interfacing with C, pointers that might be `null` are often used, which would seem to
+require some messy `transmute`s and/or unsafe code to handle conversions to/from Rust types.
+However, the language provides a workaround.
+
+As a special case, an `enum` is eligible for the "nullable pointer optimization" if it contains
+exactly two variants, one of which contains no data and the other contains a field of one of the
+non-nullable types listed above. This means no extra space is required for a discriminant; rather,
+the empty variant is represented by putting a `null` value into the non-nullable field. This is
+called an "optimization", but unlike other optimizations it is guaranteed to apply to eligible
+types.
+
+The most common type that takes advantage of the nullable pointer optimization is `Option<T>`,
+where `None` corresponds to `null`. So `Option<extern "C" fn(c_int) -> c_int>` is a correct way
+to represent a nullable function pointer using the C ABI (corresponding to the C type
+`int (*)(int)`).
+
+Here is a contrived example. Let's say some C library has a facility for registering a
+callback, which gets called in certain situations. The callback is passed a function pointer
+and an integer and it is supposed to run the function with the integer as a parameter. So
+we have function pointers flying across the FFI boundary in both directions.
+
+```rust
+# #![feature(libc)]
+extern crate libc;
+use libc::c_int;
+
+# #[cfg(hidden)]
+extern "C" {
+ /// Register the callback.
+ fn register(cb: Option<extern "C" fn(Option<extern "C" fn(c_int) -> c_int>, c_int) -> c_int>);
+}
+# unsafe fn register(_: Option<extern "C" fn(Option<extern "C" fn(c_int) -> c_int>,
+# c_int) -> c_int>)
+# {}
+
+/// This fairly useless function receives a function pointer and an integer
+/// from C, and returns the result of calling the function with the integer.
+/// In case no function is provided, it squares the integer by default.
+extern "C" fn apply(process: Option<extern "C" fn(c_int) -> c_int>, int: c_int) -> c_int {
+ match process {
+ Some(f) => f(int),
+ None => int * int
+ }
+}
+
+fn main() {
+ unsafe {
+ register(Some(apply));
+ }
+}
+```
+
+And the code on the C side looks like this:
+
+```c
+void register(void (*f)(void (*)(int), int)) {
+ ...
+}
+```
+
+No `transmute` required!
# Calling Rust code from C
--- /dev/null
+#!/usr/bin/env python
+#
+# Copyright 2011-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.
+
+# This script uses the following Unicode tables:
+# - Categories.txt
+
+import os
+import subprocess
+
+def to_ranges(iter):
+ current = None
+ for i in iter:
+ if current is None or i != current[1] or i in (0x10000, 0x20000):
+ if current is not None:
+ yield tuple(current)
+ current = [i, i + 1]
+ else:
+ current[1] += 1
+ if current is not None:
+ yield tuple(current)
+
+def get_escaped(dictionary):
+ for i in range(0x110000):
+ if dictionary.get(i, "Cn") in "Cc Cf Cs Co Cn Zl Zp Zs".split() and i != ord(' '):
+ yield i
+
+def get_file(f):
+ try:
+ return open(os.path.basename(f))
+ except FileNotFoundError:
+ subprocess.run(["curl", "-O", f], check=True)
+ return open(os.path.basename(f))
+
+def main():
+ file = get_file("http://www.unicode.org/notes/tn36/Categories.txt")
+
+ dictionary = {int(line.split()[0], 16): line.split()[1] for line in file}
+
+ CUTOFF=0x10000
+ singletons0 = []
+ singletons1 = []
+ normal0 = []
+ normal1 = []
+ extra = []
+
+ for a, b in to_ranges(get_escaped(dictionary)):
+ if a > 2 * CUTOFF:
+ extra.append((a, b - a))
+ elif a == b - 1:
+ if a & CUTOFF:
+ singletons1.append(a & ~CUTOFF)
+ else:
+ singletons0.append(a)
+ elif a == b - 2:
+ if a & CUTOFF:
+ singletons1.append(a & ~CUTOFF)
+ singletons1.append((a + 1) & ~CUTOFF)
+ else:
+ singletons0.append(a)
+ singletons0.append(a + 1)
+ else:
+ if a >= 2 * CUTOFF:
+ extra.append((a, b - a))
+ elif a & CUTOFF:
+ normal1.append((a & ~CUTOFF, b - a))
+ else:
+ normal0.append((a, b - a))
+
+ print("""\
+// 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.
+
+// NOTE: The following code was generated by "src/etc/char_private.py",
+// do not edit directly!
+
+use slice::SliceExt;
+
+fn check(x: u16, singletons: &[u16], normal: &[u16]) -> bool {
+ for &s in singletons {
+ if x == s {
+ return false;
+ } else if x < s {
+ break;
+ }
+ }
+ for w in normal.chunks(2) {
+ let start = w[0];
+ let len = w[1];
+ let difference = (x as i32) - (start as i32);
+ if 0 <= difference {
+ if difference < len as i32 {
+ return false;
+ }
+ } else {
+ break;
+ }
+ }
+ true
+}
+
+pub fn is_printable(x: char) -> bool {
+ let x = x as u32;
+ let lower = x as u16;
+ if x < 0x10000 {
+ check(lower, SINGLETONS0, NORMAL0)
+ } else if x < 0x20000 {
+ check(lower, SINGLETONS1, NORMAL1)
+ } else {\
+""")
+ for a, b in extra:
+ print(" if 0x{:x} <= x && x < 0x{:x} {{".format(a, a + b))
+ print(" return false;")
+ print(" }")
+ print("""\
+ true
+ }
+}\
+""")
+ print()
+ print("const SINGLETONS0: &'static [u16] = &[")
+ for s in singletons0:
+ print(" 0x{:x},".format(s))
+ print("];")
+ print("const SINGLETONS1: &'static [u16] = &[")
+ for s in singletons1:
+ print(" 0x{:x},".format(s))
+ print("];")
+ print("const NORMAL0: &'static [u16] = &[")
+ for a, b in normal0:
+ print(" 0x{:x}, 0x{:x},".format(a, b))
+ print("];")
+ print("const NORMAL1: &'static [u16] = &[")
+ for a, b in normal1:
+ print(" 0x{:x}, 0x{:x},".format(a, b))
+ print("];")
+
+if __name__ == '__main__':
+ main()
//! in this case, if one uses the format string `{<arg>:<spec>.*}`, then the `<arg>` part refers
//! to the *value* to print, and the `precision` must come in the input preceding `<arg>`.
//!
-//! For example, these:
+//! For example, the following calls all print the same thing `Hello x is 0.01000`:
//!
//! ```
-//! // Hello {arg 0 (x)} is {arg 1 (0.01) with precision specified inline (5)}
+//! // Hello {arg 0 ("x")} is {arg 1 (0.01) with precision specified inline (5)}
//! println!("Hello {0} is {1:.5}", "x", 0.01);
//!
-//! // Hello {arg 1 (x)} is {arg 2 (0.01) with precision specified in arg 0 (5)}
+//! // Hello {arg 1 ("x")} is {arg 2 (0.01) with precision specified in arg 0 (5)}
//! println!("Hello {1} is {2:.0$}", 5, "x", 0.01);
//!
-//! // Hello {arg 0 (x)} is {arg 2 (0.01) with precision specified in arg 1 (5)}
+//! // Hello {arg 0 ("x")} is {arg 2 (0.01) with precision specified in arg 1 (5)}
//! println!("Hello {0} is {2:.1$}", "x", 5, 0.01);
//!
-//! // Hello {next arg (x)} is {second of next two args (0.01) with precision
+//! // Hello {next arg ("x")} is {second of next two args (0.01) with precision
//! // specified in first of next two args (5)}
//! println!("Hello {} is {:.*}", "x", 5, 0.01);
//!
-//! // Hello {next arg (x)} is {arg 2 (0.01) with precision
+//! // Hello {next arg ("x")} is {arg 2 (0.01) with precision
//! // specified in its predecessor (5)}
//! println!("Hello {} is {2:.*}", "x", 5, 0.01);
//!
-//! // Hello {next arg (x)} is {arg "number" (0.01) with precision specified
+//! // Hello {next arg ("x")} is {arg "number" (0.01) with precision specified
//! // in arg "prec" (5)}
//! println!("Hello {} is {number:.prec$}", "x", prec = 5, number = 0.01);
//! ```
//!
-//! All print the same thing:
-//!
-//! ```text
-//! Hello x is 0.01000
-//! ```
-//!
//! While these:
//!
//! ```
#![feature(allow_internal_unstable)]
#![feature(box_patterns)]
#![feature(box_syntax)]
+#![cfg_attr(not(test), feature(char_escape_debug))]
#![feature(core_intrinsics)]
#![feature(dropck_parametricity)]
#![feature(fmt_internals)]
/// ```
/// use std::collections::LinkedList;
///
- /// let mut a = LinkedList::new();
- /// let mut b = LinkedList::new();
- /// a.push_back(1);
- /// a.push_back(2);
- /// b.push_back(3);
- /// b.push_back(4);
+ /// let mut list1 = LinkedList::new();
+ /// list1.push_back('a');
///
- /// a.append(&mut b);
+ /// let mut list2 = LinkedList::new();
+ /// list2.push_back('b');
+ /// list2.push_back('c');
///
- /// for e in &a {
- /// println!("{}", e); // prints 1, then 2, then 3, then 4
- /// }
- /// println!("{}", b.len()); // prints 0
+ /// list1.append(&mut list2);
+ ///
+ /// let mut iter = list1.iter();
+ /// assert_eq!(iter.next(), Some(&'a'));
+ /// assert_eq!(iter.next(), Some(&'b'));
+ /// assert_eq!(iter.next(), Some(&'c'));
+ /// assert!(iter.next().is_none());
+ ///
+ /// assert!(list2.is_empty());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn append(&mut self, other: &mut Self) {
return s;
}
+ /// Escapes each char in `s` with `char::escape_debug`.
+ #[unstable(feature = "str_escape",
+ reason = "return type may change to be an iterator",
+ issue = "27791")]
+ pub fn escape_debug(&self) -> String {
+ self.chars().flat_map(|c| c.escape_debug()).collect()
+ }
+
/// Escapes each char in `s` with `char::escape_default`.
#[unstable(feature = "str_escape",
reason = "return type may change to be an iterator",
use core::ops::{Index, IndexMut};
use core::ops;
use core::ptr;
+use core::ptr::Shared;
use core::slice;
use super::SpecExtend;
Drain {
tail_start: end,
tail_len: len - end,
- iter: range_slice.iter_mut(),
- vec: self as *mut _,
+ iter: range_slice.iter(),
+ vec: Shared::new(self as *mut _),
}
}
}
/// Length of tail
tail_len: usize,
/// Current remaining range to remove
- iter: slice::IterMut<'a, T>,
- vec: *mut Vec<T>,
+ iter: slice::Iter<'a, T>,
+ vec: Shared<Vec<T>>,
}
#[stable(feature = "drain", since = "1.6.0")]
if self.tail_len > 0 {
unsafe {
- let source_vec = &mut *self.vec;
+ let source_vec = &mut **self.vec;
// memmove back untouched tail, update to new length
let start = source_vec.len();
let tail = self.tail_start;
// except according to those terms.
use std::collections::BinaryHeap;
+use std::collections::binary_heap::Drain;
#[test]
fn test_iterator() {
assert_eq!(a.into_sorted_vec(), [-20, -10, 1, 2, 3, 3, 5, 43]);
}
+
+#[allow(dead_code)]
+fn assert_covariance() {
+ fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { d }
+}
assert_eq!("\u{1d4ea}\r".escape_unicode(), "\\u{1d4ea}\\u{d}");
}
+#[test]
+fn test_escape_debug() {
+ assert_eq!("abc".escape_debug(), "abc");
+ assert_eq!("a c".escape_debug(), "a c");
+ assert_eq!("éèê".escape_debug(), "éèê");
+ assert_eq!("\r\n\t".escape_debug(), "\\r\\n\\t");
+ assert_eq!("'\"\\".escape_debug(), "\\'\\\"\\\\");
+ assert_eq!("\u{7f}\u{ff}".escape_debug(), "\\u{7f}\u{ff}");
+ assert_eq!("\u{100}\u{ffff}".escape_debug(), "\u{100}\\u{ffff}");
+ assert_eq!("\u{10000}\u{10ffff}".escape_debug(), "\u{10000}\\u{10ffff}");
+ assert_eq!("ab\u{200b}".escape_debug(), "ab\\u{200b}");
+ assert_eq!("\u{10d4ea}\r".escape_debug(), "\\u{10d4ea}\\r");
+}
+
#[test]
fn test_escape_default() {
assert_eq!("abc".escape_default(), "abc");
assert_eq!("a c".escape_default(), "a c");
+ assert_eq!("éèê".escape_default(), "\\u{e9}\\u{e8}\\u{ea}");
assert_eq!("\r\n\t".escape_default(), "\\r\\n\\t");
assert_eq!("'\"\\".escape_default(), "\\'\\\"\\\\");
+ assert_eq!("\u{7f}\u{ff}".escape_default(), "\\u{7f}\\u{ff}");
assert_eq!("\u{100}\u{ffff}".escape_default(), "\\u{100}\\u{ffff}");
assert_eq!("\u{10000}\u{10ffff}".escape_default(), "\\u{10000}\\u{10ffff}");
- assert_eq!("ab\u{fb00}".escape_default(), "ab\\u{fb00}");
- assert_eq!("\u{1d4ea}\r".escape_default(), "\\u{1d4ea}\\r");
+ assert_eq!("ab\u{200b}".escape_default(), "ab\\u{200b}");
+ assert_eq!("\u{10d4ea}\r".escape_default(), "\\u{10d4ea}\\r");
}
#[test]
assert_eq!(&s[0..], "abcประเทศไทย中华Việt Nam");
}
+#[test]
+fn test_add_assign() {
+ let mut s = String::new();
+ s += "";
+ assert_eq!(s.as_str(), "");
+ s += "abc";
+ assert_eq!(s.as_str(), "abc");
+ s += "ประเทศไทย中华Việt Nam";
+ assert_eq!(s.as_str(), "abcประเทศไทย中华Việt Nam");
+}
+
#[test]
fn test_push() {
let mut data = String::from("ประเทศไทย中");
use std::borrow::Cow;
use std::iter::{FromIterator, repeat};
use std::mem::size_of;
+use std::vec::Drain;
use test::Bencher;
}
}
+#[allow(dead_code)]
+fn assert_covariance() {
+ fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { d }
+}
+
#[bench]
fn bench_new(b: &mut Bencher) {
b.iter(|| {
use prelude::v1::*;
+use char_private::is_printable;
use mem::transmute;
// UTF-8 ranges and tags for encoding characters
fn escape_unicode(self) -> EscapeUnicode;
#[stable(feature = "core", since = "1.6.0")]
fn escape_default(self) -> EscapeDefault;
+ #[unstable(feature = "char_escape_debug", issue = "35068")]
+ fn escape_debug(self) -> EscapeDebug;
#[stable(feature = "core", since = "1.6.0")]
fn len_utf8(self) -> usize;
#[stable(feature = "core", since = "1.6.0")]
EscapeDefault { state: init_state }
}
+ #[inline]
+ fn escape_debug(self) -> EscapeDebug {
+ let init_state = match self {
+ '\t' => EscapeDefaultState::Backslash('t'),
+ '\r' => EscapeDefaultState::Backslash('r'),
+ '\n' => EscapeDefaultState::Backslash('n'),
+ '\\' | '\'' | '"' => EscapeDefaultState::Backslash(self),
+ c if is_printable(c) => EscapeDefaultState::Char(c),
+ c => EscapeDefaultState::Unicode(c.escape_unicode()),
+ };
+ EscapeDebug(EscapeDefault { state: init_state })
+ }
+
#[inline]
fn len_utf8(self) -> usize {
let code = self as u32;
}
}
+/// An iterator that yields the literal escape code of a `char`.
+///
+/// This `struct` is created by the [`escape_debug()`] method on [`char`]. See its
+/// documentation for more.
+///
+/// [`escape_debug()`]: ../../std/primitive.char.html#method.escape_debug
+/// [`char`]: ../../std/primitive.char.html
+#[unstable(feature = "char_escape_debug", issue = "35068")]
+#[derive(Clone, Debug)]
+pub struct EscapeDebug(EscapeDefault);
+
+#[unstable(feature = "char_escape_debug", issue = "35068")]
+impl Iterator for EscapeDebug {
+ type Item = char;
+ fn next(&mut self) -> Option<char> { self.0.next() }
+ fn size_hint(&self) -> (usize, Option<usize>) { self.0.size_hint() }
+}
+
+#[unstable(feature = "char_escape_debug", issue = "35068")]
+impl ExactSizeIterator for EscapeDebug { }
+
/// An iterator over `u8` entries represending the UTF-8 encoding of a `char`
/// value.
///
--- /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.
+
+// NOTE: The following code was generated by "src/etc/char_private.py",
+// do not edit directly!
+
+use slice::SliceExt;
+
+fn check(x: u16, singletons: &[u16], normal: &[u16]) -> bool {
+ for &s in singletons {
+ if x == s {
+ return false;
+ } else if x < s {
+ break;
+ }
+ }
+ for w in normal.chunks(2) {
+ let start = w[0];
+ let len = w[1];
+ let difference = (x as i32) - (start as i32);
+ if 0 <= difference {
+ if difference < len as i32 {
+ return false;
+ }
+ } else {
+ break;
+ }
+ }
+ true
+}
+
+pub fn is_printable(x: char) -> bool {
+ let x = x as u32;
+ let lower = x as u16;
+ if x < 0x10000 {
+ check(lower, SINGLETONS0, NORMAL0)
+ } else if x < 0x20000 {
+ check(lower, SINGLETONS1, NORMAL1)
+ } else {
+ if 0x20000 <= x && x < 0x2f800 {
+ return false;
+ }
+ if 0x2fa1e <= x && x < 0xe0100 {
+ return false;
+ }
+ if 0xe01f0 <= x && x < 0x110000 {
+ return false;
+ }
+ true
+ }
+}
+
+const SINGLETONS0: &'static [u16] = &[
+ 0xad,
+ 0x378,
+ 0x379,
+ 0x38b,
+ 0x38d,
+ 0x3a2,
+ 0x557,
+ 0x558,
+ 0x560,
+ 0x588,
+ 0x590,
+ 0x61c,
+ 0x61d,
+ 0x6dd,
+ 0x70e,
+ 0x70f,
+ 0x74b,
+ 0x74c,
+ 0x82e,
+ 0x82f,
+ 0x83f,
+ 0x85c,
+ 0x85d,
+ 0x8a1,
+ 0x8ff,
+ 0x978,
+ 0x980,
+ 0x984,
+ 0x98d,
+ 0x98e,
+ 0x991,
+ 0x992,
+ 0x9a9,
+ 0x9b1,
+ 0x9ba,
+ 0x9bb,
+ 0x9c5,
+ 0x9c6,
+ 0x9c9,
+ 0x9ca,
+ 0x9de,
+ 0x9e4,
+ 0x9e5,
+ 0xa04,
+ 0xa11,
+ 0xa12,
+ 0xa29,
+ 0xa31,
+ 0xa34,
+ 0xa37,
+ 0xa3a,
+ 0xa3b,
+ 0xa3d,
+ 0xa49,
+ 0xa4a,
+ 0xa5d,
+ 0xa84,
+ 0xa8e,
+ 0xa92,
+ 0xaa9,
+ 0xab1,
+ 0xab4,
+ 0xaba,
+ 0xabb,
+ 0xac6,
+ 0xaca,
+ 0xace,
+ 0xacf,
+ 0xae4,
+ 0xae5,
+ 0xb04,
+ 0xb0d,
+ 0xb0e,
+ 0xb11,
+ 0xb12,
+ 0xb29,
+ 0xb31,
+ 0xb34,
+ 0xb3a,
+ 0xb3b,
+ 0xb45,
+ 0xb46,
+ 0xb49,
+ 0xb4a,
+ 0xb5e,
+ 0xb64,
+ 0xb65,
+ 0xb84,
+ 0xb91,
+ 0xb9b,
+ 0xb9d,
+ 0xbc9,
+ 0xbce,
+ 0xbcf,
+ 0xc04,
+ 0xc0d,
+ 0xc11,
+ 0xc29,
+ 0xc34,
+ 0xc45,
+ 0xc49,
+ 0xc57,
+ 0xc64,
+ 0xc65,
+ 0xc80,
+ 0xc81,
+ 0xc84,
+ 0xc8d,
+ 0xc91,
+ 0xca9,
+ 0xcb4,
+ 0xcba,
+ 0xcbb,
+ 0xcc5,
+ 0xcc9,
+ 0xcdf,
+ 0xce4,
+ 0xce5,
+ 0xcf0,
+ 0xd04,
+ 0xd0d,
+ 0xd11,
+ 0xd3b,
+ 0xd3c,
+ 0xd45,
+ 0xd49,
+ 0xd64,
+ 0xd65,
+ 0xd80,
+ 0xd81,
+ 0xd84,
+ 0xdb2,
+ 0xdbc,
+ 0xdbe,
+ 0xdbf,
+ 0xdd5,
+ 0xdd7,
+ 0xe83,
+ 0xe85,
+ 0xe86,
+ 0xe89,
+ 0xe8b,
+ 0xe8c,
+ 0xe98,
+ 0xea0,
+ 0xea4,
+ 0xea6,
+ 0xea8,
+ 0xea9,
+ 0xeac,
+ 0xeba,
+ 0xebe,
+ 0xebf,
+ 0xec5,
+ 0xec7,
+ 0xece,
+ 0xecf,
+ 0xeda,
+ 0xedb,
+ 0xf48,
+ 0xf98,
+ 0xfbd,
+ 0xfcd,
+ 0x10c6,
+ 0x10ce,
+ 0x10cf,
+ 0x1249,
+ 0x124e,
+ 0x124f,
+ 0x1257,
+ 0x1259,
+ 0x125e,
+ 0x125f,
+ 0x1289,
+ 0x128e,
+ 0x128f,
+ 0x12b1,
+ 0x12b6,
+ 0x12b7,
+ 0x12bf,
+ 0x12c1,
+ 0x12c6,
+ 0x12c7,
+ 0x12d7,
+ 0x1311,
+ 0x1316,
+ 0x1317,
+ 0x135b,
+ 0x135c,
+ 0x1680,
+ 0x170d,
+ 0x176d,
+ 0x1771,
+ 0x17de,
+ 0x17df,
+ 0x180e,
+ 0x180f,
+ 0x196e,
+ 0x196f,
+ 0x1a1c,
+ 0x1a1d,
+ 0x1a5f,
+ 0x1a7d,
+ 0x1a7e,
+ 0x1f16,
+ 0x1f17,
+ 0x1f1e,
+ 0x1f1f,
+ 0x1f46,
+ 0x1f47,
+ 0x1f4e,
+ 0x1f4f,
+ 0x1f58,
+ 0x1f5a,
+ 0x1f5c,
+ 0x1f5e,
+ 0x1f7e,
+ 0x1f7f,
+ 0x1fb5,
+ 0x1fc5,
+ 0x1fd4,
+ 0x1fd5,
+ 0x1fdc,
+ 0x1ff0,
+ 0x1ff1,
+ 0x1ff5,
+ 0x2072,
+ 0x2073,
+ 0x208f,
+ 0x2700,
+ 0x2c2f,
+ 0x2c5f,
+ 0x2d26,
+ 0x2d2e,
+ 0x2d2f,
+ 0x2da7,
+ 0x2daf,
+ 0x2db7,
+ 0x2dbf,
+ 0x2dc7,
+ 0x2dcf,
+ 0x2dd7,
+ 0x2ddf,
+ 0x2e9a,
+ 0x3040,
+ 0x3097,
+ 0x3098,
+ 0x318f,
+ 0x321f,
+ 0x32ff,
+ 0xa78f,
+ 0xa9ce,
+ 0xaa4e,
+ 0xaa4f,
+ 0xaa5a,
+ 0xaa5b,
+ 0xab07,
+ 0xab08,
+ 0xab0f,
+ 0xab10,
+ 0xab27,
+ 0xabee,
+ 0xabef,
+ 0xfa6e,
+ 0xfa6f,
+ 0xfb37,
+ 0xfb3d,
+ 0xfb3f,
+ 0xfb42,
+ 0xfb45,
+ 0xfd90,
+ 0xfd91,
+ 0xfdfe,
+ 0xfdff,
+ 0xfe53,
+ 0xfe67,
+ 0xfe75,
+ 0xffc8,
+ 0xffc9,
+ 0xffd0,
+ 0xffd1,
+ 0xffd8,
+ 0xffd9,
+ 0xffe7,
+ 0xfffe,
+ 0xffff,
+];
+const SINGLETONS1: &'static [u16] = &[
+ 0xc,
+ 0x27,
+ 0x3b,
+ 0x3e,
+ 0x4e,
+ 0x4f,
+ 0x31f,
+ 0x39e,
+ 0x49e,
+ 0x49f,
+ 0x806,
+ 0x807,
+ 0x809,
+ 0x836,
+ 0x83d,
+ 0x83e,
+ 0x856,
+ 0xa04,
+ 0xa14,
+ 0xa18,
+ 0xb56,
+ 0xb57,
+ 0x10bd,
+ 0x1135,
+ 0xd127,
+ 0xd128,
+ 0xd455,
+ 0xd49d,
+ 0xd4a0,
+ 0xd4a1,
+ 0xd4a3,
+ 0xd4a4,
+ 0xd4a7,
+ 0xd4a8,
+ 0xd4ad,
+ 0xd4ba,
+ 0xd4bc,
+ 0xd4c4,
+ 0xd506,
+ 0xd50b,
+ 0xd50c,
+ 0xd515,
+ 0xd51d,
+ 0xd53a,
+ 0xd53f,
+ 0xd545,
+ 0xd551,
+ 0xd6a6,
+ 0xd6a7,
+ 0xd7cc,
+ 0xd7cd,
+ 0xee04,
+ 0xee20,
+ 0xee23,
+ 0xee25,
+ 0xee26,
+ 0xee28,
+ 0xee33,
+ 0xee38,
+ 0xee3a,
+ 0xee48,
+ 0xee4a,
+ 0xee4c,
+ 0xee50,
+ 0xee53,
+ 0xee55,
+ 0xee56,
+ 0xee58,
+ 0xee5a,
+ 0xee5c,
+ 0xee5e,
+ 0xee60,
+ 0xee63,
+ 0xee65,
+ 0xee66,
+ 0xee6b,
+ 0xee73,
+ 0xee78,
+ 0xee7d,
+ 0xee7f,
+ 0xee8a,
+ 0xeea4,
+ 0xeeaa,
+ 0xf0af,
+ 0xf0b0,
+ 0xf0bf,
+ 0xf0c0,
+ 0xf0d0,
+ 0xf12f,
+ 0xf336,
+ 0xf3c5,
+ 0xf43f,
+ 0xf441,
+ 0xf4f8,
+ 0xf53e,
+ 0xf53f,
+];
+const NORMAL0: &'static [u16] = &[
+ 0x0, 0x20,
+ 0x7f, 0x22,
+ 0x37f, 0x5,
+ 0x528, 0x9,
+ 0x58b, 0x4,
+ 0x5c8, 0x8,
+ 0x5eb, 0x5,
+ 0x5f5, 0x11,
+ 0x7b2, 0xe,
+ 0x7fb, 0x5,
+ 0x85f, 0x41,
+ 0x8ad, 0x37,
+ 0x9b3, 0x3,
+ 0x9cf, 0x8,
+ 0x9d8, 0x4,
+ 0x9fc, 0x5,
+ 0xa0b, 0x4,
+ 0xa43, 0x4,
+ 0xa4e, 0x3,
+ 0xa52, 0x7,
+ 0xa5f, 0x7,
+ 0xa76, 0xb,
+ 0xad1, 0xf,
+ 0xaf2, 0xf,
+ 0xb4e, 0x8,
+ 0xb58, 0x4,
+ 0xb78, 0xa,
+ 0xb8b, 0x3,
+ 0xb96, 0x3,
+ 0xba0, 0x3,
+ 0xba5, 0x3,
+ 0xbab, 0x3,
+ 0xbba, 0x4,
+ 0xbc3, 0x3,
+ 0xbd1, 0x6,
+ 0xbd8, 0xe,
+ 0xbfb, 0x6,
+ 0xc3a, 0x3,
+ 0xc4e, 0x7,
+ 0xc5a, 0x6,
+ 0xc70, 0x8,
+ 0xcce, 0x7,
+ 0xcd7, 0x7,
+ 0xcf3, 0xf,
+ 0xd4f, 0x8,
+ 0xd58, 0x8,
+ 0xd76, 0x3,
+ 0xd97, 0x3,
+ 0xdc7, 0x3,
+ 0xdcb, 0x4,
+ 0xde0, 0x12,
+ 0xdf5, 0xc,
+ 0xe3b, 0x4,
+ 0xe5c, 0x25,
+ 0xe8e, 0x6,
+ 0xee0, 0x20,
+ 0xf6d, 0x4,
+ 0xfdb, 0x25,
+ 0x10c8, 0x5,
+ 0x137d, 0x3,
+ 0x139a, 0x6,
+ 0x13f5, 0xb,
+ 0x169d, 0x3,
+ 0x16f1, 0xf,
+ 0x1715, 0xb,
+ 0x1737, 0x9,
+ 0x1754, 0xc,
+ 0x1774, 0xc,
+ 0x17ea, 0x6,
+ 0x17fa, 0x6,
+ 0x181a, 0x6,
+ 0x1878, 0x8,
+ 0x18ab, 0x5,
+ 0x18f6, 0xa,
+ 0x191d, 0x3,
+ 0x192c, 0x4,
+ 0x193c, 0x4,
+ 0x1941, 0x3,
+ 0x1975, 0xb,
+ 0x19ac, 0x4,
+ 0x19ca, 0x6,
+ 0x19db, 0x3,
+ 0x1a8a, 0x6,
+ 0x1a9a, 0x6,
+ 0x1aae, 0x52,
+ 0x1b4c, 0x4,
+ 0x1b7d, 0x3,
+ 0x1bf4, 0x8,
+ 0x1c38, 0x3,
+ 0x1c4a, 0x3,
+ 0x1c80, 0x40,
+ 0x1cc8, 0x8,
+ 0x1cf7, 0x9,
+ 0x1de7, 0x15,
+ 0x1fff, 0x11,
+ 0x2028, 0x8,
+ 0x205f, 0x11,
+ 0x209d, 0x3,
+ 0x20ba, 0x16,
+ 0x20f1, 0xf,
+ 0x218a, 0x6,
+ 0x23f4, 0xc,
+ 0x2427, 0x19,
+ 0x244b, 0x15,
+ 0x2b4d, 0x3,
+ 0x2b5a, 0xa6,
+ 0x2cf4, 0x5,
+ 0x2d28, 0x5,
+ 0x2d68, 0x7,
+ 0x2d71, 0xe,
+ 0x2d97, 0x9,
+ 0x2e3c, 0x44,
+ 0x2ef4, 0xc,
+ 0x2fd6, 0x1a,
+ 0x2ffc, 0x5,
+ 0x3100, 0x5,
+ 0x312e, 0x3,
+ 0x31bb, 0x5,
+ 0x31e4, 0xc,
+ 0x3400, 0x19c0,
+ 0x4e00, 0x5200,
+ 0xa48d, 0x3,
+ 0xa4c7, 0x9,
+ 0xa62c, 0x14,
+ 0xa698, 0x7,
+ 0xa6f8, 0x8,
+ 0xa794, 0xc,
+ 0xa7ab, 0x4d,
+ 0xa82c, 0x4,
+ 0xa83a, 0x6,
+ 0xa878, 0x8,
+ 0xa8c5, 0x9,
+ 0xa8da, 0x6,
+ 0xa8fc, 0x4,
+ 0xa954, 0xb,
+ 0xa97d, 0x3,
+ 0xa9da, 0x4,
+ 0xa9e0, 0x20,
+ 0xaa37, 0x9,
+ 0xaa7c, 0x4,
+ 0xaac3, 0x18,
+ 0xaaf7, 0xa,
+ 0xab17, 0x9,
+ 0xab2f, 0x91,
+ 0xabfa, 0x2bb6,
+ 0xd7c7, 0x4,
+ 0xd7fc, 0x2104,
+ 0xfada, 0x26,
+ 0xfb07, 0xc,
+ 0xfb18, 0x5,
+ 0xfbc2, 0x11,
+ 0xfd40, 0x10,
+ 0xfdc8, 0x28,
+ 0xfe1a, 0x6,
+ 0xfe27, 0x9,
+ 0xfe6c, 0x4,
+ 0xfefd, 0x4,
+ 0xffbf, 0x3,
+ 0xffdd, 0x3,
+ 0xffef, 0xd,
+];
+const NORMAL1: &'static [u16] = &[
+ 0x5e, 0x22,
+ 0xfb, 0x5,
+ 0x103, 0x4,
+ 0x134, 0x3,
+ 0x18b, 0x5,
+ 0x19c, 0x34,
+ 0x1fe, 0x82,
+ 0x29d, 0x3,
+ 0x2d1, 0x2f,
+ 0x324, 0xc,
+ 0x34b, 0x35,
+ 0x3c4, 0x4,
+ 0x3d6, 0x2a,
+ 0x4aa, 0x356,
+ 0x839, 0x3,
+ 0x860, 0xa0,
+ 0x91c, 0x3,
+ 0x93a, 0x5,
+ 0x940, 0x40,
+ 0x9b8, 0x6,
+ 0x9c0, 0x40,
+ 0xa07, 0x5,
+ 0xa34, 0x4,
+ 0xa3b, 0x4,
+ 0xa48, 0x8,
+ 0xa59, 0x7,
+ 0xa80, 0x80,
+ 0xb36, 0x3,
+ 0xb73, 0x5,
+ 0xb80, 0x80,
+ 0xc49, 0x217,
+ 0xe7f, 0x181,
+ 0x104e, 0x4,
+ 0x1070, 0x10,
+ 0x10c2, 0xe,
+ 0x10e9, 0x7,
+ 0x10fa, 0x6,
+ 0x1144, 0x3c,
+ 0x11c9, 0x7,
+ 0x11da, 0x4a6,
+ 0x16b8, 0x8,
+ 0x16ca, 0x936,
+ 0x236f, 0x91,
+ 0x2463, 0xd,
+ 0x2474, 0xb8c,
+ 0x342f, 0x33d1,
+ 0x6a39, 0x4c7,
+ 0x6f45, 0xb,
+ 0x6f7f, 0x10,
+ 0x6fa0, 0x4060,
+ 0xb002, 0x1ffe,
+ 0xd0f6, 0xa,
+ 0xd173, 0x8,
+ 0xd1de, 0x22,
+ 0xd246, 0xba,
+ 0xd357, 0x9,
+ 0xd372, 0x8e,
+ 0xd547, 0x3,
+ 0xd800, 0x1600,
+ 0xee3c, 0x6,
+ 0xee43, 0x4,
+ 0xee9c, 0x5,
+ 0xeebc, 0x34,
+ 0xeef2, 0x10e,
+ 0xf02c, 0x4,
+ 0xf094, 0xc,
+ 0xf0e0, 0x20,
+ 0xf10b, 0x5,
+ 0xf16c, 0x4,
+ 0xf19b, 0x4b,
+ 0xf203, 0xd,
+ 0xf23b, 0x5,
+ 0xf249, 0x7,
+ 0xf252, 0xae,
+ 0xf321, 0xf,
+ 0xf37d, 0x3,
+ 0xf394, 0xc,
+ 0xf3cb, 0x15,
+ 0xf3f1, 0xf,
+ 0xf4fd, 0x3,
+ 0xf544, 0xc,
+ 0xf568, 0x93,
+ 0xf641, 0x4,
+ 0xf650, 0x30,
+ 0xf6c6, 0x3a,
+ 0xf774, 0x88c,
+];
f.write_char('"')?;
let mut from = 0;
for (i, c) in self.char_indices() {
- let esc = c.escape_default();
+ let esc = c.escape_debug();
// If char needs escaping, flush backlog so far and write, else skip
if esc.len() != 1 {
f.write_str(&self[from..i])?;
impl Debug for char {
fn fmt(&self, f: &mut Formatter) -> Result {
f.write_char('\'')?;
- for c in self.escape_default() {
+ for c in self.escape_debug() {
f.write_char(c)?
}
f.write_char('\'')
#[macro_use]
mod uint_macros;
-#[path = "num/isize.rs"] pub mod isize;
-#[path = "num/i8.rs"] pub mod i8;
-#[path = "num/i16.rs"] pub mod i16;
-#[path = "num/i32.rs"] pub mod i32;
-#[path = "num/i64.rs"] pub mod i64;
+#[path = "num/isize.rs"] pub mod isize;
+#[path = "num/i8.rs"] pub mod i8;
+#[path = "num/i16.rs"] pub mod i16;
+#[path = "num/i32.rs"] pub mod i32;
+#[path = "num/i64.rs"] pub mod i64;
#[path = "num/usize.rs"] pub mod usize;
-#[path = "num/u8.rs"] pub mod u8;
-#[path = "num/u16.rs"] pub mod u16;
-#[path = "num/u32.rs"] pub mod u32;
-#[path = "num/u64.rs"] pub mod u64;
+#[path = "num/u8.rs"] pub mod u8;
+#[path = "num/u16.rs"] pub mod u16;
+#[path = "num/u32.rs"] pub mod u32;
+#[path = "num/u64.rs"] pub mod u64;
#[path = "num/f32.rs"] pub mod f32;
#[path = "num/f64.rs"] pub mod f64;
pub mod fmt;
// note: does not need to be public
+mod char_private;
mod iter_private;
mod tuple;
/// This will invoke the `panic!` macro if the provided expression cannot be
/// evaluated to `true` at runtime.
///
+/// Assertions are always checked in both debug and release builds, and cannot
+/// be disabled. See `debug_assert!` for assertions that are not enabled in
+/// release builds by default.
+///
+/// Unsafe code relies on `assert!` to enforce run-time invariants that, if
+/// violated could lead to unsafety.
+///
+/// Other use-cases of `assert!` include
+/// [testing](https://doc.rust-lang.org/book/testing.html) and enforcing
+/// run-time invariants in safe code (whose violation cannot result in unsafety).
+///
/// This macro has a second version, where a custom panic message can be provided.
///
/// # Examples
/// expensive to be present in a release build but may be helpful during
/// development.
///
+/// An unchecked assertion allows a program in an inconsistent state to keep
+/// running, which might have unexpected consequences but does not introduce
+/// unsafety as long as this only happens in safe code. The performance cost
+/// of assertions, is however, not measurable in general. Replacing `assert!`
+/// with `debug_assert!` is thus only encouraged after thorough profiling, and
+/// more importantly, only in safe code!
+///
/// # Examples
///
/// ```
if b {None} else {Some(a)}
}
+ /// Checked absolute value. Computes `self.abs()`, returning `None` if
+ /// `self == MIN`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// # #![feature(no_panic_abs)]
+ ///
+ /// use std::i32;
+ ///
+ /// assert_eq!((-5i32).checked_abs(), Some(5));
+ /// assert_eq!(i32::MIN.checked_abs(), None);
+ /// ```
+ #[unstable(feature = "no_panic_abs", issue = "35057")]
+ #[inline]
+ pub fn checked_abs(self) -> Option<Self> {
+ if self.is_negative() {
+ self.checked_neg()
+ } else {
+ Some(self)
+ }
+ }
+
/// Saturating integer addition. Computes `self + other`, saturating at
/// the numeric bounds instead of overflowing.
///
self.overflowing_shr(rhs).0
}
+ /// Wrapping (modular) absolute value. Computes `self.abs()`,
+ /// wrapping around at the boundary of the type.
+ ///
+ /// The only case where such wrapping can occur is when one takes
+ /// the absolute value of the negative minimal value for the type
+ /// this is a positive value that is too large to represent in the
+ /// type. In such a case, this function returns `MIN` itself.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// # #![feature(no_panic_abs)]
+ ///
+ /// assert_eq!(100i8.wrapping_abs(), 100);
+ /// assert_eq!((-100i8).wrapping_abs(), 100);
+ /// assert_eq!((-128i8).wrapping_abs(), -128);
+ /// assert_eq!((-128i8).wrapping_abs() as u8, 128);
+ /// ```
+ #[unstable(feature = "no_panic_abs", issue = "35057")]
+ #[inline(always)]
+ pub fn wrapping_abs(self) -> Self {
+ if self.is_negative() {
+ self.wrapping_neg()
+ } else {
+ self
+ }
+ }
+
/// Calculates `self` + `rhs`
///
/// Returns a tuple of the addition along with a boolean indicating
(self >> (rhs & ($BITS - 1)), (rhs > ($BITS - 1)))
}
+ /// Computes the absolute value of `self`.
+ ///
+ /// Returns a tuple of the absolute version of self along with a
+ /// boolean indicating whether an overflow happened. If self is the
+ /// minimum value (e.g. i32::MIN for values of type i32), then the
+ /// minimum value will be returned again and true will be returned for
+ /// an overflow happening.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// # #![feature(no_panic_abs)]
+ ///
+ /// assert_eq!(10i8.overflowing_abs(), (10,false));
+ /// assert_eq!((-10i8).overflowing_abs(), (10,false));
+ /// assert_eq!((-128i8).overflowing_abs(), (-128,true));
+ /// ```
+ #[unstable(feature = "no_panic_abs", issue = "35057")]
+ #[inline]
+ pub fn overflowing_abs(self) -> (Self, bool) {
+ if self.is_negative() {
+ self.overflowing_neg()
+ } else {
+ (self, false)
+ }
+ }
+
/// Raises self to the power of `exp`, using exponentiation by squaring.
///
/// # Examples
///
/// This has the same lifetime as the original slice, and so the
/// iterator can continue to be used while this exists.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut chars = "abc".chars();
+ ///
+ /// assert_eq!(chars.as_str(), "abc");
+ /// chars.next();
+ /// assert_eq!(chars.as_str(), "bc");
+ /// chars.next();
+ /// chars.next();
+ /// assert_eq!(chars.as_str(), "");
+ /// ```
#[stable(feature = "iter_to_slice", since = "1.4.0")]
#[inline]
pub fn as_str(&self) -> &'a str {
assert!(!'Q'.is_numeric());
}
+#[test]
+fn test_escape_debug() {
+ fn string(c: char) -> String {
+ c.escape_debug().collect()
+ }
+ let s = string('\n');
+ assert_eq!(s, "\\n");
+ let s = string('\r');
+ assert_eq!(s, "\\r");
+ let s = string('\'');
+ assert_eq!(s, "\\'");
+ let s = string('"');
+ assert_eq!(s, "\\\"");
+ let s = string(' ');
+ assert_eq!(s, " ");
+ let s = string('a');
+ assert_eq!(s, "a");
+ let s = string('~');
+ assert_eq!(s, "~");
+ let s = string('é');
+ assert_eq!(s, "é");
+ let s = string('\x00');
+ assert_eq!(s, "\\u{0}");
+ let s = string('\x1f');
+ assert_eq!(s, "\\u{1f}");
+ let s = string('\x7f');
+ assert_eq!(s, "\\u{7f}");
+ let s = string('\u{80}');
+ assert_eq!(s, "\\u{80}");
+ let s = string('\u{ff}');
+ assert_eq!(s, "\u{ff}");
+ let s = string('\u{11b}');
+ assert_eq!(s, "\u{11b}");
+ let s = string('\u{1d4b6}');
+ assert_eq!(s, "\u{1d4b6}");
+ let s = string('\u{200b}'); // zero width space
+ assert_eq!(s, "\\u{200b}");
+ let s = string('\u{e000}'); // private use 1
+ assert_eq!(s, "\\u{e000}");
+ let s = string('\u{100000}'); // private use 2
+ assert_eq!(s, "\\u{100000}");
+}
+
#[test]
fn test_escape_default() {
fn string(c: char) -> String {
assert_eq!(s, "a");
let s = string('~');
assert_eq!(s, "~");
+ let s = string('é');
+ assert_eq!(s, "\\u{e9}");
let s = string('\x00');
assert_eq!(s, "\\u{0}");
let s = string('\x1f');
assert_eq!(s, "\\u{1f}");
let s = string('\x7f');
assert_eq!(s, "\\u{7f}");
+ let s = string('\u{80}');
+ assert_eq!(s, "\\u{80}");
let s = string('\u{ff}');
assert_eq!(s, "\\u{ff}");
let s = string('\u{11b}');
assert_eq!(s, "\\u{11b}");
let s = string('\u{1d4b6}');
assert_eq!(s, "\\u{1d4b6}");
+ let s = string('\u{200b}'); // zero width space
+ assert_eq!(s, "\\u{200b}");
+ let s = string('\u{e000}'); // private use 1
+ assert_eq!(s, "\\u{e000}");
+ let s = string('\u{100000}'); // private use 2
+ assert_eq!(s, "\\u{100000}");
}
#[test]
#![feature(borrow_state)]
#![feature(box_syntax)]
#![feature(cell_extras)]
+#![feature(char_escape_debug)]
#![feature(const_fn)]
#![feature(core_private_bignum)]
#![feature(core_private_diy_float)]
#![feature(slice_patterns)]
#![feature(step_by)]
#![feature(test)]
+#![feature(try_from)]
#![feature(unboxed_closures)]
#![feature(unicode)]
#![feature(unique)]
-#![feature(try_from)]
extern crate core;
extern crate test;
}
}
}
- // Ip is not present in the table. This should not hapen... but it does: issie #35011.
+ // Ip is not present in the table. This should not happen... but it does: issue #35011.
// So rather than returning EHAction::Terminate, we do this.
EHAction::None
} else {
use alloc::boxed::Box;
use unwind as uw;
+use libc::{c_int, uintptr_t};
+use dwarf::eh::{self, EHContext, EHAction};
#[repr(C)]
struct Exception {
0x4d4f5a_00_52555354
}
-// All targets, except ARM which uses a slightly different ABI (however, iOS goes here as it uses
-// SjLj unwinding). Also, 64-bit Windows implementation lives in seh64_gnu.rs
-#[cfg(all(any(target_os = "ios", not(target_arch = "arm"))))]
-pub mod eabi {
- use unwind as uw;
- use libc::{c_int, uintptr_t};
- use dwarf::eh::{EHContext, EHAction, find_eh_action};
- // Register ids were lifted from LLVM's TargetLowering::getExceptionPointerRegister()
- // and TargetLowering::getExceptionSelectorRegister() for each architecture,
- // then mapped to DWARF register numbers via register definition tables
- // (typically <arch>RegisterInfo.td, search for "DwarfRegNum").
- // See also http://llvm.org/docs/WritingAnLLVMBackend.html#defining-a-register.
+// Register ids were lifted from LLVM's TargetLowering::getExceptionPointerRegister()
+// and TargetLowering::getExceptionSelectorRegister() for each architecture,
+// then mapped to DWARF register numbers via register definition tables
+// (typically <arch>RegisterInfo.td, search for "DwarfRegNum").
+// See also http://llvm.org/docs/WritingAnLLVMBackend.html#defining-a-register.
- #[cfg(target_arch = "x86")]
- const UNWIND_DATA_REG: (i32, i32) = (0, 2); // EAX, EDX
+#[cfg(target_arch = "x86")]
+const UNWIND_DATA_REG: (i32, i32) = (0, 2); // EAX, EDX
- #[cfg(target_arch = "x86_64")]
- const UNWIND_DATA_REG: (i32, i32) = (0, 1); // RAX, RDX
+#[cfg(target_arch = "x86_64")]
+const UNWIND_DATA_REG: (i32, i32) = (0, 1); // RAX, RDX
- #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
- const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1 / X0, X1
+#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
+const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1 / X0, X1
- #[cfg(any(target_arch = "mips", target_arch = "mipsel"))]
- const UNWIND_DATA_REG: (i32, i32) = (4, 5); // A0, A1
+#[cfg(any(target_arch = "mips", target_arch = "mipsel"))]
+const UNWIND_DATA_REG: (i32, i32) = (4, 5); // A0, A1
- #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
- const UNWIND_DATA_REG: (i32, i32) = (3, 4); // R3, R4 / X3, X4
+#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
+const UNWIND_DATA_REG: (i32, i32) = (3, 4); // R3, R4 / X3, X4
- // Based on GCC's C and C++ personality routines. For reference, see:
- // https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_personality.cc
- // https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c
- #[lang = "eh_personality"]
- #[no_mangle]
- #[allow(unused)]
- unsafe extern "C" fn rust_eh_personality(version: c_int,
- actions: uw::_Unwind_Action,
- exception_class: uw::_Unwind_Exception_Class,
- exception_object: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context)
- -> uw::_Unwind_Reason_Code {
- if version != 1 {
- return uw::_URC_FATAL_PHASE1_ERROR;
- }
- let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8;
- let mut ip_before_instr: c_int = 0;
- let ip = uw::_Unwind_GetIPInfo(context, &mut ip_before_instr);
- let eh_context = EHContext {
- // The return address points 1 byte past the call instruction,
- // which could be in the next IP range in LSDA range table.
- ip: if ip_before_instr != 0 { ip } else { ip - 1 },
- func_start: uw::_Unwind_GetRegionStart(context),
- get_text_start: &|| uw::_Unwind_GetTextRelBase(context),
- get_data_start: &|| uw::_Unwind_GetDataRelBase(context),
- };
- let eh_action = find_eh_action(lsda, &eh_context);
+// The following code is based on GCC's C and C++ personality routines. For reference, see:
+// https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_personality.cc
+// https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c
- if actions as i32 & uw::_UA_SEARCH_PHASE as i32 != 0 {
- match eh_action {
- EHAction::None | EHAction::Cleanup(_) => return uw::_URC_CONTINUE_UNWIND,
- EHAction::Catch(_) => return uw::_URC_HANDLER_FOUND,
- EHAction::Terminate => return uw::_URC_FATAL_PHASE1_ERROR,
- }
- } else {
- match eh_action {
- EHAction::None => return uw::_URC_CONTINUE_UNWIND,
- EHAction::Cleanup(lpad) | EHAction::Catch(lpad) => {
- uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0, exception_object as uintptr_t);
- uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, 0);
- uw::_Unwind_SetIP(context, lpad);
- return uw::_URC_INSTALL_CONTEXT;
- }
- EHAction::Terminate => return uw::_URC_FATAL_PHASE2_ERROR,
+// The personality routine for most of our targets, except ARM, which has a slightly different ABI
+// (however, iOS goes here as it uses SjLj unwinding). Also, the 64-bit Windows implementation
+// lives in seh64_gnu.rs
+#[cfg(all(any(target_os = "ios", not(target_arch = "arm"))))]
+#[lang = "eh_personality"]
+#[no_mangle]
+#[allow(unused)]
+unsafe extern "C" fn rust_eh_personality(version: c_int,
+ actions: uw::_Unwind_Action,
+ exception_class: uw::_Unwind_Exception_Class,
+ exception_object: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context)
+ -> uw::_Unwind_Reason_Code {
+ if version != 1 {
+ return uw::_URC_FATAL_PHASE1_ERROR;
+ }
+ let eh_action = find_eh_action(context);
+ if actions as i32 & uw::_UA_SEARCH_PHASE as i32 != 0 {
+ match eh_action {
+ EHAction::None | EHAction::Cleanup(_) => return uw::_URC_CONTINUE_UNWIND,
+ EHAction::Catch(_) => return uw::_URC_HANDLER_FOUND,
+ EHAction::Terminate => return uw::_URC_FATAL_PHASE1_ERROR,
+ }
+ } else {
+ match eh_action {
+ EHAction::None => return uw::_URC_CONTINUE_UNWIND,
+ EHAction::Cleanup(lpad) | EHAction::Catch(lpad) => {
+ uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0, exception_object as uintptr_t);
+ uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, 0);
+ uw::_Unwind_SetIP(context, lpad);
+ return uw::_URC_INSTALL_CONTEXT;
}
+ EHAction::Terminate => return uw::_URC_FATAL_PHASE2_ERROR,
}
}
-
- #[cfg(stage0)]
- #[lang = "eh_personality_catch"]
- #[no_mangle]
- pub unsafe extern "C" fn rust_eh_personality_catch(version: c_int,
- actions: uw::_Unwind_Action,
- exception_class: uw::_Unwind_Exception_Class,
- ue_header: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context)
- -> uw::_Unwind_Reason_Code {
- rust_eh_personality(version, actions, exception_class, ue_header, context)
- }
}
-// ARM EHABI uses a slightly different personality routine signature,
-// but otherwise works the same.
+// ARM EHABI personality routine.
+// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf
#[cfg(all(target_arch = "arm", not(target_os = "ios")))]
-pub mod eabi {
- use unwind as uw;
- use libc::c_int;
+#[lang = "eh_personality"]
+#[no_mangle]
+unsafe extern "C" fn rust_eh_personality(state: uw::_Unwind_State,
+ exception_object: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context)
+ -> uw::_Unwind_Reason_Code {
+ let state = state as c_int;
+ let action = state & uw::_US_ACTION_MASK as c_int;
+ let search_phase = if action == uw::_US_VIRTUAL_UNWIND_FRAME as c_int {
+ // Backtraces on ARM will call the personality routine with
+ // state == _US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND. In those cases
+ // we want to continue unwinding the stack, otherwise all our backtraces
+ // would end at __rust_try
+ if state & uw::_US_FORCE_UNWIND as c_int != 0 {
+ return continue_unwind(exception_object, context)
+ }
+ true
+ } else if action == uw::_US_UNWIND_FRAME_STARTING as c_int {
+ false
+ } else if action == uw::_US_UNWIND_FRAME_RESUME as c_int {
+ return continue_unwind(exception_object, context);
+ } else {
+ return uw::_URC_FAILURE;
+ };
- extern "C" {
- fn __gcc_personality_v0(state: uw::_Unwind_State,
- ue_header: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context)
- -> uw::_Unwind_Reason_Code;
- }
+ // The DWARF unwinder assumes that _Unwind_Context holds things like the function
+ // and LSDA pointers, however ARM EHABI places them into the exception object.
+ // To preserve signatures of functions like _Unwind_GetLanguageSpecificData(), which
+ // take only the context pointer, GCC personality routines stash a pointer to exception_object
+ // in the context, using location reserved for ARM's "scratch register" (r12).
+ uw::_Unwind_SetGR(context, uw::UNWIND_POINTER_REG, exception_object as uw::_Unwind_Ptr);
+ // ...A more principled approach would be to provide the full definition of ARM's
+ // _Unwind_Context in our libunwind bindings and fetch the required data from there directly,
+ // bypassing DWARF compatibility functions.
- #[lang = "eh_personality"]
- #[no_mangle]
- extern "C" fn rust_eh_personality(state: uw::_Unwind_State,
- ue_header: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context)
- -> uw::_Unwind_Reason_Code {
- unsafe { __gcc_personality_v0(state, ue_header, context) }
+ let eh_action = find_eh_action(context);
+ if search_phase {
+ match eh_action {
+ EHAction::None |
+ EHAction::Cleanup(_) => return continue_unwind(exception_object, context),
+ EHAction::Catch(_) => return uw::_URC_HANDLER_FOUND,
+ EHAction::Terminate => return uw::_URC_FAILURE,
+ }
+ } else {
+ match eh_action {
+ EHAction::None => return continue_unwind(exception_object, context),
+ EHAction::Cleanup(lpad) | EHAction::Catch(lpad) => {
+ uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0, exception_object as uintptr_t);
+ uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, 0);
+ uw::_Unwind_SetIP(context, lpad);
+ return uw::_URC_INSTALL_CONTEXT;
+ }
+ EHAction::Terminate => return uw::_URC_FAILURE,
+ }
}
- #[lang = "eh_personality_catch"]
- #[no_mangle]
- pub extern "C" fn rust_eh_personality_catch(state: uw::_Unwind_State,
- ue_header: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context)
- -> uw::_Unwind_Reason_Code {
- // Backtraces on ARM will call the personality routine with
- // state == _US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND. In those cases
- // we want to continue unwinding the stack, otherwise all our backtraces
- // would end at __rust_try.
- if (state as c_int & uw::_US_ACTION_MASK as c_int) ==
- uw::_US_VIRTUAL_UNWIND_FRAME as c_int &&
- (state as c_int & uw::_US_FORCE_UNWIND as c_int) == 0 {
- // search phase
- uw::_URC_HANDLER_FOUND // catch!
+ // On ARM EHABI the personality routine is responsible for actually
+ // unwinding a single stack frame before returning (ARM EHABI Sec. 6.1).
+ unsafe fn continue_unwind(exception_object: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context)
+ -> uw::_Unwind_Reason_Code {
+ if __gnu_unwind_frame(exception_object, context) == uw::_URC_NO_REASON {
+ uw::_URC_CONTINUE_UNWIND
} else {
- // cleanup phase
- unsafe { __gcc_personality_v0(state, ue_header, context) }
+ uw::_URC_FAILURE
}
}
+ // defined in libgcc
+ extern "C" {
+ fn __gnu_unwind_frame(exception_object: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context)
+ -> uw::_Unwind_Reason_Code;
+ }
+}
+
+unsafe fn find_eh_action(context: *mut uw::_Unwind_Context) -> EHAction {
+ let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8;
+ let mut ip_before_instr: c_int = 0;
+ let ip = uw::_Unwind_GetIPInfo(context, &mut ip_before_instr);
+ let eh_context = EHContext {
+ // The return address points 1 byte past the call instruction,
+ // which could be in the next IP range in LSDA range table.
+ ip: if ip_before_instr != 0 { ip } else { ip - 1 },
+ func_start: uw::_Unwind_GetRegionStart(context),
+ get_text_start: &|| uw::_Unwind_GetTextRelBase(context),
+ get_data_start: &|| uw::_Unwind_GetDataRelBase(context),
+ };
+ eh::find_eh_action(lsda, &eh_context)
+}
+
+// *** Delete after a new snapshot ***
+#[cfg(all(stage0, any(target_os = "ios", not(target_arch = "arm"))))]
+#[lang = "eh_personality_catch"]
+#[no_mangle]
+pub unsafe extern "C" fn rust_eh_personality_catch(version: c_int,
+ actions: uw::_Unwind_Action,
+ exception_class: uw::_Unwind_Exception_Class,
+ ue_header: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context)
+ -> uw::_Unwind_Reason_Code {
+ rust_eh_personality(version, actions, exception_class, ue_header, context)
+}
+
+// *** Delete after a new snapshot ***
+#[cfg(all(stage0, target_arch = "arm", not(target_os = "ios")))]
+#[lang = "eh_personality_catch"]
+#[no_mangle]
+pub unsafe extern "C" fn rust_eh_personality_catch(state: uw::_Unwind_State,
+ ue_header: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context)
+ -> uw::_Unwind_Reason_Code {
+ rust_eh_personality(state, ue_header, context)
}
// See docs in the `unwind` module.
// This is considered acceptable, because the behavior of throwing exceptions
// through a C ABI boundary is undefined.
+// *** Delete after a new snapshot ***
#[cfg(stage0)]
#[lang = "eh_personality_catch"]
#[cfg(not(test))]
// except according to those terms.
use std::fmt::Debug;
+use std::sync::Arc;
macro_rules! try_opt {
($e:expr) => (
// in an extern crate.
MetaData(D),
+ // Represents some artifact that we save to disk. Note that these
+ // do not have a def-id as part of their identifier.
+ WorkProduct(Arc<WorkProductId>),
+
// Represents different phases in the compiler.
CrateReader,
CollectLanguageItems,
TransCrate => Some(TransCrate),
TransWriteMetadata => Some(TransWriteMetadata),
LinkBinary => Some(LinkBinary),
+
+ // work product names do not need to be mapped, because
+ // they are always absolute.
+ WorkProduct(ref id) => Some(WorkProduct(id.clone())),
+
Hir(ref d) => op(d).map(Hir),
MetaData(ref d) => op(d).map(MetaData),
CollectItem(ref d) => op(d).map(CollectItem),
}
}
}
+
+/// A "work product" corresponds to a `.o` (or other) file that we
+/// save in between runs. These ids do not have a DefId but rather
+/// some independent path or string that persists between runs without
+/// the need to be mapped or unmapped. (This ensures we can serialize
+/// them even in the absence of a tcx.)
+#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
+pub struct WorkProductId(pub String);
+
// except according to those terms.
use hir::def_id::DefId;
+use rustc_data_structures::fnv::FnvHashMap;
+use session::config::OutputType;
+use std::cell::{Ref, RefCell};
use std::rc::Rc;
+use std::sync::Arc;
-use super::dep_node::DepNode;
+use super::dep_node::{DepNode, WorkProductId};
use super::query::DepGraphQuery;
use super::raii;
use super::thread::{DepGraphThreadData, DepMessage};
#[derive(Clone)]
pub struct DepGraph {
- data: Rc<DepGraphThreadData>
+ data: Rc<DepGraphData>
+}
+
+struct DepGraphData {
+ /// We send messages to the thread to let it build up the dep-graph
+ /// from the current run.
+ thread: DepGraphThreadData,
+
+ /// When we load, there may be `.o` files, cached mir, or other such
+ /// things available to us. If we find that they are not dirty, we
+ /// load the path to the file storing those work-products here into
+ /// this map. We can later look for and extract that data.
+ previous_work_products: RefCell<FnvHashMap<Arc<WorkProductId>, WorkProduct>>,
+
+ /// Work-products that we generate in this run.
+ work_products: RefCell<FnvHashMap<Arc<WorkProductId>, WorkProduct>>,
}
impl DepGraph {
pub fn new(enabled: bool) -> DepGraph {
DepGraph {
- data: Rc::new(DepGraphThreadData::new(enabled))
+ data: Rc::new(DepGraphData {
+ thread: DepGraphThreadData::new(enabled),
+ previous_work_products: RefCell::new(FnvHashMap()),
+ work_products: RefCell::new(FnvHashMap())
+ })
}
}
/// then the other methods on this `DepGraph` will have no net effect.
#[inline]
pub fn enabled(&self) -> bool {
- self.data.enabled()
+ self.data.thread.enabled()
}
pub fn query(&self) -> DepGraphQuery<DefId> {
- self.data.query()
+ self.data.thread.query()
}
pub fn in_ignore<'graph>(&'graph self) -> raii::IgnoreTask<'graph> {
- raii::IgnoreTask::new(&self.data)
+ raii::IgnoreTask::new(&self.data.thread)
}
pub fn in_task<'graph>(&'graph self, key: DepNode<DefId>) -> raii::DepTask<'graph> {
- raii::DepTask::new(&self.data, key)
+ raii::DepTask::new(&self.data.thread, key)
}
pub fn with_ignore<OP,R>(&self, op: OP) -> R
}
pub fn read(&self, v: DepNode<DefId>) {
- self.data.enqueue(DepMessage::Read(v));
+ self.data.thread.enqueue(DepMessage::Read(v));
}
pub fn write(&self, v: DepNode<DefId>) {
- self.data.enqueue(DepMessage::Write(v));
+ self.data.thread.enqueue(DepMessage::Write(v));
+ }
+
+ /// Indicates that a previous work product exists for `v`. This is
+ /// invoked during initial start-up based on what nodes are clean
+ /// (and what files exist in the incr. directory).
+ pub fn insert_previous_work_product(&self, v: &Arc<WorkProductId>, data: WorkProduct) {
+ debug!("insert_previous_work_product({:?}, {:?})", v, data);
+ self.data.previous_work_products.borrow_mut()
+ .insert(v.clone(), data);
+ }
+
+ /// Indicates that we created the given work-product in this run
+ /// for `v`. This record will be preserved and loaded in the next
+ /// run.
+ pub fn insert_work_product(&self, v: &Arc<WorkProductId>, data: WorkProduct) {
+ debug!("insert_work_product({:?}, {:?})", v, data);
+ self.data.work_products.borrow_mut()
+ .insert(v.clone(), data);
}
+
+ /// Check whether a previous work product exists for `v` and, if
+ /// so, return the path that leads to it. Used to skip doing work.
+ pub fn previous_work_product(&self, v: &Arc<WorkProductId>) -> Option<WorkProduct> {
+ self.data.previous_work_products.borrow()
+ .get(v)
+ .cloned()
+ }
+
+ /// Access the map of work-products created during this run. Only
+ /// used during saving of the dep-graph.
+ pub fn work_products(&self) -> Ref<FnvHashMap<Arc<WorkProductId>, WorkProduct>> {
+ self.data.work_products.borrow()
+ }
+}
+
+/// A "work product" is an intermediate result that we save into the
+/// incremental directory for later re-use. The primary example are
+/// the object files that we save for each partition at code
+/// generation time.
+///
+/// Each work product is associated with a dep-node, representing the
+/// process that produced the work-product. If that dep-node is found
+/// to be dirty when we load up, then we will delete the work-product
+/// at load time. If the work-product is found to be clean, then we
+/// will keep a record in the `previous_work_products` list.
+///
+/// In addition, work products have an associated hash. This hash is
+/// an extra hash that can be used to decide if the work-product from
+/// a previous compilation can be re-used (in addition to the dirty
+/// edges check).
+///
+/// As the primary example, consider the object files we generate for
+/// each partition. In the first run, we create partitions based on
+/// the symbols that need to be compiled. For each partition P, we
+/// hash the symbols in P and create a `WorkProduct` record associated
+/// with `DepNode::TransPartition(P)`; the hash is the set of symbols
+/// in P.
+///
+/// The next time we compile, if the `DepNode::TransPartition(P)` is
+/// judged to be clean (which means none of the things we read to
+/// generate the partition were found to be dirty), it will be loaded
+/// into previous work products. We will then regenerate the set of
+/// symbols in the partition P and hash them (note that new symbols
+/// may be added -- for example, new monomorphizations -- even if
+/// nothing in P changed!). We will compare that hash against the
+/// previous hash. If it matches up, we can reuse the object file.
+#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
+pub struct WorkProduct {
+ /// Extra hash used to decide if work-product is still suitable;
+ /// note that this is *not* a hash of the work-product itself.
+ /// See documentation on `WorkProduct` type for an example.
+ pub input_hash: u64,
+
+ /// Saved files associated with this CGU
+ pub saved_files: Vec<(OutputType, String)>,
}
pub use self::dep_tracking_map::{DepTrackingMap, DepTrackingMapConfig};
pub use self::dep_node::DepNode;
+pub use self::dep_node::WorkProductId;
pub use self::graph::DepGraph;
+pub use self::graph::WorkProduct;
pub use self::query::DepGraphQuery;
pub use self::visit::visit_all_items_in_krate;
pub use self::raii::DepTask;
///////////////////////////////////////////////////////////////////////////
+ fn visit_id(&mut self, _node_id: NodeId) {
+ // Nothing to do.
+ }
fn visit_name(&mut self, _span: Span, _name: Name) {
// Nothing to do.
}
- fn visit_mod(&mut self, m: &'v Mod, _s: Span, _n: NodeId) {
- walk_mod(self, m)
+ fn visit_mod(&mut self, m: &'v Mod, _s: Span, n: NodeId) {
+ walk_mod(self, m, n)
}
fn visit_foreign_item(&mut self, i: &'v ForeignItem) {
walk_foreign_item(self, i)
fn visit_where_predicate(&mut self, predicate: &'v WherePredicate) {
walk_where_predicate(self, predicate)
}
- fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: &'v Block, s: Span, _: NodeId) {
- walk_fn(self, fk, fd, b, s)
+ fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: &'v Block, s: Span, id: NodeId) {
+ walk_fn(self, fk, fd, b, s, id)
}
fn visit_trait_item(&mut self, ti: &'v TraitItem) {
walk_trait_item(self, ti)
s: &'v VariantData,
_: Name,
_: &'v Generics,
- _: NodeId,
+ _parent_id: NodeId,
_: Span) {
walk_struct_def(self, s)
}
}
pub fn walk_macro_def<'v, V: Visitor<'v>>(visitor: &mut V, macro_def: &'v MacroDef) {
+ visitor.visit_id(macro_def.id);
visitor.visit_name(macro_def.span, macro_def.name);
walk_opt_name(visitor, macro_def.span, macro_def.imported_from);
walk_list!(visitor, visit_attribute, ¯o_def.attrs);
}
-pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod) {
+pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod, mod_node_id: NodeId) {
+ visitor.visit_id(mod_node_id);
for &item_id in &module.item_ids {
visitor.visit_nested_item(item_id);
}
}
pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) {
+ visitor.visit_id(local.id);
visitor.visit_pat(&local.pat);
walk_list!(visitor, visit_ty, &local.ty);
walk_list!(visitor, visit_expr, &local.init);
}
pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) {
+ visitor.visit_id(lifetime.id);
visitor.visit_name(lifetime.span, lifetime.name);
}
pub fn walk_trait_ref<'v, V>(visitor: &mut V, trait_ref: &'v TraitRef)
where V: Visitor<'v>
{
+ visitor.visit_id(trait_ref.ref_id);
visitor.visit_path(&trait_ref.path, trait_ref.ref_id)
}
visitor.visit_name(item.span, item.name);
match item.node {
ItemExternCrate(opt_name) => {
+ visitor.visit_id(item.id);
walk_opt_name(visitor, item.span, opt_name)
}
ItemUse(ref vp) => {
+ visitor.visit_id(item.id);
match vp.node {
ViewPathSimple(name, ref path) => {
visitor.visit_name(vp.span, name);
}
ItemStatic(ref typ, _, ref expr) |
ItemConst(ref typ, ref expr) => {
+ visitor.visit_id(item.id);
visitor.visit_ty(typ);
visitor.visit_expr(expr);
}
item.id)
}
ItemMod(ref module) => {
+ // visit_mod() takes care of visiting the Item's NodeId
visitor.visit_mod(module, item.span, item.id)
}
ItemForeignMod(ref foreign_module) => {
+ visitor.visit_id(item.id);
walk_list!(visitor, visit_foreign_item, &foreign_module.items);
}
ItemTy(ref typ, ref type_parameters) => {
+ visitor.visit_id(item.id);
visitor.visit_ty(typ);
visitor.visit_generics(type_parameters)
}
ItemEnum(ref enum_definition, ref type_parameters) => {
visitor.visit_generics(type_parameters);
+ // 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) => {
+ visitor.visit_id(item.id);
visitor.visit_trait_ref(trait_ref)
}
ItemImpl(_, _, ref type_parameters, ref opt_trait_reference, ref typ, ref impl_items) => {
+ visitor.visit_id(item.id);
visitor.visit_generics(type_parameters);
walk_list!(visitor, visit_trait_ref, opt_trait_reference);
visitor.visit_ty(typ);
}
ItemStruct(ref struct_definition, ref generics) => {
visitor.visit_generics(generics);
+ visitor.visit_id(item.id);
visitor.visit_variant_data(struct_definition, item.name, generics, item.id, item.span);
}
ItemTrait(_, ref generics, ref bounds, ref methods) => {
+ visitor.visit_id(item.id);
visitor.visit_generics(generics);
walk_list!(visitor, visit_ty_param_bound, bounds);
walk_list!(visitor, visit_trait_item, methods);
enum_definition: &'v EnumDef,
generics: &'v Generics,
item_id: NodeId) {
+ visitor.visit_id(item_id);
walk_list!(visitor,
visit_variant,
&enum_definition.variants,
pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V,
variant: &'v Variant,
generics: &'v Generics,
- item_id: NodeId) {
+ parent_item_id: NodeId) {
visitor.visit_name(variant.span, variant.node.name);
visitor.visit_variant_data(&variant.node.data,
variant.node.name,
generics,
- item_id,
+ parent_item_id,
variant.span);
walk_list!(visitor, visit_expr, &variant.node.disr_expr);
walk_list!(visitor, visit_attribute, &variant.node.attrs);
}
pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
+ visitor.visit_id(typ.id);
+
match typ.node {
TyVec(ref ty) => {
visitor.visit_ty(ty)
pub fn walk_path_list_item<'v, V: Visitor<'v>>(visitor: &mut V,
_prefix: &'v Path,
item: &'v PathListItem) {
+ visitor.visit_id(item.node.id());
walk_opt_name(visitor, item.span, item.node.name());
walk_opt_name(visitor, item.span, item.node.rename());
}
pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(visitor: &mut V,
type_binding: &'v TypeBinding) {
+ visitor.visit_id(type_binding.id);
visitor.visit_name(type_binding.span, type_binding.name);
visitor.visit_ty(&type_binding.ty);
}
pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
+ visitor.visit_id(pattern.id);
match pattern.node {
PatKind::TupleStruct(ref path, ref children, _) => {
visitor.visit_path(path, pattern.id);
}
pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v ForeignItem) {
+ visitor.visit_id(foreign_item.id);
visitor.visit_vis(&foreign_item.vis);
visitor.visit_name(foreign_item.span, foreign_item.name);
pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics) {
for param in &generics.ty_params {
+ visitor.visit_id(param.id);
visitor.visit_name(param.span, param.name);
walk_list!(visitor, visit_ty_param_bound, ¶m.bounds);
walk_list!(visitor, visit_ty, ¶m.default);
}
walk_list!(visitor, visit_lifetime_def, &generics.lifetimes);
+ visitor.visit_id(generics.where_clause.id);
walk_list!(visitor, visit_where_predicate, &generics.where_clause.predicates);
}
ref path,
ref ty,
..}) => {
+ visitor.visit_id(id);
visitor.visit_path(path, id);
visitor.visit_ty(ty);
}
pub fn walk_fn_decl<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl) {
for argument in &function_declaration.inputs {
+ visitor.visit_id(argument.id);
visitor.visit_pat(&argument.pat);
visitor.visit_ty(&argument.ty)
}
pub fn walk_fn_decl_nopat<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl) {
for argument in &function_declaration.inputs {
+ visitor.visit_id(argument.id);
visitor.visit_ty(&argument.ty)
}
walk_fn_ret_ty(visitor, &function_declaration.output)
function_kind: FnKind<'v>,
function_declaration: &'v FnDecl,
function_body: &'v Block,
- _span: Span) {
+ _span: Span,
+ id: NodeId) {
+ visitor.visit_id(id);
walk_fn_decl(visitor, function_declaration);
walk_fn_kind(visitor, function_kind);
visitor.visit_block(function_body)
walk_list!(visitor, visit_attribute, &trait_item.attrs);
match trait_item.node {
ConstTraitItem(ref ty, ref default) => {
+ visitor.visit_id(trait_item.id);
visitor.visit_ty(ty);
walk_list!(visitor, visit_expr, default);
}
MethodTraitItem(ref sig, None) => {
+ visitor.visit_id(trait_item.id);
visitor.visit_generics(&sig.generics);
walk_fn_decl(visitor, &sig.decl);
}
trait_item.id);
}
TypeTraitItem(ref bounds, ref default) => {
+ visitor.visit_id(trait_item.id);
walk_list!(visitor, visit_ty_param_bound, bounds);
walk_list!(visitor, visit_ty, default);
}
walk_list!(visitor, visit_attribute, &impl_item.attrs);
match impl_item.node {
ImplItemKind::Const(ref ty, ref expr) => {
+ visitor.visit_id(impl_item.id);
visitor.visit_ty(ty);
visitor.visit_expr(expr);
}
impl_item.id);
}
ImplItemKind::Type(ref ty) => {
+ visitor.visit_id(impl_item.id);
visitor.visit_ty(ty);
}
}
}
pub fn walk_struct_def<'v, V: Visitor<'v>>(visitor: &mut V, struct_definition: &'v VariantData) {
+ visitor.visit_id(struct_definition.id());
walk_list!(visitor, visit_struct_field, struct_definition.fields());
}
pub fn walk_struct_field<'v, V: Visitor<'v>>(visitor: &mut V, struct_field: &'v StructField) {
+ visitor.visit_id(struct_field.id);
visitor.visit_vis(&struct_field.vis);
visitor.visit_name(struct_field.span, struct_field.name);
visitor.visit_ty(&struct_field.ty);
}
pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block) {
+ visitor.visit_id(block.id);
walk_list!(visitor, visit_stmt, &block.stmts);
walk_list!(visitor, visit_expr, &block.expr);
}
pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt) {
match statement.node {
- StmtDecl(ref declaration, _) => visitor.visit_decl(declaration),
- StmtExpr(ref expression, _) | StmtSemi(ref expression, _) => {
+ StmtDecl(ref declaration, id) => {
+ visitor.visit_id(id);
+ visitor.visit_decl(declaration)
+ }
+ StmtExpr(ref expression, id) |
+ StmtSemi(ref expression, id) => {
+ visitor.visit_id(id);
visitor.visit_expr(expression)
}
}
}
pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
+ visitor.visit_id(expression.id);
match expression.node {
ExprBox(ref subexpression) => {
visitor.visit_expr(subexpression)
pub fn walk_vis<'v, V: Visitor<'v>>(visitor: &mut V, vis: &'v Visibility) {
if let Visibility::Restricted { ref path, id } = *vis {
+ visitor.visit_id(id);
visitor.visit_path(path, id)
}
}
self.min >= self.max
}
+ pub fn contains(&self, id: NodeId) -> bool {
+ id >= self.min && id < self.max
+ }
+
pub fn add(&mut self, id: NodeId) {
self.min = cmp::min(self.min, id);
self.max = cmp::max(self.max, id + 1);
}
}
-pub trait IdVisitingOperation {
- fn visit_id(&mut self, node_id: NodeId);
-}
pub struct IdRangeComputingVisitor {
pub result: IdRange,
}
}
-impl IdVisitingOperation for IdRangeComputingVisitor {
+impl<'v> Visitor<'v> for IdRangeComputingVisitor {
fn visit_id(&mut self, id: NodeId) {
self.result.add(id);
}
}
-pub struct IdVisitor<'a, O: 'a> {
- operation: &'a mut O,
-
- // In general, the id visitor visits the contents of an item, but
- // not including nested trait/impl items, nor other nested items.
- // The base visitor itself always skips nested items, but not
- // trait/impl items. This means in particular that if you start by
- // visiting a trait or an impl, you should not visit the
- // trait/impl items respectively. This is handled by setting
- // `skip_members` to true when `visit_item` is on the stack. This
- // way, if the user begins by calling `visit_trait_item`, we will
- // visit the trait item, but if they begin with `visit_item`, we
- // won't visit the (nested) trait items.
- skip_members: bool,
-}
-
-impl<'a, O: IdVisitingOperation> IdVisitor<'a, O> {
- pub fn new(operation: &'a mut O) -> IdVisitor<'a, O> {
- IdVisitor { operation: operation, skip_members: false }
- }
-
- fn visit_generics_helper(&mut self, generics: &Generics) {
- for type_parameter in generics.ty_params.iter() {
- self.operation.visit_id(type_parameter.id)
- }
- for lifetime in &generics.lifetimes {
- self.operation.visit_id(lifetime.lifetime.id)
- }
- }
-}
-
-impl<'a, 'v, O: IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> {
- fn visit_mod(&mut self, module: &Mod, _: Span, node_id: NodeId) {
- self.operation.visit_id(node_id);
- walk_mod(self, module)
- }
-
- fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) {
- self.operation.visit_id(foreign_item.id);
- walk_foreign_item(self, foreign_item)
- }
-
- fn visit_item(&mut self, item: &Item) {
- assert!(!self.skip_members);
- self.skip_members = true;
-
- self.operation.visit_id(item.id);
- match item.node {
- ItemUse(ref view_path) => {
- match view_path.node {
- ViewPathSimple(_, _) |
- ViewPathGlob(_) => {}
- ViewPathList(_, ref paths) => {
- for path in paths {
- self.operation.visit_id(path.node.id())
- }
- }
- }
- }
- _ => {}
- }
- walk_item(self, item);
-
- self.skip_members = false;
- }
-
- fn visit_local(&mut self, local: &Local) {
- self.operation.visit_id(local.id);
- walk_local(self, local)
- }
-
- fn visit_block(&mut self, block: &Block) {
- self.operation.visit_id(block.id);
- walk_block(self, block)
- }
-
- fn visit_stmt(&mut self, statement: &Stmt) {
- self.operation.visit_id(statement.node.id());
- walk_stmt(self, statement)
- }
-
- fn visit_pat(&mut self, pattern: &Pat) {
- self.operation.visit_id(pattern.id);
- walk_pat(self, pattern)
- }
-
- fn visit_expr(&mut self, expression: &Expr) {
- self.operation.visit_id(expression.id);
- walk_expr(self, expression)
- }
-
- fn visit_ty(&mut self, typ: &Ty) {
- self.operation.visit_id(typ.id);
- walk_ty(self, typ)
- }
-
- fn visit_generics(&mut self, generics: &Generics) {
- self.visit_generics_helper(generics);
- walk_generics(self, generics)
- }
-
- fn visit_fn(&mut self,
- function_kind: FnKind<'v>,
- function_declaration: &'v FnDecl,
- block: &'v Block,
- span: Span,
- node_id: NodeId) {
- self.operation.visit_id(node_id);
-
- match function_kind {
- FnKind::ItemFn(_, generics, _, _, _, _, _) => {
- self.visit_generics_helper(generics)
- }
- FnKind::Method(_, sig, _, _) => {
- self.visit_generics_helper(&sig.generics)
- }
- FnKind::Closure(_) => {}
- }
-
- for argument in &function_declaration.inputs {
- self.operation.visit_id(argument.id)
- }
-
- walk_fn(self, function_kind, function_declaration, block, span);
- }
-
- fn visit_struct_field(&mut self, struct_field: &StructField) {
- self.operation.visit_id(struct_field.id);
- walk_struct_field(self, struct_field)
- }
-
- fn visit_variant_data(&mut self,
- struct_def: &VariantData,
- _: Name,
- _: &Generics,
- _: NodeId,
- _: Span) {
- self.operation.visit_id(struct_def.id());
- walk_struct_def(self, struct_def);
- }
-
- fn visit_trait_item(&mut self, ti: &TraitItem) {
- if !self.skip_members {
- self.operation.visit_id(ti.id);
- walk_trait_item(self, ti);
- }
- }
-
- fn visit_impl_item(&mut self, ii: &ImplItem) {
- if !self.skip_members {
- self.operation.visit_id(ii.id);
- walk_impl_item(self, ii);
- }
- }
-
- fn visit_lifetime(&mut self, lifetime: &Lifetime) {
- self.operation.visit_id(lifetime.id);
- }
-
- fn visit_lifetime_def(&mut self, def: &LifetimeDef) {
- self.visit_lifetime(&def.lifetime);
- }
-
- fn visit_trait_ref(&mut self, trait_ref: &TraitRef) {
- self.operation.visit_id(trait_ref.ref_id);
- walk_trait_ref(self, trait_ref);
- }
-}
-
/// Computes the id range for a single fn body, ignoring nested items.
pub fn compute_id_range_for_fn_body(fk: FnKind,
decl: &FnDecl,
sp: Span,
id: NodeId)
-> IdRange {
- let mut visitor = IdRangeComputingVisitor { result: IdRange::max() };
- let mut id_visitor = IdVisitor::new(&mut visitor);
- id_visitor.visit_fn(fk, decl, body, sp, id);
- id_visitor.operation.result
+ let mut visitor = IdRangeComputingVisitor::new();
+ visitor.visit_fn(fk, decl, body, sp, id);
+ visitor.result()
}
fn visit_fn(&mut self, fk: intravisit::FnKind<'ast>, fd: &'ast FnDecl,
b: &'ast Block, s: Span, id: NodeId) {
assert_eq!(self.parent_node, id);
- intravisit::walk_fn(self, fk, fd, b, s);
+ intravisit::walk_fn(self, fk, fd, b, s, id);
}
fn visit_block(&mut self, block: &'ast Block) {
/// TraitRef's appear in impls.
///
/// resolve maps each TraitRef's ref_id to its defining trait; that's all
-/// that the ref_id is for. The impl_id maps to the "self type" of this impl.
-/// If this impl is an ItemImpl, the impl_id is redundant (it could be the
-/// same as the impl's node id).
+/// that the ref_id is for. Note that ref_id's value is not the NodeId of the
+/// trait being referred to but just a unique NodeId that serves as a key
+/// within the DefMap.
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct TraitRef {
pub path: Path,
use ty::TyVar;
use ty::relate::{Relate, RelateResult, TypeRelation};
-pub struct Bivariate<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
- fields: CombineFields<'a, 'gcx, 'tcx>
+pub struct Bivariate<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
+ fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>,
+ a_is_expected: bool,
}
-impl<'a, 'gcx, 'tcx> Bivariate<'a, 'gcx, 'tcx> {
- pub fn new(fields: CombineFields<'a, 'gcx, 'tcx>) -> Bivariate<'a, 'gcx, 'tcx> {
- Bivariate { fields: fields }
+impl<'combine, 'infcx, 'gcx, 'tcx> Bivariate<'combine, 'infcx, 'gcx, 'tcx> {
+ pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool)
+ -> Bivariate<'combine, 'infcx, 'gcx, 'tcx>
+ {
+ Bivariate { fields: fields, a_is_expected: a_is_expected }
}
}
-impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Bivariate<'a, 'gcx, 'tcx> {
+impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
+ for Bivariate<'combine, 'infcx, 'gcx, 'tcx>
+{
fn tag(&self) -> &'static str { "Bivariate" }
- fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.fields.tcx() }
+ fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() }
- fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
+ fn a_is_expected(&self) -> bool { self.a_is_expected }
fn relate_with_variance<T: Relate<'tcx>>(&mut self,
variance: ty::Variance,
}
(&ty::TyInfer(TyVar(a_id)), _) => {
- self.fields.instantiate(b, BiTo, a_id)?;
+ self.fields.instantiate(b, BiTo, a_id, self.a_is_expected)?;
Ok(a)
}
(_, &ty::TyInfer(TyVar(b_id))) => {
- self.fields.instantiate(a, BiTo, b_id)?;
+ self.fields.instantiate(a, BiTo, b_id, self.a_is_expected)?;
Ok(a)
}
use syntax_pos::Span;
#[derive(Clone)]
-pub struct CombineFields<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
- pub infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
- pub a_is_expected: bool,
+pub struct CombineFields<'infcx, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
+ pub infcx: &'infcx InferCtxt<'infcx, 'gcx, 'tcx>,
pub trace: TypeTrace<'tcx>,
pub cause: Option<ty::relate::Cause>,
pub obligations: PredicateObligations<'tcx>,
}
-impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
+impl<'infcx, 'gcx, 'tcx> InferCtxt<'infcx, 'gcx, 'tcx> {
pub fn super_combine_tys<R>(&self,
relation: &mut R,
a: Ty<'tcx>,
b: Ty<'tcx>)
-> RelateResult<'tcx, Ty<'tcx>>
- where R: TypeRelation<'a, 'gcx, 'tcx>
+ where R: TypeRelation<'infcx, 'gcx, 'tcx>
{
let a_is_expected = relation.a_is_expected();
}
}
-impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
- pub fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
+impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> {
+ pub fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> {
self.infcx.tcx
}
- pub fn switch_expected(&self) -> CombineFields<'a, 'gcx, 'tcx> {
- CombineFields {
- a_is_expected: !self.a_is_expected,
- ..(*self).clone()
- }
- }
-
- pub fn equate(&self) -> Equate<'a, 'gcx, 'tcx> {
- Equate::new(self.clone())
+ pub fn equate<'a>(&'a mut self, a_is_expected: bool) -> Equate<'a, 'infcx, 'gcx, 'tcx> {
+ Equate::new(self, a_is_expected)
}
- pub fn bivariate(&self) -> Bivariate<'a, 'gcx, 'tcx> {
- Bivariate::new(self.clone())
+ pub fn bivariate<'a>(&'a mut self, a_is_expected: bool) -> Bivariate<'a, 'infcx, 'gcx, 'tcx> {
+ Bivariate::new(self, a_is_expected)
}
- pub fn sub(&self) -> Sub<'a, 'gcx, 'tcx> {
- Sub::new(self.clone())
+ pub fn sub<'a>(&'a mut self, a_is_expected: bool) -> Sub<'a, 'infcx, 'gcx, 'tcx> {
+ Sub::new(self, a_is_expected)
}
- pub fn lub(&self) -> Lub<'a, 'gcx, 'tcx> {
- Lub::new(self.clone())
+ pub fn lub<'a>(&'a mut self, a_is_expected: bool) -> Lub<'a, 'infcx, 'gcx, 'tcx> {
+ Lub::new(self, a_is_expected)
}
- pub fn glb(&self) -> Glb<'a, 'gcx, 'tcx> {
- Glb::new(self.clone())
+ pub fn glb<'a>(&'a mut self, a_is_expected: bool) -> Glb<'a, 'infcx, 'gcx, 'tcx> {
+ Glb::new(self, a_is_expected)
}
- pub fn instantiate(&self,
+ pub fn instantiate(&mut self,
a_ty: Ty<'tcx>,
dir: RelationDir,
- b_vid: ty::TyVid)
+ b_vid: ty::TyVid,
+ a_is_expected: bool)
-> RelateResult<'tcx, ()>
{
let mut stack = Vec::new();
// to associate causes/spans with each of the relations in
// the stack to get this right.
match dir {
- BiTo => self.bivariate().relate(&a_ty, &b_ty),
- EqTo => self.equate().relate(&a_ty, &b_ty),
- SubtypeOf => self.sub().relate(&a_ty, &b_ty),
- SupertypeOf => self.sub().relate_with_variance(ty::Contravariant, &a_ty, &b_ty),
+ BiTo => self.bivariate(a_is_expected).relate(&a_ty, &b_ty),
+ EqTo => self.equate(a_is_expected).relate(&a_ty, &b_ty),
+ SubtypeOf => self.sub(a_is_expected).relate(&a_ty, &b_ty),
+ SupertypeOf => self.sub(a_is_expected).relate_with_variance(
+ ty::Contravariant, &a_ty, &b_ty),
}?;
}
use ty::{self, Ty, TyCtxt};
use ty::TyVar;
use ty::relate::{Relate, RelateResult, TypeRelation};
-use traits::PredicateObligations;
/// Ensures `a` is made equal to `b`. Returns `a` on success.
-pub struct Equate<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
- fields: CombineFields<'a, 'gcx, 'tcx>
+pub struct Equate<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
+ fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>,
+ a_is_expected: bool,
}
-impl<'a, 'gcx, 'tcx> Equate<'a, 'gcx, 'tcx> {
- pub fn new(fields: CombineFields<'a, 'gcx, 'tcx>) -> Equate<'a, 'gcx, 'tcx> {
- Equate { fields: fields }
- }
-
- pub fn obligations(self) -> PredicateObligations<'tcx> {
- self.fields.obligations
+impl<'combine, 'infcx, 'gcx, 'tcx> Equate<'combine, 'infcx, 'gcx, 'tcx> {
+ pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool)
+ -> Equate<'combine, 'infcx, 'gcx, 'tcx>
+ {
+ Equate { fields: fields, a_is_expected: a_is_expected }
}
}
-impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Equate<'a, 'gcx, 'tcx> {
+impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
+ for Equate<'combine, 'infcx, 'gcx, 'tcx>
+{
fn tag(&self) -> &'static str { "Equate" }
- fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.fields.tcx() }
+ fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() }
- fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
+ fn a_is_expected(&self) -> bool { self.a_is_expected }
fn relate_with_variance<T: Relate<'tcx>>(&mut self,
_: ty::Variance,
}
(&ty::TyInfer(TyVar(a_id)), _) => {
- self.fields.instantiate(b, EqTo, a_id)?;
+ self.fields.instantiate(b, EqTo, a_id, self.a_is_expected)?;
Ok(a)
}
(_, &ty::TyInfer(TyVar(b_id))) => {
- self.fields.instantiate(a, EqTo, b_id)?;
+ self.fields.instantiate(a, EqTo, b_id, self.a_is_expected)?;
Ok(a)
}
-> RelateResult<'tcx, ty::Binder<T>>
where T: Relate<'tcx>
{
- self.fields.higher_ranked_sub(a, b)?;
- self.fields.higher_ranked_sub(b, a)
+ self.fields.higher_ranked_sub(a, b, self.a_is_expected)?;
+ self.fields.higher_ranked_sub(b, a, self.a_is_expected)
}
}
use infer::{self, TypeOrigin};
use middle::region;
use ty::subst;
-use ty::{self, Ty, TyCtxt, TypeFoldable};
+use ty::{self, TyCtxt, TypeFoldable};
use ty::{Region, ReFree};
use ty::error::TypeError;
}
}
- fn report_type_error(&self,
- trace: TypeTrace<'tcx>,
- terr: &TypeError<'tcx>)
- -> DiagnosticBuilder<'tcx> {
- let (expected, found) = match self.values_str(&trace.values) {
- Some(v) => v,
- None => {
- return self.tcx.sess.diagnostic().struct_dummy(); /* derived error */
- }
- };
-
- let is_simple_error = if let &TypeError::Sorts(ref values) = terr {
- values.expected.is_primitive() && values.found.is_primitive()
- } else {
- false
- };
-
- let mut err = struct_span_err!(self.tcx.sess,
- trace.origin.span(),
- E0308,
- "{}",
- trace.origin);
-
- if !is_simple_error || check_old_school() {
- err.note_expected_found(&"type", &expected, &found);
- }
-
- err.span_label(trace.origin.span(), &terr);
-
- self.check_and_note_conflicting_crates(&mut err, terr, trace.origin.span());
-
- match trace.origin {
- TypeOrigin::MatchExpressionArm(_, arm_span, source) => match source {
- hir::MatchSource::IfLetDesugar{..} => {
- err.span_note(arm_span, "`if let` arm with an incompatible type");
- }
- _ => {
- err.span_note(arm_span, "match arm with an incompatible type");
- }
- },
- _ => ()
- }
-
- err
- }
-
/// Adds a note if the types come from similarly named crates
fn check_and_note_conflicting_crates(&self,
err: &mut DiagnosticBuilder,
}
}
+ fn note_error_origin(&self,
+ err: &mut DiagnosticBuilder<'tcx>,
+ origin: &TypeOrigin)
+ {
+ match origin {
+ &TypeOrigin::MatchExpressionArm(_, arm_span, source) => match source {
+ hir::MatchSource::IfLetDesugar {..} => {
+ err.span_note(arm_span, "`if let` arm with an incompatible type");
+ }
+ _ => {
+ err.span_note(arm_span, "match arm with an incompatible type");
+ }
+ },
+ _ => ()
+ }
+ }
+
+ pub fn note_type_err(&self,
+ diag: &mut DiagnosticBuilder<'tcx>,
+ origin: TypeOrigin,
+ values: Option<ValuePairs<'tcx>>,
+ terr: &TypeError<'tcx>)
+ {
+ let expected_found = match values {
+ None => None,
+ Some(values) => match self.values_str(&values) {
+ Some((expected, found)) => Some((expected, found)),
+ None => {
+ // Derived error. Cancel the emitter.
+ self.tcx.sess.diagnostic().cancel(diag);
+ return
+ }
+ }
+ };
+
+ let span = origin.span();
+
+ let mut is_simple_error = false;
+
+ if let Some((expected, found)) = expected_found {
+ is_simple_error = if let &TypeError::Sorts(ref values) = terr {
+ values.expected.is_primitive() && values.found.is_primitive()
+ } else {
+ false
+ };
+
+ if !is_simple_error || check_old_school() {
+ diag.note_expected_found(&"type", &expected, &found);
+ }
+ }
+
+ if !is_simple_error && check_old_school() {
+ diag.span_note(span, &format!("{}", terr));
+ } else {
+ diag.span_label(span, &terr);
+ }
+
+ self.note_error_origin(diag, &origin);
+ self.check_and_note_conflicting_crates(diag, terr, span);
+ self.tcx.note_and_explain_type_err(diag, terr, span);
+ }
+
pub fn report_and_explain_type_error(&self,
trace: TypeTrace<'tcx>,
terr: &TypeError<'tcx>)
- -> DiagnosticBuilder<'tcx> {
- let span = trace.origin.span();
- let mut err = self.report_type_error(trace, terr);
- self.tcx.note_and_explain_type_err(&mut err, terr, span);
- err
+ -> DiagnosticBuilder<'tcx>
+ {
+ // FIXME: do we want to use a different error code for each origin?
+ let mut diag = struct_span_err!(
+ self.tcx.sess, trace.origin.span(), E0308,
+ "{}", trace.origin.as_failure_str()
+ );
+ self.note_type_err(&mut diag, trace.origin, Some(trace.values), terr);
+ diag
}
- /// Returns a string of the form "expected `{}`, found `{}`", or None if this is a derived
- /// error.
+ /// Returns a string of the form "expected `{}`, found `{}`".
fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<(String, String)> {
match *values {
infer::Types(ref exp_found) => self.expected_found_str(exp_found),
infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found),
- infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found)
+ infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found),
}
}
- fn expected_found_str<T: fmt::Display + Resolvable<'tcx> + TypeFoldable<'tcx>>(
+ fn expected_found_str<T: fmt::Display + TypeFoldable<'tcx>>(
&self,
exp_found: &ty::error::ExpectedFound<T>)
-> Option<(String, String)>
{
- let expected = exp_found.expected.resolve(self);
- if expected.references_error() {
- return None;
- }
-
- let found = exp_found.found.resolve(self);
- if found.references_error() {
+ let exp_found = self.resolve_type_vars_if_possible(exp_found);
+ if exp_found.references_error() {
return None;
}
- Some((format!("{}", expected), format!("{}", found)))
+ Some((format!("{}", exp_found.expected), format!("{}", exp_found.found)))
}
fn report_generic_bound_failure(&self,
fn note_region_origin(&self, err: &mut DiagnosticBuilder, origin: &SubregionOrigin<'tcx>) {
match *origin {
infer::Subtype(ref trace) => {
- let desc = match trace.origin {
- TypeOrigin::Misc(_) => {
- "types are compatible"
- }
- TypeOrigin::MethodCompatCheck(_) => {
- "method type is compatible with trait"
- }
- TypeOrigin::ExprAssignable(_) => {
- "expression is assignable"
- }
- TypeOrigin::RelateTraitRefs(_) => {
- "traits are compatible"
- }
- TypeOrigin::RelateSelfType(_) => {
- "self type matches impl self type"
- }
- TypeOrigin::RelateOutputImplTypes(_) => {
- "trait type parameters matches those \
- specified on the impl"
- }
- TypeOrigin::MatchExpressionArm(_, _, _) => {
- "match arms have compatible types"
- }
- TypeOrigin::IfExpression(_) => {
- "if and else have compatible types"
- }
- TypeOrigin::IfExpressionWithNoElse(_) => {
- "if may be missing an else clause"
- }
- TypeOrigin::RangeExpression(_) => {
- "start and end of range have compatible types"
- }
- TypeOrigin::EquatePredicate(_) => {
- "equality where clause is satisfied"
- }
- };
-
- match self.values_str(&trace.values) {
- Some((expected, found)) => {
- err.span_note(
- trace.origin.span(),
- &format!("...so that {} (expected {}, found {})",
- desc, expected, found));
- }
- None => {
- // Really should avoid printing this error at
- // all, since it is derived, but that would
- // require more refactoring than I feel like
- // doing right now. - nmatsakis
- err.span_note(
- trace.origin.span(),
- &format!("...so that {}", desc));
- }
+ if let Some((expected, found)) = self.values_str(&trace.values) {
+ // FIXME: do we want a "the" here?
+ err.span_note(
+ trace.origin.span(),
+ &format!("...so that {} (expected {}, found {})",
+ trace.origin.as_requirement_str(), expected, found));
+ } else {
+ // FIXME: this really should be handled at some earlier stage. Our
+ // handling of region checking when type errors are present is
+ // *terrible*.
+
+ err.span_note(
+ trace.origin.span(),
+ &format!("...so that {}",
+ trace.origin.as_requirement_str()));
}
}
infer::Reborrow(span) => {
}
}
-pub trait Resolvable<'tcx> {
- fn resolve<'a, 'gcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) -> Self;
-}
-
-impl<'tcx> Resolvable<'tcx> for Ty<'tcx> {
- fn resolve<'a, 'gcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
- infcx.resolve_type_vars_if_possible(self)
- }
-}
-
-impl<'tcx> Resolvable<'tcx> for ty::TraitRef<'tcx> {
- fn resolve<'a, 'gcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>)
- -> ty::TraitRef<'tcx> {
- infcx.resolve_type_vars_if_possible(self)
- }
-}
-
-impl<'tcx> Resolvable<'tcx> for ty::PolyTraitRef<'tcx> {
- fn resolve<'a, 'gcx>(&self,
- infcx: &InferCtxt<'a, 'gcx, 'tcx>)
- -> ty::PolyTraitRef<'tcx>
- {
- infcx.resolve_type_vars_if_possible(self)
- }
-}
-
fn lifetimes_in_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
scope_id: ast::NodeId)
-> Vec<hir::LifetimeDef> {
use ty::{self, Ty, TyCtxt};
use ty::relate::{Relate, RelateResult, TypeRelation};
-use traits::PredicateObligations;
/// "Greatest lower bound" (common subtype)
-pub struct Glb<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
- fields: CombineFields<'a, 'gcx, 'tcx>
+pub struct Glb<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
+ fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>,
+ a_is_expected: bool,
}
-impl<'a, 'gcx, 'tcx> Glb<'a, 'gcx, 'tcx> {
- pub fn new(fields: CombineFields<'a, 'gcx, 'tcx>) -> Glb<'a, 'gcx, 'tcx> {
- Glb { fields: fields }
- }
-
- pub fn obligations(self) -> PredicateObligations<'tcx> {
- self.fields.obligations
+impl<'combine, 'infcx, 'gcx, 'tcx> Glb<'combine, 'infcx, 'gcx, 'tcx> {
+ pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool)
+ -> Glb<'combine, 'infcx, 'gcx, 'tcx>
+ {
+ Glb { fields: fields, a_is_expected: a_is_expected }
}
}
-impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Glb<'a, 'gcx, 'tcx> {
+impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
+ for Glb<'combine, 'infcx, 'gcx, 'tcx>
+{
fn tag(&self) -> &'static str { "Glb" }
- fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.fields.tcx() }
+ fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() }
- fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
+ fn a_is_expected(&self) -> bool { self.a_is_expected }
fn relate_with_variance<T: Relate<'tcx>>(&mut self,
variance: ty::Variance,
-> RelateResult<'tcx, T>
{
match variance {
- ty::Invariant => self.fields.equate().relate(a, b),
+ ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b),
ty::Covariant => self.relate(a, b),
- ty::Bivariant => self.fields.bivariate().relate(a, b),
- ty::Contravariant => self.fields.lub().relate(a, b),
+ ty::Bivariant => self.fields.bivariate(self.a_is_expected).relate(a, b),
+ ty::Contravariant => self.fields.lub(self.a_is_expected).relate(a, b),
}
}
-> RelateResult<'tcx, ty::Binder<T>>
where T: Relate<'tcx>
{
- self.fields.higher_ranked_glb(a, b)
+ self.fields.higher_ranked_glb(a, b, self.a_is_expected)
}
}
-impl<'a, 'gcx, 'tcx> LatticeDir<'a, 'gcx, 'tcx> for Glb<'a, 'gcx, 'tcx> {
- fn infcx(&self) -> &'a InferCtxt<'a, 'gcx, 'tcx> {
+impl<'combine, 'infcx, 'gcx, 'tcx> LatticeDir<'infcx, 'gcx, 'tcx>
+ for Glb<'combine, 'infcx, 'gcx, 'tcx>
+{
+ fn infcx(&self) -> &'infcx InferCtxt<'infcx, 'gcx, 'tcx> {
self.fields.infcx
}
- fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
- let mut sub = self.fields.sub();
+ fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
+ let mut sub = self.fields.sub(self.a_is_expected);
sub.relate(&v, &a)?;
sub.relate(&v, &b)?;
Ok(())
}
impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
- pub fn higher_ranked_sub<T>(&self, a: &Binder<T>, b: &Binder<T>)
+ pub fn higher_ranked_sub<T>(&mut self, a: &Binder<T>, b: &Binder<T>, a_is_expected: bool)
-> RelateResult<'tcx, Binder<T>>
where T: Relate<'tcx>
{
debug!("b_prime={:?}", b_prime);
// Compare types now that bound regions have been replaced.
- let result = self.sub().relate(&a_prime, &b_prime)?;
+ let result = self.sub(a_is_expected).relate(&a_prime, &b_prime)?;
// Presuming type comparison succeeds, we need to check
// that the skolemized regions do not "leak".
- self.infcx.leak_check(!self.a_is_expected, span, &skol_map, snapshot)?;
+ self.infcx.leak_check(!a_is_expected, span, &skol_map, snapshot)?;
// We are finished with the skolemized regions now so pop
// them off.
/// NB. It should not happen that there are LBR appearing in `U`
/// that do not appear in `T`. If that happens, those regions are
/// unconstrained, and this routine replaces them with `'static`.
- pub fn higher_ranked_match<T, U>(&self,
+ pub fn higher_ranked_match<T, U>(&mut self,
span: Span,
a_pair: &Binder<(T, U)>,
- b_match: &T)
+ b_match: &T,
+ a_is_expected: bool)
-> RelateResult<'tcx, HrMatchResult<U>>
where T: Relate<'tcx>,
U: TypeFoldable<'tcx>
debug!("higher_ranked_match: skol_map={:?}", skol_map);
// Equate types now that bound regions have been replaced.
- try!(self.equate().relate(&a_match, &b_match));
+ try!(self.equate(a_is_expected).relate(&a_match, &b_match));
// Map each skolemized region to a vector of other regions that it
// must be equated with. (Note that this vector may include other
});
}
- pub fn higher_ranked_lub<T>(&self, a: &Binder<T>, b: &Binder<T>)
+ pub fn higher_ranked_lub<T>(&mut self, a: &Binder<T>, b: &Binder<T>, a_is_expected: bool)
-> RelateResult<'tcx, Binder<T>>
where T: Relate<'tcx>
{
// Collect constraints.
let result0 =
- self.lub().relate(&a_with_fresh, &b_with_fresh)?;
+ self.lub(a_is_expected).relate(&a_with_fresh, &b_with_fresh)?;
let result0 =
self.infcx.resolve_type_vars_if_possible(&result0);
debug!("lub result0 = {:?}", result0);
}
}
- pub fn higher_ranked_glb<T>(&self, a: &Binder<T>, b: &Binder<T>)
+ pub fn higher_ranked_glb<T>(&mut self, a: &Binder<T>, b: &Binder<T>, a_is_expected: bool)
-> RelateResult<'tcx, Binder<T>>
where T: Relate<'tcx>
{
// Collect constraints.
let result0 =
- self.glb().relate(&a_with_fresh, &b_with_fresh)?;
+ self.glb(a_is_expected).relate(&a_with_fresh, &b_with_fresh)?;
let result0 =
self.infcx.resolve_type_vars_if_possible(&result0);
debug!("glb result0 = {:?}", result0);
// Relates the type `v` to `a` and `b` such that `v` represents
// the LUB/GLB of `a` and `b` as appropriate.
- fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>;
+ fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>;
}
pub fn super_lattice_tys<'a, 'gcx, 'tcx, L>(this: &mut L,
use ty::{self, Ty, TyCtxt};
use ty::relate::{Relate, RelateResult, TypeRelation};
-use traits::PredicateObligations;
/// "Least upper bound" (common supertype)
-pub struct Lub<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
- fields: CombineFields<'a, 'gcx, 'tcx>
+pub struct Lub<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
+ fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>,
+ a_is_expected: bool,
}
-impl<'a, 'gcx, 'tcx> Lub<'a, 'gcx, 'tcx> {
- pub fn new(fields: CombineFields<'a, 'gcx, 'tcx>) -> Lub<'a, 'gcx, 'tcx> {
- Lub { fields: fields }
- }
-
- pub fn obligations(self) -> PredicateObligations<'tcx> {
- self.fields.obligations
+impl<'combine, 'infcx, 'gcx, 'tcx> Lub<'combine, 'infcx, 'gcx, 'tcx> {
+ pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool)
+ -> Lub<'combine, 'infcx, 'gcx, 'tcx>
+ {
+ Lub { fields: fields, a_is_expected: a_is_expected }
}
}
-impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Lub<'a, 'gcx, 'tcx> {
+impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
+ for Lub<'combine, 'infcx, 'gcx, 'tcx>
+{
fn tag(&self) -> &'static str { "Lub" }
- fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.fields.tcx() }
+ fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() }
- fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
+ fn a_is_expected(&self) -> bool { self.a_is_expected }
fn relate_with_variance<T: Relate<'tcx>>(&mut self,
variance: ty::Variance,
-> RelateResult<'tcx, T>
{
match variance {
- ty::Invariant => self.fields.equate().relate(a, b),
+ ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b),
ty::Covariant => self.relate(a, b),
- ty::Bivariant => self.fields.bivariate().relate(a, b),
- ty::Contravariant => self.fields.glb().relate(a, b),
+ ty::Bivariant => self.fields.bivariate(self.a_is_expected).relate(a, b),
+ ty::Contravariant => self.fields.glb(self.a_is_expected).relate(a, b),
}
}
-> RelateResult<'tcx, ty::Binder<T>>
where T: Relate<'tcx>
{
- self.fields.higher_ranked_lub(a, b)
+ self.fields.higher_ranked_lub(a, b, self.a_is_expected)
}
}
-impl<'a, 'gcx, 'tcx> LatticeDir<'a, 'gcx, 'tcx> for Lub<'a, 'gcx, 'tcx> {
- fn infcx(&self) -> &'a InferCtxt<'a, 'gcx, 'tcx> {
+impl<'combine, 'infcx, 'gcx, 'tcx> LatticeDir<'infcx, 'gcx, 'tcx>
+ for Lub<'combine, 'infcx, 'gcx, 'tcx>
+{
+ fn infcx(&self) -> &'infcx InferCtxt<'infcx, 'gcx, 'tcx> {
self.fields.infcx
}
- fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
- let mut sub = self.fields.sub();
+ fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
+ let mut sub = self.fields.sub(self.a_is_expected);
sub.relate(&a, &v)?;
sub.relate(&b, &v)?;
Ok(())
use ty::{TyVid, IntVid, FloatVid};
use ty::{self, Ty, TyCtxt};
use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
-use ty::fold::TypeFoldable;
+use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use ty::relate::{Relate, RelateResult, TypeRelation};
use traits::{self, PredicateObligations, ProjectionMode};
use rustc_data_structures::unify::{self, UnificationTable};
use self::region_inference::{RegionVarBindings, RegionSnapshot};
use self::unify_key::ToType;
-pub mod bivariate;
-pub mod combine;
-pub mod equate;
+mod bivariate;
+mod combine;
+mod equate;
pub mod error_reporting;
-pub mod glb;
+mod glb;
mod higher_ranked;
pub mod lattice;
-pub mod lub;
+mod lub;
pub mod region_inference;
pub mod resolve;
mod freshen;
-pub mod sub;
+mod sub;
pub mod type_variable;
pub mod unify_key;
// FIXME(eddyb) #11161 is the original Expr required?
ExprAssignable(Span),
- // Relating trait refs when resolving vtables
- RelateTraitRefs(Span),
-
- // Relating self types when resolving vtables
- RelateSelfType(Span),
-
// Relating trait type parameters to those found in impl etc
RelateOutputImplTypes(Span),
// `where a == b`
EquatePredicate(Span),
+
+ // `main` has wrong type
+ MainFunctionType(Span),
+
+ // `start` has wrong type
+ StartFunctionType(Span),
+
+ // intrinsic has wrong type
+ IntrinsicType(Span),
+
+ // method receiver
+ MethodReceiver(Span),
}
impl TypeOrigin {
- fn as_str(&self) -> &'static str {
+ fn as_failure_str(&self) -> &'static str {
match self {
&TypeOrigin::Misc(_) |
- &TypeOrigin::RelateSelfType(_) |
&TypeOrigin::RelateOutputImplTypes(_) |
&TypeOrigin::ExprAssignable(_) => "mismatched types",
- &TypeOrigin::RelateTraitRefs(_) => "mismatched traits",
&TypeOrigin::MethodCompatCheck(_) => "method not compatible with trait",
&TypeOrigin::MatchExpressionArm(_, _, source) => match source {
hir::MatchSource::IfLetDesugar{..} => "`if let` arms have incompatible types",
&TypeOrigin::IfExpressionWithNoElse(_) => "if may be missing an else clause",
&TypeOrigin::RangeExpression(_) => "start and end of range have incompatible types",
&TypeOrigin::EquatePredicate(_) => "equality predicate not satisfied",
+ &TypeOrigin::MainFunctionType(_) => "main function has wrong type",
+ &TypeOrigin::StartFunctionType(_) => "start function has wrong type",
+ &TypeOrigin::IntrinsicType(_) => "intrinsic has wrong type",
+ &TypeOrigin::MethodReceiver(_) => "mismatched method receiver",
}
}
-}
-impl fmt::Display for TypeOrigin {
- fn fmt(&self, f: &mut fmt::Formatter) -> Result<(),fmt::Error> {
- fmt::Display::fmt(self.as_str(), f)
+ fn as_requirement_str(&self) -> &'static str {
+ match self {
+ &TypeOrigin::Misc(_) => "types are compatible",
+ &TypeOrigin::MethodCompatCheck(_) => "method type is compatible with trait",
+ &TypeOrigin::ExprAssignable(_) => "expression is assignable",
+ &TypeOrigin::RelateOutputImplTypes(_) => {
+ "trait type parameters matches those specified on the impl"
+ }
+ &TypeOrigin::MatchExpressionArm(_, _, _) => "match arms have compatible types",
+ &TypeOrigin::IfExpression(_) => "if and else have compatible types",
+ &TypeOrigin::IfExpressionWithNoElse(_) => "if missing an else returns ()",
+ &TypeOrigin::RangeExpression(_) => "start and end of range have compatible types",
+ &TypeOrigin::EquatePredicate(_) => "equality where clause is satisfied",
+ &TypeOrigin::MainFunctionType(_) => "`main` function has the correct type",
+ &TypeOrigin::StartFunctionType(_) => "`start` function has the correct type",
+ &TypeOrigin::IntrinsicType(_) => "intrinsic has the correct type",
+ &TypeOrigin::MethodReceiver(_) => "method receiver has the correct type",
+ }
}
}
return variables;
}
- fn combine_fields(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>)
+ fn combine_fields(&'a self, trace: TypeTrace<'tcx>)
-> CombineFields<'a, 'gcx, 'tcx> {
CombineFields {
infcx: self,
- a_is_expected: a_is_expected,
trace: trace,
cause: None,
obligations: PredicateObligations::new(),
-> InferResult<'tcx, T>
where T: Relate<'tcx>
{
- let mut equate = self.combine_fields(a_is_expected, trace).equate();
- let result = equate.relate(a, b);
- result.map(|t| InferOk { value: t, obligations: equate.obligations() })
+ let mut fields = self.combine_fields(trace);
+ let result = fields.equate(a_is_expected).relate(a, b);
+ result.map(move |t| InferOk { value: t, obligations: fields.obligations })
}
pub fn sub<T>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T)
-> InferResult<'tcx, T>
where T: Relate<'tcx>
{
- let mut sub = self.combine_fields(a_is_expected, trace).sub();
- let result = sub.relate(a, b);
- result.map(|t| InferOk { value: t, obligations: sub.obligations() })
+ let mut fields = self.combine_fields(trace);
+ let result = fields.sub(a_is_expected).relate(a, b);
+ result.map(move |t| InferOk { value: t, obligations: fields.obligations })
}
pub fn lub<T>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T)
-> InferResult<'tcx, T>
where T: Relate<'tcx>
{
- let mut lub = self.combine_fields(a_is_expected, trace).lub();
- let result = lub.relate(a, b);
- result.map(|t| InferOk { value: t, obligations: lub.obligations() })
+ let mut fields = self.combine_fields(trace);
+ let result = fields.lub(a_is_expected).relate(a, b);
+ result.map(move |t| InferOk { value: t, obligations: fields.obligations })
}
pub fn glb<T>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T)
-> InferResult<'tcx, T>
where T: Relate<'tcx>
{
- let mut glb = self.combine_fields(a_is_expected, trace).glb();
- let result = glb.relate(a, b);
- result.map(|t| InferOk { value: t, obligations: glb.obligations() })
+ let mut fields = self.combine_fields(trace);
+ let result = fields.glb(a_is_expected).relate(a, b);
+ result.map(move |t| InferOk { value: t, obligations: fields.obligations })
}
fn start_snapshot(&self) -> CombinedSnapshot {
// error type, meaning that an error occurred when typechecking this expression),
// this is a derived error. The error cascaded from another error (that was already
// reported), so it's not useful to display it to the user.
- // The following four methods -- type_error_message_str, type_error_message_str_with_expected,
- // type_error_message, and report_mismatched_types -- implement this logic.
+ // The following methods implement this logic.
// They check if either the actual or expected type is TyError, and don't print the error
// in this case. The typechecker should only ever report type errors involving mismatched
- // types using one of these four methods, and should not call span_err directly for such
+ // types using one of these methods, and should not call span_err directly for such
// errors.
- pub fn type_error_message_str<M>(&self,
- sp: Span,
- mk_msg: M,
- actual_ty: String,
- err: Option<&TypeError<'tcx>>)
- where M: FnOnce(Option<String>, String) -> String,
- {
- self.type_error_message_str_with_expected(sp, mk_msg, None, actual_ty, err)
- }
-
- pub fn type_error_struct_str<M>(&self,
- sp: Span,
- mk_msg: M,
- actual_ty: String,
- err: Option<&TypeError<'tcx>>)
- -> DiagnosticBuilder<'tcx>
- where M: FnOnce(Option<String>, String) -> String,
- {
- self.type_error_struct_str_with_expected(sp, mk_msg, None, actual_ty, err)
- }
-
- pub fn type_error_message_str_with_expected<M>(&self,
- sp: Span,
- mk_msg: M,
- expected_ty: Option<Ty<'tcx>>,
- actual_ty: String,
- err: Option<&TypeError<'tcx>>)
- where M: FnOnce(Option<String>, String) -> String,
- {
- self.type_error_struct_str_with_expected(sp, mk_msg, expected_ty, actual_ty, err)
- .emit();
- }
-
- pub fn type_error_struct_str_with_expected<M>(&self,
- sp: Span,
- mk_msg: M,
- expected_ty: Option<Ty<'tcx>>,
- actual_ty: String,
- err: Option<&TypeError<'tcx>>)
- -> DiagnosticBuilder<'tcx>
- where M: FnOnce(Option<String>, String) -> String,
- {
- debug!("hi! expected_ty = {:?}, actual_ty = {}", expected_ty, actual_ty);
-
- let resolved_expected = expected_ty.map(|e_ty| self.resolve_type_vars_if_possible(&e_ty));
-
- if !resolved_expected.references_error() {
- let error_str = err.map_or("".to_string(), |t_err| {
- format!(" ({})", t_err)
- });
-
- let mut db = self.tcx.sess.struct_span_err(sp, &format!("{}{}",
- mk_msg(resolved_expected.map(|t| self.ty_to_string(t)), actual_ty),
- error_str));
-
- if let Some(err) = err {
- self.tcx.note_and_explain_type_err(&mut db, err, sp);
- }
- db
- } else {
- self.tcx.sess.diagnostic().struct_dummy()
- }
- }
pub fn type_error_message<M>(&self,
sp: Span,
mk_msg: M,
- actual_ty: Ty<'tcx>,
- err: Option<&TypeError<'tcx>>)
+ actual_ty: Ty<'tcx>)
where M: FnOnce(String) -> String,
{
- self.type_error_struct(sp, mk_msg, actual_ty, err).emit();
+ self.type_error_struct(sp, mk_msg, actual_ty).emit();
}
+ // FIXME: this results in errors without an error code. Deprecate?
pub fn type_error_struct<M>(&self,
sp: Span,
mk_msg: M,
- actual_ty: Ty<'tcx>,
- err: Option<&TypeError<'tcx>>)
+ actual_ty: Ty<'tcx>)
-> DiagnosticBuilder<'tcx>
where M: FnOnce(String) -> String,
+ {
+ self.type_error_struct_with_diag(sp, |actual_ty| {
+ self.tcx.sess.struct_span_err(sp, &mk_msg(actual_ty))
+ }, actual_ty)
+ }
+
+ pub fn type_error_struct_with_diag<M>(&self,
+ sp: Span,
+ mk_diag: M,
+ actual_ty: Ty<'tcx>)
+ -> DiagnosticBuilder<'tcx>
+ where M: FnOnce(String) -> DiagnosticBuilder<'tcx>,
{
let actual_ty = self.resolve_type_vars_if_possible(&actual_ty);
+ debug!("type_error_struct_with_diag({:?}, {:?})", sp, actual_ty);
// Don't report an error if actual type is TyError.
if actual_ty.references_error() {
return self.tcx.sess.diagnostic().struct_dummy();
}
- self.type_error_struct_str(sp,
- move |_e, a| { mk_msg(a) },
- self.ty_to_string(actual_ty), err)
+ mk_diag(self.ty_to_string(actual_ty))
}
pub fn report_mismatched_types(&self,
};
let match_pair = match_a.map_bound(|p| (p.projection_ty.trait_ref, p.ty));
- let combine = self.combine_fields(true, trace);
- let result = combine.higher_ranked_match(span, &match_pair, &match_b)?;
+ let mut combine = self.combine_fields(trace);
+ let result = combine.higher_ranked_match(span, &match_pair, &match_b, true)?;
Ok(InferOk { value: result, obligations: combine.obligations })
}
TypeOrigin::MethodCompatCheck(span) => span,
TypeOrigin::ExprAssignable(span) => span,
TypeOrigin::Misc(span) => span,
- TypeOrigin::RelateTraitRefs(span) => span,
- TypeOrigin::RelateSelfType(span) => span,
TypeOrigin::RelateOutputImplTypes(span) => span,
TypeOrigin::MatchExpressionArm(match_span, _, _) => match_span,
TypeOrigin::IfExpression(span) => span,
TypeOrigin::IfExpressionWithNoElse(span) => span,
TypeOrigin::RangeExpression(span) => span,
TypeOrigin::EquatePredicate(span) => span,
+ TypeOrigin::MainFunctionType(span) => span,
+ TypeOrigin::StartFunctionType(span) => span,
+ TypeOrigin::IntrinsicType(span) => span,
+ TypeOrigin::MethodReceiver(span) => span,
}
}
}
}
}
}
+
+impl<'tcx> TypeFoldable<'tcx> for TypeOrigin {
+ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _folder: &mut F) -> Self {
+ self.clone()
+ }
+
+ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> bool {
+ false
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ValuePairs<'tcx> {
+ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+ match *self {
+ ValuePairs::Types(ref ef) => {
+ ValuePairs::Types(ef.fold_with(folder))
+ }
+ ValuePairs::TraitRefs(ref ef) => {
+ ValuePairs::TraitRefs(ef.fold_with(folder))
+ }
+ ValuePairs::PolyTraitRefs(ref ef) => {
+ ValuePairs::PolyTraitRefs(ef.fold_with(folder))
+ }
+ }
+ }
+
+ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+ match *self {
+ ValuePairs::Types(ref ef) => ef.visit_with(visitor),
+ ValuePairs::TraitRefs(ref ef) => ef.visit_with(visitor),
+ ValuePairs::PolyTraitRefs(ref ef) => ef.visit_with(visitor),
+ }
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for TypeTrace<'tcx> {
+ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+ TypeTrace {
+ origin: self.origin.fold_with(folder),
+ values: self.values.fold_with(folder)
+ }
+ }
+
+ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+ self.origin.visit_with(visitor) || self.values.visit_with(visitor)
+ }
+}
use ty::{self, Ty, TyCtxt};
use ty::TyVar;
use ty::relate::{Cause, Relate, RelateResult, TypeRelation};
-use traits::PredicateObligations;
use std::mem;
/// Ensures `a` is made a subtype of `b`. Returns `a` on success.
-pub struct Sub<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
- fields: CombineFields<'a, 'gcx, 'tcx>,
+pub struct Sub<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
+ fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>,
+ a_is_expected: bool,
}
-impl<'a, 'gcx, 'tcx> Sub<'a, 'gcx, 'tcx> {
- pub fn new(f: CombineFields<'a, 'gcx, 'tcx>) -> Sub<'a, 'gcx, 'tcx> {
- Sub { fields: f }
+impl<'combine, 'infcx, 'gcx, 'tcx> Sub<'combine, 'infcx, 'gcx, 'tcx> {
+ pub fn new(f: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool)
+ -> Sub<'combine, 'infcx, 'gcx, 'tcx>
+ {
+ Sub { fields: f, a_is_expected: a_is_expected }
}
- pub fn obligations(self) -> PredicateObligations<'tcx> {
- self.fields.obligations
+ fn with_expected_switched<R, F: FnOnce(&mut Self) -> R>(&mut self, f: F) -> R {
+ self.a_is_expected = !self.a_is_expected;
+ let result = f(self);
+ self.a_is_expected = !self.a_is_expected;
+ result
}
}
-impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Sub<'a, 'gcx, 'tcx> {
+impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
+ for Sub<'combine, 'infcx, 'gcx, 'tcx>
+{
fn tag(&self) -> &'static str { "Sub" }
- fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.fields.infcx.tcx }
- fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
+ fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.infcx.tcx }
+ fn a_is_expected(&self) -> bool { self.a_is_expected }
fn with_cause<F,R>(&mut self, cause: Cause, f: F) -> R
where F: FnOnce(&mut Self) -> R
-> RelateResult<'tcx, T>
{
match variance {
- ty::Invariant => self.fields.equate().relate(a, b),
+ ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b),
ty::Covariant => self.relate(a, b),
- ty::Bivariant => self.fields.bivariate().relate(a, b),
- ty::Contravariant => self.fields.switch_expected().sub().relate(b, a),
+ ty::Bivariant => self.fields.bivariate(self.a_is_expected).relate(a, b),
+ ty::Contravariant => self.with_expected_switched(|this| { this.relate(b, a) }),
}
}
}
(&ty::TyInfer(TyVar(a_id)), _) => {
self.fields
- .switch_expected()
- .instantiate(b, SupertypeOf, a_id)?;
+ .instantiate(b, SupertypeOf, a_id, !self.a_is_expected)?;
Ok(a)
}
(_, &ty::TyInfer(TyVar(b_id))) => {
- self.fields.instantiate(a, SubtypeOf, b_id)?;
+ self.fields.instantiate(a, SubtypeOf, b_id, self.a_is_expected)?;
Ok(a)
}
-> RelateResult<'tcx, ty::Binder<T>>
where T: Relate<'tcx>
{
- self.fields.higher_ranked_sub(a, b)
+ self.fields.higher_ranked_sub(a, b, self.a_is_expected)
}
}
use errors::DiagnosticBuilder;
use hir;
use hir::intravisit as hir_visit;
-use hir::intravisit::{IdVisitor, IdVisitingOperation};
use syntax::visit as ast_visit;
/// Information about the registered lints.
attr::mark_used(attr);
let meta = &attr.node.value;
- let metas = match meta.node {
- ast::MetaItemKind::List(_, ref metas) => metas,
- _ => {
- out.push(Err(meta.span));
- return out;
- }
+ let metas = if let Some(metas) = meta.meta_item_list() {
+ metas
+ } else {
+ out.push(Err(meta.span));
+ return out;
};
for meta in metas {
- out.push(match meta.node {
- ast::MetaItemKind::Word(ref lint_name) => Ok((lint_name.clone(), level, meta.span)),
- _ => Err(meta.span),
+ out.push(if meta.is_word() {
+ Ok((meta.name().clone(), level, meta.span))
+ } else {
+ Err(meta.span)
});
}
}
fn visit_ids<F>(&mut self, f: F)
- where F: FnOnce(&mut IdVisitor<LateContext>)
+ where F: FnOnce(&mut IdVisitor)
{
- let mut v = IdVisitor::new(self);
+ let mut v = IdVisitor {
+ cx: self
+ };
f(&mut v);
}
}
fn visit_fn(&mut self, fk: hir_visit::FnKind<'v>, decl: &'v hir::FnDecl,
body: &'v hir::Block, span: Span, id: ast::NodeId) {
run_lints!(self, check_fn, late_passes, fk, decl, body, span, id);
- hir_visit::walk_fn(self, fk, decl, body, span);
+ hir_visit::walk_fn(self, fk, decl, body, span, id);
run_lints!(self, check_fn_post, late_passes, fk, decl, body, span, id);
}
fn visit_mod(&mut self, m: &hir::Mod, s: Span, n: ast::NodeId) {
run_lints!(self, check_mod, late_passes, m, s, n);
- hir_visit::walk_mod(self, m);
+ hir_visit::walk_mod(self, m, n);
run_lints!(self, check_mod_post, late_passes, m, s, n);
}
fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) {
self.with_lint_attrs(&trait_item.attrs, |cx| {
run_lints!(cx, check_trait_item, late_passes, trait_item);
- cx.visit_ids(|v| v.visit_trait_item(trait_item));
+ cx.visit_ids(|v| hir_visit::walk_trait_item(v, trait_item));
hir_visit::walk_trait_item(cx, trait_item);
run_lints!(cx, check_trait_item_post, late_passes, trait_item);
});
fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) {
self.with_lint_attrs(&impl_item.attrs, |cx| {
run_lints!(cx, check_impl_item, late_passes, impl_item);
- cx.visit_ids(|v| v.visit_impl_item(impl_item));
+ cx.visit_ids(|v| hir_visit::walk_impl_item(v, impl_item));
hir_visit::walk_impl_item(cx, impl_item);
run_lints!(cx, check_impl_item_post, late_passes, impl_item);
});
}
}
+struct IdVisitor<'a, 'b: 'a, 'tcx: 'a+'b> {
+ cx: &'a mut LateContext<'b, 'tcx>
+}
+
// Output any lints that were previously added to the session.
-impl<'a, 'tcx> IdVisitingOperation for LateContext<'a, 'tcx> {
+impl<'a, 'b, 'tcx, 'v> hir_visit::Visitor<'v> for IdVisitor<'a, 'b, 'tcx> {
+
fn visit_id(&mut self, id: ast::NodeId) {
- if let Some(lints) = self.sess().lints.borrow_mut().remove(&id) {
+ if let Some(lints) = self.cx.sess().lints.borrow_mut().remove(&id) {
debug!("LateContext::visit_id: id={:?} lints={:?}", id, lints);
for (lint_id, span, msg) in lints {
- self.span_lint(lint_id.lint, span, &msg[..])
+ self.cx.span_lint(lint_id.lint, span, &msg[..])
}
}
}
+
+ fn visit_trait_item(&mut self, _ti: &hir::TraitItem) {
+ // Do not recurse into trait or impl items automatically. These are
+ // processed separately by calling hir_visit::walk_trait_item()
+ }
+
+ fn visit_impl_item(&mut self, _ii: &hir::ImplItem) {
+ // See visit_trait_item()
+ }
}
enum CheckLintNameResult {
// Visit the whole crate.
cx.with_lint_attrs(&krate.attrs, |cx| {
- cx.visit_id(ast::CRATE_NODE_ID);
cx.visit_ids(|v| {
hir_visit::walk_crate(v, krate);
});
use syntax_pos::Span;
use rustc_back::target::Target;
use hir;
-use hir::intravisit::{IdVisitor, IdVisitingOperation, Visitor};
+use hir::intravisit::Visitor;
pub use self::DefLike::{DlDef, DlField, DlImpl};
pub use self::NativeLibraryKind::{NativeStatic, NativeFramework, NativeUnknown};
InlinedItem::ImplItem(_, ref ii) => visitor.visit_impl_item(ii),
}
}
-
- pub fn visit_ids<O: IdVisitingOperation>(&self, operation: &mut O) {
- let mut id_visitor = IdVisitor::new(operation);
- self.visit(&mut id_visitor);
- }
}
// FIXME: find a better place for this?
impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
fn visit_fn(&mut self, fn_kind: FnKind<'v>, fn_decl: &'v hir::FnDecl,
- block: &'v hir::Block, span: Span, _: ast::NodeId) {
+ block: &'v hir::Block, span: Span, id: ast::NodeId) {
let (is_item_fn, is_unsafe_fn) = match fn_kind {
FnKind::ItemFn(_, _, unsafety, _, _, _, _) =>
self.unsafe_context = UnsafeContext::new(SafeContext)
}
- intravisit::walk_fn(self, fn_kind, fn_decl, block, span);
+ intravisit::walk_fn(self, fn_kind, fn_decl, block, span, id);
self.unsafe_context = old_unsafe_context
}
StartFnLangItem, "start", start_fn;
EhPersonalityLangItem, "eh_personality", eh_personality;
- EhPersonalityCatchLangItem, "eh_personality_catch", eh_personality_catch;
EhUnwindResumeLangItem, "eh_unwind_resume", eh_unwind_resume;
MSVCTryFilterLangItem, "msvc_try_filter", msvc_try_filter;
// gather up the various local variables, significant expressions,
// and so forth:
- intravisit::walk_fn(&mut fn_maps, fk, decl, body, sp);
+ intravisit::walk_fn(&mut fn_maps, fk, decl, body, sp, id);
// Special nodes and variables:
// - exit_ln represents the end of the fn, either by return or panic
FullDebugInfo,
}
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
pub enum OutputType {
Bitcode,
Assembly,
OutputType::DepInfo => "dep-info",
}
}
+
+ pub fn extension(&self) -> &'static str {
+ match *self {
+ OutputType::Bitcode => "bc",
+ OutputType::Assembly => "s",
+ OutputType::LlvmAssembly => "ll",
+ OutputType::Object => "o",
+ OutputType::DepInfo => "d",
+ OutputType::Exe => "",
+ }
+ }
}
#[derive(Clone)]
flavor: OutputType,
codegen_unit_name: Option<&str>)
-> PathBuf {
- let extension = match flavor {
- OutputType::Bitcode => "bc",
- OutputType::Assembly => "s",
- OutputType::LlvmAssembly => "ll",
- OutputType::Object => "o",
- OutputType::DepInfo => "d",
- OutputType::Exe => "",
- };
-
+ let extension = flavor.extension();
self.temp_path_ext(extension, codegen_unit_name)
}
// forms a unique global identifier for the crate. It is used to allow
// multiple crates with the same name to coexist. See the
// trans::back::symbol_names module for more information.
- pub crate_disambiguator: Cell<ast::Name>,
+ pub crate_disambiguator: RefCell<token::InternedString>,
pub features: RefCell<feature_gate::Features>,
/// The maximum recursion limit for potentially infinitely recursive
}
impl Session {
+ pub fn local_crate_disambiguator(&self) -> token::InternedString {
+ self.crate_disambiguator.borrow().clone()
+ }
pub fn struct_span_warn<'a, S: Into<MultiSpan>>(&'a self,
sp: S,
msg: &str)
sp: S,
msg: &str)
-> DiagnosticBuilder<'a> {
- match split_msg_into_multilines(msg) {
- Some(ref msg) => self.diagnostic().struct_span_err(sp, msg),
- None => self.diagnostic().struct_span_err(sp, msg),
- }
+ self.diagnostic().struct_span_err(sp, msg)
}
pub fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self,
sp: S,
msg: &str,
code: &str)
-> DiagnosticBuilder<'a> {
- match split_msg_into_multilines(msg) {
- Some(ref msg) => self.diagnostic().struct_span_err_with_code(sp, msg, code),
- None => self.diagnostic().struct_span_err_with_code(sp, msg, code),
- }
+ 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 span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
- match split_msg_into_multilines(msg) {
- Some(msg) => self.diagnostic().span_err(sp, &msg),
- None => self.diagnostic().span_err(sp, msg)
- }
+ self.diagnostic().span_err(sp, msg)
}
pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) {
- match split_msg_into_multilines(msg) {
- Some(msg) => self.diagnostic().span_err_with_code(sp, &msg, code),
- None => self.diagnostic().span_err_with_code(sp, msg, code)
- }
+ self.diagnostic().span_err_with_code(sp, &msg, code)
}
pub fn err(&self, msg: &str) {
self.diagnostic().err(msg)
}
}
-fn split_msg_into_multilines(msg: &str) -> Option<String> {
- // Conditions for enabling multi-line errors:
- if !msg.contains("mismatched types") &&
- !msg.contains("type mismatch resolving") &&
- !msg.contains("if and else have incompatible types") &&
- !msg.contains("if may be missing an else clause") &&
- !msg.contains("match arms have incompatible types") &&
- !msg.contains("structure constructor specifies a structure of type") &&
- !msg.contains("has an incompatible type for trait") {
- return None
- }
- let first = msg.match_indices("expected").filter(|s| {
- let last = msg[..s.0].chars().rev().next();
- last == Some(' ') || last == Some('(')
- }).map(|(a, b)| (a - 1, a + b.len()));
- let second = msg.match_indices("found").filter(|s| {
- msg[..s.0].chars().rev().next() == Some(' ')
- }).map(|(a, b)| (a - 1, a + b.len()));
-
- let mut new_msg = String::new();
- let mut head = 0;
-
- // Insert `\n` before expected and found.
- for (pos1, pos2) in first.zip(second) {
- new_msg = new_msg +
- // A `(` may be preceded by a space and it should be trimmed
- msg[head..pos1.0].trim_right() + // prefix
- "\n" + // insert before first
- &msg[pos1.0..pos1.1] + // insert what first matched
- &msg[pos1.1..pos2.0] + // between matches
- "\n " + // insert before second
- // 123
- // `expected` is 3 char longer than `found`. To align the types,
- // `found` gets 3 spaces prepended.
- &msg[pos2.0..pos2.1]; // insert what second matched
-
- head = pos2.1;
- }
-
- let mut tail = &msg[head..];
- let third = tail.find("(values differ")
- .or(tail.find("(lifetime"))
- .or(tail.find("(cyclic type of infinite size"));
- // Insert `\n` before any remaining messages which match.
- if let Some(pos) = third {
- // The end of the message may just be wrapped in `()` without
- // `expected`/`found`. Push this also to a new line and add the
- // final tail after.
- new_msg = new_msg +
- // `(` is usually preceded by a space and should be trimmed.
- tail[..pos].trim_right() + // prefix
- "\n" + // insert before paren
- &tail[pos..]; // append the tail
-
- tail = "";
- }
-
- new_msg.push_str(tail);
- return Some(new_msg);
-}
-
pub fn build_session(sopts: config::Options,
dep_graph: &DepGraph,
local_crate_source_file: Option<PathBuf>,
plugin_attributes: RefCell::new(Vec::new()),
crate_types: RefCell::new(Vec::new()),
dependency_formats: RefCell::new(FnvHashMap()),
- crate_disambiguator: Cell::new(token::intern("")),
+ crate_disambiguator: RefCell::new(token::intern("").as_str()),
features: RefCell::new(feature_gate::Features::new()),
recursion_limit: Cell::new(64),
next_node_id: Cell::new(1),
use fmt_macros::{Parser, Piece, Position};
use hir::def_id::DefId;
-use infer::{InferCtxt};
+use infer::{self, InferCtxt, TypeOrigin};
use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
+use ty::error::ExpectedFound;
use ty::fast_reject;
use ty::fold::TypeFolder;
use ty::subst::{self, Subst, TypeSpace};
let predicate =
self.resolve_type_vars_if_possible(&obligation.predicate);
- if !predicate.references_error() {
- if let Some(warning_node_id) = warning_node_id {
- self.tcx.sess.add_lint(
- ::lint::builtin::UNSIZED_IN_TUPLE,
- warning_node_id,
+ if predicate.references_error() {
+ return
+ }
+ if let Some(warning_node_id) = warning_node_id {
+ self.tcx.sess.add_lint(
+ ::lint::builtin::UNSIZED_IN_TUPLE,
+ warning_node_id,
+ obligation.cause.span,
+ format!("type mismatch resolving `{}`: {}",
+ predicate,
+ error.err));
+ return
+ }
+ self.probe(|_| {
+ let origin = TypeOrigin::Misc(obligation.cause.span);
+ let err_buf;
+ let mut err = &error.err;
+ let mut values = None;
+
+ // try to find the mismatched types to report the error with.
+ //
+ // this can fail if the problem was higher-ranked, in which
+ // cause I have no idea for a good error message.
+ if let ty::Predicate::Projection(ref data) = predicate {
+ let mut selcx = SelectionContext::new(self);
+ let (data, _) = self.replace_late_bound_regions_with_fresh_var(
obligation.cause.span,
- format!("type mismatch resolving `{}`: {}",
- predicate,
- error.err));
- } else {
- let mut err = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271,
- "type mismatch resolving `{}`: {}",
- predicate,
- error.err);
- self.note_obligation_cause(&mut err, obligation);
- err.emit();
+ infer::LateBoundRegionConversionTime::HigherRankedType,
+ data);
+ let normalized = super::normalize_projection_type(
+ &mut selcx,
+ data.projection_ty,
+ obligation.cause.clone(),
+ 0
+ );
+ let origin = TypeOrigin::Misc(obligation.cause.span);
+ if let Err(error) = self.eq_types(
+ false, origin,
+ data.ty, normalized.value
+ ) {
+ values = Some(infer::ValuePairs::Types(ExpectedFound {
+ expected: normalized.value,
+ found: data.ty,
+ }));
+ err_buf = error;
+ err = &err_buf;
+ }
}
- }
+
+ let mut diag = struct_span_err!(
+ self.tcx.sess, origin.span(), E0271,
+ "type mismatch resolving `{}`", predicate
+ );
+ self.note_type_err(&mut diag, origin, values, err);
+ self.note_obligation_cause(&mut diag, obligation);
+ diag.emit();
+ });
}
fn impl_substs(&self,
pub fn crate_disambiguator(self, cnum: ast::CrateNum) -> token::InternedString {
if cnum == LOCAL_CRATE {
- self.sess.crate_disambiguator.get().as_str()
+ self.sess.local_crate_disambiguator()
} else {
self.sess.cstore.crate_disambiguator(cnum)
}
self.generics.visit_with(visitor) || self.ty.visit_with(visitor)
}
}
+
+impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::error::ExpectedFound<T> {
+ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+ ty::error::ExpectedFound {
+ expected: self.expected.fold_with(folder),
+ found: self.found.fold_with(folder),
+ }
+ }
+
+ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+ self.expected.visit_with(visitor) || self.found.visit_with(visitor)
+ }
+}
use std::path::{self, Path, PathBuf};
use std::ffi::OsString;
+use std::fs;
+use std::io;
// Unfortunately, on windows, it looks like msvcrt.dll is silently translating
// verbatim paths under the hood to non-verbatim paths! This manifests itself as
_ => p.to_path_buf(),
}
}
+
+/// Copy `p` into `q`, preferring to use hard-linking if possible. If
+/// `q` already exists, it is removed first.
+pub fn link_or_copy<P: AsRef<Path>, Q: AsRef<Path>>(p: P, q: Q) -> io::Result<()> {
+ let p = p.as_ref();
+ let q = q.as_ref();
+ if q.exists() {
+ try!(fs::remove_file(&q));
+ }
+ fs::hard_link(p, q)
+ .or_else(|_| fs::copy(p, q).map(|_| ()))
+}
ty::TyVar(ref vid) if print_var_ids => write!(f, "{:?}", vid),
ty::IntVar(ref vid) if print_var_ids => write!(f, "{:?}", vid),
ty::FloatVar(ref vid) if print_var_ids => write!(f, "{:?}", vid),
- ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => write!(f, "_"),
+ ty::TyVar(_) => write!(f, "_"),
+ ty::IntVar(_) => write!(f, "{}", "{integer}"),
+ ty::FloatVar(_) => write!(f, "{}", "{float}"),
ty::FreshTy(v) => write!(f, "FreshTy({})", v),
ty::FreshIntTy(v) => write!(f, "FreshIntTy({})", v),
ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({})", v)
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::{Target, TargetOptions};
+use target::{Target, TargetOptions, TargetResult};
use super::apple_ios_base::{opts, Arch};
-pub fn target() -> Target {
- Target {
+pub fn target() -> TargetResult {
+ let base = try!(opts(Arch::Arm64));
+ Ok(Target {
llvm_target: "arm64-apple-ios".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "64".to_string(),
features: "+neon,+fp-armv8,+cyclone".to_string(),
eliminate_frame_pointer: false,
max_atomic_width: 128,
- .. opts(Arch::Arm64)
+ .. base
},
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::Target;
+use target::{Target, TargetResult};
-pub fn target() -> Target {
+pub fn target() -> TargetResult {
let mut base = super::android_base::opts();
base.max_atomic_width = 128;
// As documented in http://developer.android.com/ndk/guides/cpu-features.html
// the neon (ASIMD) and FP must exist on all android aarch64 targets.
base.features = "+neon,+fp-armv8".to_string();
- Target {
+ Ok(Target {
llvm_target: "aarch64-linux-android".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "64".to_string(),
target_env: "".to_string(),
target_vendor: "unknown".to_string(),
options: base,
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::Target;
+use target::{Target, TargetResult};
-pub fn target() -> Target {
+pub fn target() -> TargetResult {
let mut base = super::linux_base::opts();
base.max_atomic_width = 128;
- Target {
+ Ok(Target {
llvm_target: "aarch64-unknown-linux-gnu".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "64".to_string(),
target_os: "linux".to_string(),
target_vendor: "unknown".to_string(),
options: base,
- }
+ })
}
}
}
-pub fn get_sdk_root(sdk_name: &str) -> String {
+pub fn get_sdk_root(sdk_name: &str) -> Result<String, String> {
let res = Command::new("xcrun")
.arg("--show-sdk-path")
.arg("-sdk")
});
match res {
- Ok(output) => output.trim().to_string(),
- Err(e) => panic!("failed to get {} SDK path: {}", sdk_name, e)
+ Ok(output) => Ok(output.trim().to_string()),
+ Err(e) => Err(format!("failed to get {} SDK path: {}", sdk_name, e))
}
}
-fn pre_link_args(arch: Arch) -> Vec<String> {
+fn build_pre_link_args(arch: Arch) -> Result<Vec<String>, String> {
let sdk_name = match arch {
Armv7 | Armv7s | Arm64 => "iphoneos",
I386 | X86_64 => "iphonesimulator"
let arch_name = arch.to_string();
- vec!["-arch".to_string(), arch_name.to_string(),
- "-Wl,-syslibroot".to_string(), get_sdk_root(sdk_name)]
+ let sdk_root = try!(get_sdk_root(sdk_name));
+
+ Ok(vec!["-arch".to_string(), arch_name.to_string(),
+ "-Wl,-syslibroot".to_string(), sdk_root])
}
fn target_cpu(arch: Arch) -> String {
}.to_string()
}
-pub fn opts(arch: Arch) -> TargetOptions {
- TargetOptions {
+pub fn opts(arch: Arch) -> Result<TargetOptions, String> {
+ let pre_link_args = try!(build_pre_link_args(arch));
+ Ok(TargetOptions {
cpu: target_cpu(arch),
dynamic_linking: false,
executables: true,
- pre_link_args: pre_link_args(arch),
+ pre_link_args: pre_link_args,
has_elf_tls: false,
.. super::apple_base::opts()
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::Target;
+use target::{Target, TargetResult};
-pub fn target() -> Target {
+pub fn target() -> TargetResult {
let mut base = super::android_base::opts();
base.features = "+v7,+vfp3,+d16".to_string();
base.max_atomic_width = 64;
- Target {
+ Ok(Target {
llvm_target: "arm-linux-androideabi".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "32".to_string(),
target_env: "".to_string(),
target_vendor: "unknown".to_string(),
options: base,
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::{Target, TargetOptions};
+use target::{Target, TargetOptions, TargetResult};
-pub fn target() -> Target {
+pub fn target() -> TargetResult {
let mut base = super::linux_base::opts();
base.max_atomic_width = 64;
- Target {
+ Ok(Target {
llvm_target: "arm-unknown-linux-gnueabi".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "32".to_string(),
features: "+v6".to_string(),
.. base
},
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::{Target, TargetOptions};
+use target::{Target, TargetOptions, TargetResult};
-pub fn target() -> Target {
+pub fn target() -> TargetResult {
let mut base = super::linux_base::opts();
base.max_atomic_width = 64;
- Target {
+ Ok(Target {
llvm_target: "arm-unknown-linux-gnueabihf".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "32".to_string(),
features: "+v6,+vfp2".to_string(),
.. base
}
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::{Target, TargetOptions};
+use target::{Target, TargetOptions, TargetResult};
use super::apple_ios_base::{opts, Arch};
-pub fn target() -> Target {
- Target {
+pub fn target() -> TargetResult {
+ let base = try!(opts(Arch::Armv7));
+ Ok(Target {
llvm_target: "armv7-apple-ios".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "32".to_string(),
options: TargetOptions {
features: "+v7,+vfp3,+neon".to_string(),
max_atomic_width: 64,
- .. opts(Arch::Armv7)
+ .. base
}
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::Target;
+use target::{Target, TargetResult};
-pub fn target() -> Target {
+pub fn target() -> TargetResult {
let mut base = super::android_base::opts();
base.features = "+v7,+thumb2,+vfp3,+d16".to_string();
base.max_atomic_width = 64;
- Target {
+ Ok(Target {
llvm_target: "armv7-none-linux-android".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "32".to_string(),
target_env: "".to_string(),
target_vendor: "unknown".to_string(),
options: base,
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::{Target, TargetOptions};
+use target::{Target, TargetOptions, TargetResult};
-pub fn target() -> Target {
+pub fn target() -> TargetResult {
let base = super::linux_base::opts();
- Target {
+ Ok(Target {
llvm_target: "armv7-unknown-linux-gnueabihf".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "32".to_string(),
max_atomic_width: 64,
.. base
}
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::{Target, TargetOptions};
+use target::{Target, TargetOptions, TargetResult};
use super::apple_ios_base::{opts, Arch};
-pub fn target() -> Target {
- Target {
+pub fn target() -> TargetResult {
+ let base = try!(opts(Arch::Armv7s));
+ Ok(Target {
llvm_target: "armv7s-apple-ios".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "32".to_string(),
options: TargetOptions {
features: "+v7,+vfp4,+neon".to_string(),
max_atomic_width: 64,
- .. opts(Arch::Armv7s)
+ .. base
}
- }
+ })
}
use super::{Target, TargetOptions};
-pub fn target() -> Target {
+pub fn target() -> Result<Target, String> {
let opts = TargetOptions {
linker: "emcc".to_string(),
ar: "emar".to_string(),
max_atomic_width: 32,
.. Default::default()
};
- Target {
+ Ok(Target {
llvm_target: "asmjs-unknown-emscripten".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "32".to_string(),
data_layout: "e-p:32:32-i64:64-v128:32:128-n32-S128".to_string(),
arch: "asmjs".to_string(),
options: opts,
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::{Target, TargetOptions};
+use target::{Target, TargetOptions, TargetResult};
use super::apple_ios_base::{opts, Arch};
-pub fn target() -> Target {
- Target {
+pub fn target() -> TargetResult {
+ let base = try!(opts(Arch::I386));
+ Ok(Target {
llvm_target: "i386-apple-ios".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "32".to_string(),
target_vendor: "apple".to_string(),
options: TargetOptions {
max_atomic_width: 64,
- .. opts(Arch::I386)
+ .. base
}
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::Target;
+use target::TargetResult;
-pub fn target() -> Target {
- let mut base = super::i686_pc_windows_msvc::target();
+pub fn target() -> TargetResult {
+ let mut base = try!(super::i686_pc_windows_msvc::target());
base.options.cpu = "pentium".to_string();
base.llvm_target = "i586-pc-windows-msvc".to_string();
- return base
+ Ok(base)
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::Target;
+use target::TargetResult;
-pub fn target() -> Target {
- let mut base = super::i686_unknown_linux_gnu::target();
+pub fn target() -> TargetResult {
+ let mut base = try!(super::i686_unknown_linux_gnu::target());
base.options.cpu = "pentium".to_string();
base.llvm_target = "i586-unknown-linux-gnu".to_string();
- return base
+ Ok(base)
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::Target;
+use target::{Target, TargetResult};
-pub fn target() -> Target {
+pub fn target() -> TargetResult {
let mut base = super::apple_base::opts();
base.cpu = "yonah".to_string();
base.max_atomic_width = 64;
base.pre_link_args.push("-m32".to_string());
- Target {
+ Ok(Target {
llvm_target: "i686-apple-darwin".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "32".to_string(),
target_env: "".to_string(),
target_vendor: "apple".to_string(),
options: base,
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::Target;
+use target::{Target, TargetResult};
-pub fn target() -> Target {
+pub fn target() -> TargetResult {
let mut base = super::android_base::opts();
base.max_atomic_width = 64;
base.cpu = "pentiumpro".to_string();
base.features = "+mmx,+sse,+sse2,+sse3,+ssse3".to_string();
- Target {
+ Ok(Target {
llvm_target: "i686-linux-android".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "32".to_string(),
target_env: "".to_string(),
target_vendor: "unknown".to_string(),
options: base,
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::Target;
+use target::{Target, TargetResult};
-pub fn target() -> Target {
+pub fn target() -> TargetResult {
let mut base = super::windows_base::opts();
base.cpu = "pentium4".to_string();
base.max_atomic_width = 64;
// space available to x86 Windows binaries on x86_64.
base.pre_link_args.push("-Wl,--large-address-aware".to_string());
- Target {
+ Ok(Target {
llvm_target: "i686-pc-windows-gnu".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "32".to_string(),
target_env: "gnu".to_string(),
target_vendor: "pc".to_string(),
options: base,
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::Target;
+use target::{Target, TargetResult};
-pub fn target() -> Target {
+pub fn target() -> TargetResult {
let mut base = super::windows_msvc_base::opts();
base.cpu = "pentium4".to_string();
base.max_atomic_width = 64;
// https://msdn.microsoft.com/en-us/library/9a89h429.aspx
base.pre_link_args.push("/SAFESEH".to_string());
- Target {
+ Ok(Target {
llvm_target: "i686-pc-windows-msvc".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "32".to_string(),
target_env: "msvc".to_string(),
target_vendor: "pc".to_string(),
options: base,
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::Target;
+use target::{Target, TargetResult};
-pub fn target() -> Target {
+pub fn target() -> TargetResult {
let mut base = super::dragonfly_base::opts();
base.cpu = "pentium4".to_string();
base.max_atomic_width = 64;
base.pre_link_args.push("-m32".to_string());
- Target {
+ Ok(Target {
llvm_target: "i686-unknown-dragonfly".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "32".to_string(),
target_env: "".to_string(),
target_vendor: "unknown".to_string(),
options: base,
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::Target;
+use target::{Target, TargetResult};
-pub fn target() -> Target {
+pub fn target() -> TargetResult {
let mut base = super::freebsd_base::opts();
base.cpu = "pentium4".to_string();
base.max_atomic_width = 64;
base.pre_link_args.push("-m32".to_string());
- Target {
+ Ok(Target {
llvm_target: "i686-unknown-freebsd".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "32".to_string(),
target_env: "".to_string(),
target_vendor: "unknown".to_string(),
options: base,
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::Target;
+use target::{Target, TargetResult};
-pub fn target() -> Target {
+pub fn target() -> TargetResult {
let mut base = super::linux_base::opts();
base.cpu = "pentium4".to_string();
base.max_atomic_width = 64;
base.pre_link_args.push("-m32".to_string());
- Target {
+ Ok(Target {
llvm_target: "i686-unknown-linux-gnu".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "32".to_string(),
target_env: "gnu".to_string(),
target_vendor: "unknown".to_string(),
options: base,
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::Target;
+use target::{Target, TargetResult};
-pub fn target() -> Target {
+pub fn target() -> TargetResult {
let mut base = super::linux_musl_base::opts();
base.cpu = "pentium4".to_string();
base.max_atomic_width = 64;
base.pre_link_args.push("-m32".to_string());
base.pre_link_args.push("-Wl,-melf_i386".to_string());
- Target {
+ Ok(Target {
llvm_target: "i686-unknown-linux-musl".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "32".to_string(),
target_env: "musl".to_string(),
target_vendor: "unknown".to_string(),
options: base,
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use super::{Target, TargetOptions};
+use super::{Target, TargetOptions, TargetResult};
-pub fn target() -> Target {
+pub fn target() -> TargetResult {
let opts = TargetOptions {
linker: "pnacl-clang".to_string(),
ar: "pnacl-ar".to_string(),
max_atomic_width: 32,
.. Default::default()
};
- Target {
+ Ok(Target {
llvm_target: "le32-unknown-nacl".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "32".to_string(),
data_layout: "e-i64:64:64-p:32:32:32-v128:32:32".to_string(),
arch: "le32".to_string(),
options: opts,
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::{Target, TargetOptions};
+use target::{Target, TargetOptions, TargetResult};
-pub fn target() -> Target {
- Target {
+pub fn target() -> TargetResult {
+ Ok(Target {
llvm_target: "mips-unknown-linux-gnu".to_string(),
target_endian: "big".to_string(),
target_pointer_width: "32".to_string(),
max_atomic_width: 32,
..super::linux_base::opts()
},
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::{Target, TargetOptions};
+use target::{Target, TargetOptions, TargetResult};
-pub fn target() -> Target {
- Target {
+pub fn target() -> TargetResult {
+ Ok(Target {
llvm_target: "mips-unknown-linux-musl".to_string(),
target_endian: "big".to_string(),
target_pointer_width: "32".to_string(),
max_atomic_width: 32,
..super::linux_base::opts()
}
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::{Target, TargetOptions};
+use target::{Target, TargetOptions, TargetResult};
-pub fn target() -> Target {
- Target {
+pub fn target() -> TargetResult {
+ Ok(Target {
llvm_target: "mipsel-unknown-linux-gnu".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "32".to_string(),
max_atomic_width: 32,
..super::linux_base::opts()
},
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::{Target, TargetOptions};
+use target::{Target, TargetOptions, TargetResult};
-pub fn target() -> Target {
- Target {
+pub fn target() -> TargetResult {
+ Ok(Target {
llvm_target: "mipsel-unknown-linux-musl".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "32".to_string(),
target_vendor: "unknown".to_string(),
options: TargetOptions {
cpu: "mips32".to_string(),
- features: "+mips32".to_string(),
+ features: "+mips32,+soft-float".to_string(),
max_atomic_width: 32,
..super::linux_base::opts()
}
- }
+ })
}
//! the target's settings, though `target-feature` and `link-args` will *add*
//! to the list specified by the target, rather than replace.
-use serialize::json::Json;
+use serialize::json::{Json, ToJson};
+use std::collections::BTreeMap;
use std::default::Default;
use std::io::prelude::*;
use syntax::abi::Abi;
mod windows_base;
mod windows_msvc_base;
+pub type TargetResult = Result<Target, String>;
+
macro_rules! supported_targets {
( $(($triple:expr, $module:ident)),+ ) => (
$(mod $module;)*
/// List of supported targets
- pub const TARGETS: &'static [&'static str] = &[$($triple),*];
+ const TARGETS: &'static [&'static str] = &[$($triple),*];
+
+ fn load_specific(target: &str) -> TargetResult {
+ match target {
+ $(
+ $triple => {
+ let mut t = try!($module::target());
+ t.options.is_builtin = true;
+
+ // round-trip through the JSON parser to ensure at
+ // run-time that the parser works correctly
+ t = try!(Target::from_json(t.to_json()));
+ debug!("Got builtin target: {:?}", t);
+ Ok(t)
+ },
+ )+
+ _ => Err(format!("Unable to find target: {}", target))
+ }
+ }
+
+ pub fn get_targets() -> Box<Iterator<Item=String>> {
+ Box::new(TARGETS.iter().filter_map(|t| -> Option<String> {
+ load_specific(t)
+ .map(|t| t.llvm_target)
+ .ok()
+ }))
+ }
+
+ #[cfg(test)]
+ mod test_json_encode_decode {
+ use serialize::json::ToJson;
+ use super::Target;
+ $(use super::$module;)*
- // this would use a match if stringify! were allowed in pattern position
- fn load_specific(target: &str) -> Option<Target> {
- let target = target.replace("-", "_");
- if false { }
$(
- else if target == stringify!($module) {
- let mut t = $module::target();
- t.options.is_builtin = true;
- debug!("Got builtin target: {:?}", t);
- return Some(t);
+ #[test]
+ fn $module() {
+ // Grab the TargetResult struct. If we successfully retrieved
+ // a Target, then the test JSON encoding/decoding can run for this
+ // Target on this testing platform (i.e., checking the iOS targets
+ // only on a Mac test platform).
+ let _ = $module::target().map(|original| {
+ let as_json = original.to_json();
+ let parsed = Target::from_json(as_json).unwrap();
+ assert_eq!(original, parsed);
+ });
}
)*
-
- None
}
)
}
/// Everything `rustc` knows about how to compile for a specific target.
///
/// Every field here must be specified, and has no default value.
-#[derive(Clone, Debug)]
+#[derive(PartialEq, Clone, Debug)]
pub struct Target {
/// Target triple to pass to LLVM.
pub llvm_target: String,
///
/// This has an implementation of `Default`, see each field for what the default is. In general,
/// these try to take "minimal defaults" that don't assume anything about the runtime they run in.
-#[derive(Clone, Debug)]
+#[derive(PartialEq, Clone, Debug)]
pub struct TargetOptions {
/// Whether the target is built-in or loaded from a custom target specification.
pub is_builtin: bool,
}
/// Load a target descriptor from a JSON object.
- pub fn from_json(obj: Json) -> Target {
- // this is 1. ugly, 2. error prone.
+ pub fn from_json(obj: Json) -> TargetResult {
+ // While ugly, this code must remain this way to retain
+ // compatibility with existing JSON fields and the internal
+ // expected naming of the Target and TargetOptions structs.
+ // To ensure compatibility is retained, the built-in targets
+ // are round-tripped through this code to catch cases where
+ // the JSON parser is not updated to match the structs.
let get_req_field = |name: &str| {
match obj.find(name)
.map(|s| s.as_string())
.and_then(|os| os.map(|s| s.to_string())) {
- Some(val) => val,
+ Some(val) => Ok(val),
None => {
- panic!("Field {} in target specification is required", name)
+ return Err(format!("Field {} in target specification is required", name))
}
}
};
};
let mut base = Target {
- llvm_target: get_req_field("llvm-target"),
- target_endian: get_req_field("target-endian"),
- target_pointer_width: get_req_field("target-pointer-width"),
- data_layout: get_req_field("data-layout"),
- arch: get_req_field("arch"),
- target_os: get_req_field("os"),
+ llvm_target: try!(get_req_field("llvm-target")),
+ target_endian: try!(get_req_field("target-endian")),
+ target_pointer_width: try!(get_req_field("target-pointer-width")),
+ data_layout: try!(get_req_field("data-layout")),
+ arch: try!(get_req_field("arch")),
+ target_os: try!(get_req_field("os")),
target_env: get_opt_field("env", ""),
target_vendor: get_opt_field("vendor", "unknown"),
options: Default::default(),
} );
}
- key!(cpu);
- key!(ar);
+ key!(is_builtin, bool);
key!(linker);
+ key!(ar);
+ key!(pre_link_args, list);
+ key!(pre_link_objects_exe, list);
+ key!(pre_link_objects_dll, list);
+ key!(late_link_args, list);
+ key!(post_link_objects, list);
+ key!(post_link_args, list);
+ key!(cpu);
+ key!(features);
+ key!(dynamic_linking, bool);
+ key!(executables, bool);
key!(relocation_model);
key!(code_model);
+ key!(disable_redzone, bool);
+ key!(eliminate_frame_pointer, bool);
+ key!(function_sections, bool);
key!(dll_prefix);
key!(dll_suffix);
key!(exe_suffix);
key!(staticlib_prefix);
key!(staticlib_suffix);
- key!(features);
- key!(dynamic_linking, bool);
- key!(executables, bool);
- key!(disable_redzone, bool);
- key!(eliminate_frame_pointer, bool);
- key!(function_sections, bool);
key!(target_family, optional);
key!(is_like_osx, bool);
+ key!(is_like_solaris, bool);
key!(is_like_windows, bool);
key!(is_like_msvc, bool);
+ key!(is_like_android, bool);
key!(linker_is_gnu, bool);
key!(has_rpath, bool);
key!(no_compiler_rt, bool);
key!(no_default_libraries, bool);
- key!(pre_link_args, list);
- key!(post_link_args, list);
+ key!(position_independent_executables, bool);
key!(archive_format);
key!(allow_asm, bool);
key!(custom_unwind_resume, bool);
+ key!(lib_allocation_crate);
+ key!(exe_allocation_crate);
+ key!(has_elf_tls, bool);
+ key!(obj_is_bitcode, bool);
key!(max_atomic_width, u64);
- base
+ Ok(base)
}
/// Search RUST_TARGET_PATH for a JSON file specifying the given target
f.read_to_end(&mut contents).map_err(|e| e.to_string())?;
let obj = json::from_reader(&mut &contents[..])
.map_err(|e| e.to_string())?;
- Ok(Target::from_json(obj))
+ Target::from_json(obj)
}
- if let Some(t) = load_specific(target) {
+ if let Ok(t) = load_specific(target) {
return Ok(t)
}
}
}
+impl ToJson for Target {
+ fn to_json(&self) -> Json {
+ let mut d = BTreeMap::new();
+ let default: TargetOptions = Default::default();
+
+ macro_rules! target_val {
+ ($attr:ident) => ( {
+ let name = (stringify!($attr)).replace("_", "-");
+ d.insert(name.to_string(), self.$attr.to_json());
+ } );
+ ($attr:ident, $key_name:expr) => ( {
+ let name = $key_name;
+ d.insert(name.to_string(), self.$attr.to_json());
+ } );
+ }
+
+ macro_rules! target_option_val {
+ ($attr:ident) => ( {
+ let name = (stringify!($attr)).replace("_", "-");
+ if default.$attr != self.options.$attr {
+ d.insert(name.to_string(), self.options.$attr.to_json());
+ }
+ } );
+ ($attr:ident, $key_name:expr) => ( {
+ let name = $key_name;
+ if default.$attr != self.options.$attr {
+ d.insert(name.to_string(), self.options.$attr.to_json());
+ }
+ } );
+ }
+
+ target_val!(llvm_target);
+ target_val!(target_endian);
+ target_val!(target_pointer_width);
+ target_val!(arch);
+ target_val!(target_os, "os");
+ target_val!(target_env, "env");
+ target_val!(target_vendor, "vendor");
+ target_val!(arch);
+ target_val!(data_layout);
+
+ target_option_val!(is_builtin);
+ target_option_val!(linker);
+ target_option_val!(ar);
+ target_option_val!(pre_link_args);
+ target_option_val!(pre_link_objects_exe);
+ target_option_val!(pre_link_objects_dll);
+ target_option_val!(late_link_args);
+ target_option_val!(post_link_objects);
+ target_option_val!(post_link_args);
+ target_option_val!(cpu);
+ target_option_val!(features);
+ target_option_val!(dynamic_linking);
+ target_option_val!(executables);
+ target_option_val!(relocation_model);
+ target_option_val!(code_model);
+ target_option_val!(disable_redzone);
+ target_option_val!(eliminate_frame_pointer);
+ target_option_val!(function_sections);
+ target_option_val!(dll_prefix);
+ target_option_val!(dll_suffix);
+ target_option_val!(exe_suffix);
+ target_option_val!(staticlib_prefix);
+ target_option_val!(staticlib_suffix);
+ target_option_val!(target_family);
+ target_option_val!(is_like_osx);
+ target_option_val!(is_like_solaris);
+ target_option_val!(is_like_windows);
+ target_option_val!(is_like_msvc);
+ target_option_val!(is_like_android);
+ target_option_val!(linker_is_gnu);
+ target_option_val!(has_rpath);
+ target_option_val!(no_compiler_rt);
+ target_option_val!(no_default_libraries);
+ target_option_val!(position_independent_executables);
+ target_option_val!(archive_format);
+ target_option_val!(allow_asm);
+ target_option_val!(custom_unwind_resume);
+ target_option_val!(lib_allocation_crate);
+ target_option_val!(exe_allocation_crate);
+ target_option_val!(has_elf_tls);
+ target_option_val!(obj_is_bitcode);
+ target_option_val!(max_atomic_width);
+
+ Json::Object(d)
+ }
+}
+
fn maybe_jemalloc() -> String {
if cfg!(feature = "jemalloc") {
"alloc_jemalloc".to_string()
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::Target;
+use target::{Target, TargetResult};
-pub fn target() -> Target {
+pub fn target() -> TargetResult {
let mut base = super::linux_base::opts();
base.cpu = "ppc64".to_string();
base.pre_link_args.push("-m64".to_string());
base.max_atomic_width = 64;
- Target {
+ Ok(Target {
llvm_target: "powerpc64-unknown-linux-gnu".to_string(),
target_endian: "big".to_string(),
target_pointer_width: "64".to_string(),
target_env: "gnu".to_string(),
target_vendor: "unknown".to_string(),
options: base,
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::Target;
+use target::{Target, TargetResult};
-pub fn target() -> Target {
+pub fn target() -> TargetResult {
let mut base = super::linux_base::opts();
base.cpu = "ppc64le".to_string();
base.pre_link_args.push("-m64".to_string());
base.max_atomic_width = 64;
- Target {
+ Ok(Target {
llvm_target: "powerpc64le-unknown-linux-gnu".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "64".to_string(),
target_env: "gnu".to_string(),
target_vendor: "unknown".to_string(),
options: base,
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::Target;
+use target::{Target, TargetResult};
-pub fn target() -> Target {
+pub fn target() -> TargetResult {
let mut base = super::linux_base::opts();
base.pre_link_args.push("-m32".to_string());
base.max_atomic_width = 32;
- Target {
+ Ok(Target {
llvm_target: "powerpc-unknown-linux-gnu".to_string(),
target_endian: "big".to_string(),
target_pointer_width: "32".to_string(),
target_env: "gnu".to_string(),
target_vendor: "unknown".to_string(),
options: base,
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::Target;
+use target::{Target, TargetResult};
-pub fn target() -> Target {
+pub fn target() -> TargetResult {
let mut base = super::apple_base::opts();
base.cpu = "core2".to_string();
base.max_atomic_width = 128; // core2 support cmpxchg16b
base.eliminate_frame_pointer = false;
base.pre_link_args.push("-m64".to_string());
- Target {
+ Ok(Target {
llvm_target: "x86_64-apple-darwin".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "64".to_string(),
target_env: "".to_string(),
target_vendor: "apple".to_string(),
options: base,
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::{Target, TargetOptions};
+use target::{Target, TargetOptions, TargetResult};
use super::apple_ios_base::{opts, Arch};
-pub fn target() -> Target {
- Target {
+pub fn target() -> TargetResult {
+ let base = try!(opts(Arch::X86_64));
+ Ok(Target {
llvm_target: "x86_64-apple-ios".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "64".to_string(),
target_vendor: "apple".to_string(),
options: TargetOptions {
max_atomic_width: 64,
- .. opts(Arch::X86_64)
+ .. base
}
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::Target;
+use target::{Target, TargetResult};
-pub fn target() -> Target {
+pub fn target() -> TargetResult {
let mut base = super::windows_base::opts();
base.cpu = "x86-64".to_string();
base.pre_link_args.push("-m64".to_string());
base.max_atomic_width = 64;
- Target {
+ Ok(Target {
llvm_target: "x86_64-pc-windows-gnu".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "64".to_string(),
target_env: "gnu".to_string(),
target_vendor: "pc".to_string(),
options: base,
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::Target;
+use target::{Target, TargetResult};
-pub fn target() -> Target {
+pub fn target() -> TargetResult {
let mut base = super::windows_msvc_base::opts();
base.cpu = "x86-64".to_string();
base.max_atomic_width = 64;
- Target {
+ Ok(Target {
llvm_target: "x86_64-pc-windows-msvc".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "64".to_string(),
target_env: "msvc".to_string(),
target_vendor: "pc".to_string(),
options: base,
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::Target;
+use target::{Target, TargetResult};
-pub fn target() -> Target {
+pub fn target() -> TargetResult {
let mut base = super::netbsd_base::opts();
base.pre_link_args.push("-m64".to_string());
base.linker = "x86_64-rumprun-netbsd-gcc".to_string();
base.no_default_libraries = false;
base.exe_allocation_crate = "alloc_system".to_string();
- Target {
+ Ok(Target {
llvm_target: "x86_64-rumprun-netbsd".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "64".to_string(),
target_env: "".to_string(),
target_vendor: "rumprun".to_string(),
options: base,
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::Target;
+use target::{Target, TargetResult};
-pub fn target() -> Target {
+pub fn target() -> TargetResult {
let mut base = super::solaris_base::opts();
base.pre_link_args.push("-m64".to_string());
base.cpu = "x86-64".to_string();
base.max_atomic_width = 64;
- Target {
+ Ok(Target {
llvm_target: "x86_64-pc-solaris".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "64".to_string(),
target_env: "".to_string(),
target_vendor: "sun".to_string(),
options: base,
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::Target;
+use target::{Target, TargetResult};
-pub fn target() -> Target {
+pub fn target() -> TargetResult {
let mut base = super::bitrig_base::opts();
base.max_atomic_width = 64;
base.pre_link_args.push("-m64".to_string());
- Target {
+ Ok(Target {
llvm_target: "x86_64-unknown-bitrig".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "64".to_string(),
target_env: "".to_string(),
target_vendor: "unknown".to_string(),
options: base,
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::Target;
+use target::{Target, TargetResult};
-pub fn target() -> Target {
+pub fn target() -> TargetResult {
let mut base = super::dragonfly_base::opts();
base.cpu = "x86-64".to_string();
base.max_atomic_width = 64;
base.pre_link_args.push("-m64".to_string());
- Target {
+ Ok(Target {
llvm_target: "x86_64-unknown-dragonfly".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "64".to_string(),
target_env: "".to_string(),
target_vendor: "unknown".to_string(),
options: base,
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::Target;
+use target::{Target, TargetResult};
-pub fn target() -> Target {
+pub fn target() -> TargetResult {
let mut base = super::freebsd_base::opts();
base.cpu = "x86-64".to_string();
base.max_atomic_width = 64;
base.pre_link_args.push("-m64".to_string());
- Target {
+ Ok(Target {
llvm_target: "x86_64-unknown-freebsd".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "64".to_string(),
target_env: "".to_string(),
target_vendor: "unknown".to_string(),
options: base,
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::Target;
+use target::{Target, TargetResult};
-pub fn target() -> Target {
+pub fn target() -> TargetResult {
let mut base = super::linux_base::opts();
base.cpu = "x86-64".to_string();
base.max_atomic_width = 64;
base.pre_link_args.push("-m64".to_string());
- Target {
+ Ok(Target {
llvm_target: "x86_64-unknown-linux-gnu".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "64".to_string(),
target_env: "gnu".to_string(),
target_vendor: "unknown".to_string(),
options: base,
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::Target;
+use target::{Target, TargetResult};
-pub fn target() -> Target {
+pub fn target() -> TargetResult {
let mut base = super::linux_musl_base::opts();
base.cpu = "x86-64".to_string();
base.max_atomic_width = 64;
base.pre_link_args.push("-m64".to_string());
- Target {
+ Ok(Target {
llvm_target: "x86_64-unknown-linux-musl".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "64".to_string(),
target_env: "musl".to_string(),
target_vendor: "unknown".to_string(),
options: base,
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::Target;
+use target::{Target, TargetResult};
-pub fn target() -> Target {
+pub fn target() -> TargetResult {
let mut base = super::netbsd_base::opts();
base.max_atomic_width = 64;
base.pre_link_args.push("-m64".to_string());
- Target {
+ Ok(Target {
llvm_target: "x86_64-unknown-netbsd".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "64".to_string(),
target_env: "".to_string(),
target_vendor: "unknown".to_string(),
options: base,
- }
+ })
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use target::Target;
+use target::{Target, TargetResult};
-pub fn target() -> Target {
+pub fn target() -> TargetResult {
let mut base = super::openbsd_base::opts();
base.cpu = "x86-64".to_string();
base.max_atomic_width = 64;
base.pre_link_args.push("-m64".to_string());
- Target {
+ Ok(Target {
llvm_target: "x86_64-unknown-openbsd".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "64".to_string(),
target_env: "".to_string(),
target_vendor: "unknown".to_string(),
options: base,
- }
+ })
}
decl,
body);
- intravisit::walk_fn(this, fk, decl, body, sp);
+ intravisit::walk_fn(this, fk, decl, body, sp, id);
}
fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
rustc = { path = "../librustc" }
rustc_back = { path = "../librustc_back" }
rustc_const_math = { path = "../librustc_const_math" }
+rustc_errors = { path = "../librustc_errors" }
syntax = { path = "../libsyntax" }
graphviz = { path = "../libgraphviz" }
syntax_pos = { path = "../libsyntax_pos" }
\ No newline at end of file
use ::{eval_const_expr, eval_const_expr_partial, compare_const_vals};
use ::{const_expr_to_pat, lookup_const_by_id};
use ::EvalHint::ExprTypeChecked;
+use eval::report_const_eval_err;
use rustc::hir::def::*;
use rustc::hir::def_id::{DefId};
use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor};
use rustc::hir;
use rustc::hir::{Pat, PatKind};
-use rustc::hir::intravisit::{self, IdVisitor, IdVisitingOperation, Visitor, FnKind};
+use rustc::hir::intravisit::{self, Visitor, FnKind};
use rustc_back::slice;
use syntax::ast::{self, DUMMY_NODE_ID, NodeId};
use rustc::hir::fold::{Folder, noop_fold_pat};
use rustc::hir::print::pat_to_string;
use syntax::ptr::P;
+use rustc::util::common::ErrorReported;
use rustc::util::nodemap::FnvHashMap;
pub const DUMMY_WILD_PAT: &'static Pat = &Pat {
Ok(_) => {}
Err(err) => {
- let mut diag = struct_span_err!(cx.tcx.sess, err.span, E0471,
- "constant evaluation error: {}",
- err.description());
- if !p.span.contains(err.span) {
- diag.span_note(p.span, "in pattern here");
- }
- diag.emit();
+ report_const_eval_err(cx.tcx, &err, p.span, "pattern").emit();
}
}
}
renaming_map: &'map mut FnvHashMap<(NodeId, Span), NodeId>
}
-impl<'map> IdVisitingOperation for RenamingRecorder<'map> {
+impl<'v, 'map> Visitor<'v> for RenamingRecorder<'map> {
fn visit_id(&mut self, node_id: NodeId) {
let key = (node_id, self.origin_span);
self.renaming_map.insert(key, self.substituted_node_id);
renaming_map: renaming_map,
};
- let mut id_visitor = IdVisitor::new(&mut renaming_recorder);
-
- id_visitor.visit_expr(const_expr);
+ renaming_recorder.visit_expr(const_expr);
}
}
}
}
}
-fn range_covered_by_constructor(ctor: &Constructor,
- from: &ConstVal, to: &ConstVal) -> Option<bool> {
+fn range_covered_by_constructor(tcx: TyCtxt, span: Span,
+ ctor: &Constructor,
+ from: &ConstVal, to: &ConstVal)
+ -> Result<bool, ErrorReported> {
let (c_from, c_to) = match *ctor {
ConstantValue(ref value) => (value, value),
ConstantRange(ref from, ref to) => (from, to),
- Single => return Some(true),
+ Single => return Ok(true),
_ => bug!()
};
- let cmp_from = compare_const_vals(c_from, from);
- let cmp_to = compare_const_vals(c_to, to);
- match (cmp_from, cmp_to) {
- (Some(cmp_from), Some(cmp_to)) => {
- Some(cmp_from != Ordering::Less && cmp_to != Ordering::Greater)
- }
- _ => None
- }
+ let cmp_from = compare_const_vals(tcx, span, c_from, from)?;
+ let cmp_to = compare_const_vals(tcx, span, c_to, to)?;
+ Ok(cmp_from != Ordering::Less && cmp_to != Ordering::Greater)
}
fn wrap_pat<'a, 'b, 'tcx>(cx: &MatchCheckCtxt<'b, 'tcx>,
Some(vec![(pat, Some(mt.ty))])
} else {
let expr_value = eval_const_expr(cx.tcx, &expr);
- match range_covered_by_constructor(constructor, &expr_value, &expr_value) {
- Some(true) => Some(vec![]),
- Some(false) => None,
- None => {
- span_err!(cx.tcx.sess, pat_span, E0298, "mismatched types between arms");
- None
- }
+ match range_covered_by_constructor(
+ cx.tcx, expr.span, constructor, &expr_value, &expr_value
+ ) {
+ Ok(true) => Some(vec![]),
+ Ok(false) => None,
+ Err(ErrorReported) => None,
}
}
}
PatKind::Range(ref from, ref to) => {
let from_value = eval_const_expr(cx.tcx, &from);
let to_value = eval_const_expr(cx.tcx, &to);
- match range_covered_by_constructor(constructor, &from_value, &to_value) {
- Some(true) => Some(vec![]),
- Some(false) => None,
- None => {
- span_err!(cx.tcx.sess, pat_span, E0299, "mismatched types between arms");
- None
- }
+ match range_covered_by_constructor(
+ cx.tcx, pat_span, constructor, &from_value, &to_value
+ ) {
+ Ok(true) => Some(vec![]),
+ Ok(false) => None,
+ Err(ErrorReported) => None,
}
}
_ => cx.param_env = ParameterEnvironment::for_item(cx.tcx, fn_id),
}
- intravisit::walk_fn(cx, kind, decl, body, sp);
+ intravisit::walk_fn(cx, kind, decl, body, sp, fn_id);
for input in &decl.inputs {
check_irrefutable(cx, &input.pat, true);
See also https://github.com/rust-lang/rust/issues/14587
"##,
-E0306: r##"
-In an array literal `[x; N]`, `N` is the number of elements in the array. This
-must be an unsigned integer. Erroneous code example:
+E0080: r##"
+This error indicates that the compiler was unable to sensibly evaluate an
+constant expression that had to be evaluated. Attempting to divide by 0
+or causing integer overflow are two ways to induce this error. For example:
```compile_fail
-let x = [0i32; true]; // error: expected positive integer for repeat count,
- // found boolean
+enum Enum {
+ X = (1 << 500),
+ Y = (1 / 0)
+}
```
-Working example:
+Ensure that the expressions given can be evaluated as the desired integer type.
+See the FFI section of the Reference for more information about using a custom
+integer type:
-```
-let x = [0i32; 2];
-```
+https://doc.rust-lang.org/reference.html#ffi-attributes
"##,
-E0307: r##"
-The length of an array is part of its type. For this reason, this length must
-be a compile-time constant. Erroneous code example:
+
+E0306: r##"
+In an array literal `[x; N]`, `N` is the number of elements in the array. This
+must be an unsigned integer. Erroneous code example:
```compile_fail
- let len = 10;
- let x = [0i32; len]; // error: expected constant integer for repeat count,
- // found variable
+let x = [0i32; true]; // error: expected positive integer for repeat count,
+ // found boolean
```
Working example:
```
-let x = [0i32; 10];
+let x = [0i32; 2];
```
"##,
-
}
register_diagnostics! {
-E0298, // mismatched types between arms
-E0299, // mismatched types between arms
-E0471, // constant evaluation error: ..
+ E0298, // cannot compare constants
+// E0299, // mismatched types between arms
+// E0471, // constant evaluation error (in pattern)
}
use rustc::ty::{self, Ty, TyCtxt, subst};
use rustc::ty::util::IntTypeExt;
use rustc::traits::ProjectionMode;
+use rustc::util::common::ErrorReported;
use rustc::util::nodemap::NodeMap;
use rustc::lint;
use std::collections::hash_map::Entry::Vacant;
use rustc_const_math::*;
+use rustc_errors::{DiagnosticBuilder, check_old_school};
macro_rules! math {
($e:expr, $op:expr) => {
Ok(P(hir::Pat { id: expr.id, node: pat, span: span }))
}
+pub fn report_const_eval_err<'a, 'tcx>(
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ err: &ConstEvalErr,
+ primary_span: Span,
+ primary_kind: &str)
+ -> DiagnosticBuilder<'tcx>
+{
+ let mut err = err;
+ while let &ConstEvalErr { kind: ErroneousReferencedConstant(box ref i_err), .. } = err {
+ err = i_err;
+ }
+
+ let mut diag = struct_span_err!(tcx.sess, err.span, E0080, "constant evaluation error");
+ note_const_eval_err(tcx, err, primary_span, primary_kind, &mut diag);
+ diag
+}
+
+pub fn fatal_const_eval_err<'a, 'tcx>(
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ err: &ConstEvalErr,
+ primary_span: Span,
+ primary_kind: &str)
+ -> !
+{
+ report_const_eval_err(tcx, err, primary_span, primary_kind).emit();
+ tcx.sess.abort_if_errors();
+ unreachable!()
+}
+
+pub fn note_const_eval_err<'a, 'tcx>(
+ _tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ err: &ConstEvalErr,
+ primary_span: Span,
+ primary_kind: &str,
+ diag: &mut DiagnosticBuilder)
+{
+ match err.description() {
+ ConstEvalErrDescription::Simple(message) => {
+ if check_old_school() {
+ diag.note(&message);
+ } else {
+ diag.span_label(err.span, &message);
+ }
+ }
+ }
+
+ if !primary_span.contains(err.span) {
+ diag.span_note(primary_span,
+ &format!("for {} here", primary_kind));
+ }
+}
+
pub fn eval_const_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
e: &Expr) -> ConstVal {
match eval_const_expr_partial(tcx, e, ExprTypeChecked, None) {
Ok(r) => r,
// non-const path still needs to be a fatal error, because enums are funky
Err(s) => {
+ report_const_eval_err(tcx, &s, e.span, "expression").emit();
match s.kind {
NonConstPath |
- UnimplementedConstVal(_) => tcx.sess.span_fatal(s.span, &s.description()),
- _ => {
- tcx.sess.span_err(s.span, &s.description());
- Dummy
- }
+ UnimplementedConstVal(_) => tcx.sess.abort_if_errors(),
+ _ => {}
}
+ Dummy
},
}
}
IntermediateUnsignedNegative,
/// Expected, Got
TypeMismatch(String, ConstInt),
+
BadType(ConstVal),
ErroneousReferencedConstant(Box<ConstEvalErr>),
CharCast(ConstInt),
}
}
+#[derive(Clone, Debug)]
+pub enum ConstEvalErrDescription<'a> {
+ Simple(Cow<'a, str>),
+}
+
+impl<'a> ConstEvalErrDescription<'a> {
+ /// Return a one-line description of the error, for lints and such
+ pub fn into_oneline(self) -> Cow<'a, str> {
+ match self {
+ ConstEvalErrDescription::Simple(simple) => simple,
+ }
+ }
+}
+
impl ConstEvalErr {
- pub fn description(&self) -> Cow<str> {
+ pub fn description(&self) -> ConstEvalErrDescription {
use self::ErrKind::*;
+ use self::ConstEvalErrDescription::*;
+
+ macro_rules! simple {
+ ($msg:expr) => ({ Simple($msg.into_cow()) });
+ ($fmt:expr, $($arg:tt)+) => ({
+ Simple(format!($fmt, $($arg)+).into_cow())
+ })
+ }
match self.kind {
- CannotCast => "can't cast this type".into_cow(),
- CannotCastTo(s) => format!("can't cast this type to {}", s).into_cow(),
- InvalidOpForInts(_) => "can't do this op on integrals".into_cow(),
- InvalidOpForBools(_) => "can't do this op on bools".into_cow(),
- InvalidOpForFloats(_) => "can't do this op on floats".into_cow(),
- InvalidOpForIntUint(..) => "can't do this op on an isize and usize".into_cow(),
- InvalidOpForUintInt(..) => "can't do this op on a usize and isize".into_cow(),
- NegateOn(ref const_val) => format!("negate on {}", const_val.description()).into_cow(),
- NotOn(ref const_val) => format!("not on {}", const_val.description()).into_cow(),
- CallOn(ref const_val) => format!("call on {}", const_val.description()).into_cow(),
-
- MissingStructField => "nonexistent struct field".into_cow(),
- NonConstPath => "non-constant path in constant expression".into_cow(),
+ CannotCast => simple!("can't cast this type"),
+ CannotCastTo(s) => simple!("can't cast this type to {}", s),
+ InvalidOpForInts(_) => simple!("can't do this op on integrals"),
+ InvalidOpForBools(_) => simple!("can't do this op on bools"),
+ InvalidOpForFloats(_) => simple!("can't do this op on floats"),
+ InvalidOpForIntUint(..) => simple!("can't do this op on an isize and usize"),
+ InvalidOpForUintInt(..) => simple!("can't do this op on a usize and isize"),
+ NegateOn(ref const_val) => simple!("negate on {}", const_val.description()),
+ NotOn(ref const_val) => simple!("not on {}", const_val.description()),
+ CallOn(ref const_val) => simple!("call on {}", const_val.description()),
+
+ MissingStructField => simple!("nonexistent struct field"),
+ NonConstPath => simple!("non-constant path in constant expression"),
UnimplementedConstVal(what) =>
- format!("unimplemented constant expression: {}", what).into_cow(),
- UnresolvedPath => "unresolved path in constant expression".into_cow(),
- ExpectedConstTuple => "expected constant tuple".into_cow(),
- ExpectedConstStruct => "expected constant struct".into_cow(),
- TupleIndexOutOfBounds => "tuple index out of bounds".into_cow(),
- IndexedNonVec => "indexing is only supported for arrays".into_cow(),
- IndexNegative => "indices must be non-negative integers".into_cow(),
- IndexNotInt => "indices must be integers".into_cow(),
+ simple!("unimplemented constant expression: {}", what),
+ UnresolvedPath => simple!("unresolved path in constant expression"),
+ ExpectedConstTuple => simple!("expected constant tuple"),
+ ExpectedConstStruct => simple!("expected constant struct"),
+ TupleIndexOutOfBounds => simple!("tuple index out of bounds"),
+ IndexedNonVec => simple!("indexing is only supported for arrays"),
+ IndexNegative => simple!("indices must be non-negative integers"),
+ IndexNotInt => simple!("indices must be integers"),
IndexOutOfBounds { len, index } => {
- format!("index out of bounds: the len is {} but the index is {}",
- len, index).into_cow()
+ simple!("index out of bounds: the len is {} but the index is {}",
+ len, index)
}
- RepeatCountNotNatural => "repeat count must be a natural number".into_cow(),
- RepeatCountNotInt => "repeat count must be integers".into_cow(),
+ RepeatCountNotNatural => simple!("repeat count must be a natural number"),
+ RepeatCountNotInt => simple!("repeat count must be integers"),
- MiscBinaryOp => "bad operands for binary".into_cow(),
- MiscCatchAll => "unsupported constant expr".into_cow(),
- IndexOpFeatureGated => "the index operation on const values is unstable".into_cow(),
- Math(ref err) => err.description().into_cow(),
+ MiscBinaryOp => simple!("bad operands for binary"),
+ MiscCatchAll => simple!("unsupported constant expr"),
+ IndexOpFeatureGated => simple!("the index operation on const values is unstable"),
+ Math(ref err) => Simple(err.description().into_cow()),
- IntermediateUnsignedNegative => "during the computation of an unsigned a negative \
- number was encountered. This is most likely a bug in\
- the constant evaluator".into_cow(),
+ IntermediateUnsignedNegative => simple!(
+ "during the computation of an unsigned a negative \
+ number was encountered. This is most likely a bug in\
+ the constant evaluator"),
TypeMismatch(ref expected, ref got) => {
- format!("mismatched types: expected `{}`, found `{}`",
- expected, got.description()).into_cow()
+ simple!("expected {}, found {}", expected, got.description())
},
- BadType(ref i) => format!("value of wrong type: {:?}", i).into_cow(),
- ErroneousReferencedConstant(_) => "could not evaluate referenced constant".into_cow(),
+ BadType(ref i) => simple!("value of wrong type: {:?}", i),
+ ErroneousReferencedConstant(_) => simple!("could not evaluate referenced constant"),
CharCast(ref got) => {
- format!("only `u8` can be cast as `char`, not `{}`", got.description()).into_cow()
+ simple!("only `u8` can be cast as `char`, not `{}`", got.description())
},
}
}
})
}
-pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option<Ordering> {
- match (a, b) {
+pub fn compare_const_vals(tcx: TyCtxt, span: Span, a: &ConstVal, b: &ConstVal)
+ -> Result<Ordering, ErrorReported>
+{
+ let result = match (a, b) {
(&Integral(a), &Integral(b)) => a.try_cmp(b).ok(),
(&Float(a), &Float(b)) => a.try_cmp(b).ok(),
(&Str(ref a), &Str(ref b)) => Some(a.cmp(b)),
(&ByteStr(ref a), &ByteStr(ref b)) => Some(a.cmp(b)),
(&Char(a), &Char(ref b)) => Some(a.cmp(b)),
_ => None,
+ };
+
+ match result {
+ Some(result) => Ok(result),
+ None => {
+ // FIXME: can this ever be reached?
+ span_err!(tcx.sess, span, E0298,
+ "type mismatch comparing {} and {}",
+ a.description(),
+ b.description());
+ Err(ErrorReported)
+ }
}
}
pub fn compare_lit_exprs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ span: Span,
a: &Expr,
- b: &Expr) -> Option<Ordering> {
+ b: &Expr) -> Result<Ordering, ErrorReported> {
let a = match eval_const_expr_partial(tcx, a, ExprTypeChecked, None) {
Ok(a) => a,
Err(e) => {
- tcx.sess.span_err(a.span, &e.description());
- return None;
+ report_const_eval_err(tcx, &e, a.span, "expression").emit();
+ return Err(ErrorReported);
}
};
let b = match eval_const_expr_partial(tcx, b, ExprTypeChecked, None) {
Ok(b) => b,
Err(e) => {
- tcx.sess.span_err(b.span, &e.description());
- return None;
+ report_const_eval_err(tcx, &e, b.span, "expression").emit();
+ return Err(ErrorReported);
}
};
- compare_const_vals(&a, &b)
+ compare_const_vals(tcx, span, &a, &b)
}
-/// Returns the repeat count for a repeating vector expression.
-pub fn eval_repeat_count<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- count_expr: &hir::Expr) -> usize {
+/// Returns the value of the length-valued expression
+pub fn eval_length<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ count_expr: &hir::Expr,
+ reason: &str)
+ -> Result<usize, ErrorReported>
+{
let hint = UncheckedExprHint(tcx.types.usize);
match eval_const_expr_partial(tcx, count_expr, hint, None) {
Ok(Integral(Usize(count))) => {
let val = count.as_u64(tcx.sess.target.uint_type);
assert_eq!(val as usize as u64, val);
- val as usize
+ Ok(val as usize)
},
Ok(const_val) => {
span_err!(tcx.sess, count_expr.span, E0306,
- "expected positive integer for repeat count, found {}",
+ "expected usize for {}, found {}",
+ reason,
const_val.description());
- 0
+ Err(ErrorReported)
}
Err(err) => {
- let err_msg = match count_expr.node {
+ let mut diag = report_const_eval_err(
+ tcx, &err, count_expr.span, reason);
+
+ match count_expr.node {
hir::ExprPath(None, hir::Path {
global: false,
ref segments,
..
- }) if segments.len() == 1 =>
- format!("found variable"),
- _ => match err.kind {
- MiscCatchAll => format!("but found {}", err.description()),
- _ => format!("but {}", err.description())
+ }) if segments.len() == 1 => {
+ if let Some(Def::Local(..)) = tcx.expect_def_or_none(count_expr.id) {
+ diag.note(&format!("`{}` is a variable", segments[0].name));
+ }
}
- };
- span_err!(tcx.sess, count_expr.span, E0307,
- "expected constant integer for repeat count, {}", err_msg);
- 0
+ _ => {}
+ }
+
+ diag.emit();
+ Err(ErrorReported)
}
}
}
#[macro_use] extern crate rustc;
extern crate rustc_back;
extern crate rustc_const_math;
+extern crate rustc_errors;
extern crate graphviz;
extern crate syntax_pos;
extern crate serialize as rustc_serialize; // used by deriving
// We need nested scopes here, because the intermediate results can keep
// large chunks of memory alive and we want to free them as soon as
// possible to keep the peak memory usage low
- let (outputs, trans) = {
+ let (outputs, trans, crate_name) = {
let krate = match phase_1_parse_input(sess, cfg, input) {
Ok(krate) => krate,
Err(mut parse_error) => {
};
let outputs = build_output_filenames(input, outdir, output, &krate.attrs, sess);
- let id = link::find_crate_name(Some(sess), &krate.attrs, input);
+ let crate_name = link::find_crate_name(Some(sess), &krate.attrs, input);
let ExpansionResult { expanded_crate, defs, analysis, resolutions, mut hir_forest } = {
phase_2_configure_and_expand(
- sess, &cstore, krate, &id, addl_plugins, control.make_glob_map,
+ sess, &cstore, krate, &crate_name, addl_plugins, control.make_glob_map,
|expanded_crate| {
let mut state = CompileState::state_after_expand(
- input, sess, outdir, output, &cstore, expanded_crate, &id,
+ input, sess, outdir, output, &cstore, expanded_crate, &crate_name,
);
controller_entry_point!(after_expand, sess, state, Ok(()));
Ok(())
)?
};
- write_out_deps(sess, &outputs, &id);
+ write_out_deps(sess, &outputs, &crate_name);
let arenas = ty::CtxtArenas::new();
&resolutions,
&expanded_crate,
&hir_map.krate(),
- &id),
+ &crate_name),
Ok(()));
}
analysis,
resolutions,
&arenas,
- &id,
+ &crate_name,
|tcx, mir_map, analysis, result| {
{
// Eventually, we will want to track plugins.
&analysis,
mir_map.as_ref(),
tcx,
- &id);
+ &crate_name);
(control.after_analysis.callback)(&mut state);
if control.after_analysis.stop == Compilation::Stop {
// Discard interned strings as they are no longer required.
token::clear_ident_interner();
- Ok((outputs, trans))
+ Ok((outputs, trans, crate_name.clone()))
})??
};
- let phase5_result = phase_5_run_llvm_passes(sess, &trans, &outputs);
+ let phase5_result = phase_5_run_llvm_passes(sess, &crate_name, &trans, &outputs);
controller_entry_point!(after_llvm,
sess,
cfg: ast::CrateConfig,
input: &Input)
-> PResult<'a, ast::Crate> {
- // These may be left in an incoherent state after a previous compile.
- syntax::ext::hygiene::reset_hygiene_data();
- // `clear_ident_interner` can be used to free memory, but it does not restore the initial state.
- token::reset_ident_interner();
let continue_after_error = sess.opts.continue_parse_after_error;
sess.diagnostic().set_continue_after_error(continue_after_error);
});
*sess.crate_types.borrow_mut() = collect_crate_types(sess, &krate.attrs);
- sess.crate_disambiguator.set(token::intern(&compute_crate_disambiguator(sess)));
+ *sess.crate_disambiguator.borrow_mut() =
+ token::intern(&compute_crate_disambiguator(sess)).as_str();
time(time_passes, "recursion limit", || {
middle::recursion_limit::update_recursion_limit(sess, &krate);
/// Run LLVM itself, producing a bitcode file, assembly file or object file
/// as a side effect.
pub fn phase_5_run_llvm_passes(sess: &Session,
+ crate_name: &str,
trans: &trans::CrateTranslation,
outputs: &OutputFilenames) -> CompileResult {
if sess.opts.cg.no_integrated_as {
|| write::run_passes(sess, trans, &sess.opts.output_types, outputs));
}
+ time(sess.time_passes(),
+ "serialize work products",
+ move || rustc_incremental::save_work_products(sess, crate_name));
+
if sess.err_count() > 0 {
Err(sess.err_count())
} else {
filename.replace(" ", "\\ ")
}
-fn write_out_deps(sess: &Session, outputs: &OutputFilenames, id: &str) {
+fn write_out_deps(sess: &Session, outputs: &OutputFilenames, crate_name: &str) {
let mut out_filenames = Vec::new();
for output_type in sess.opts.output_types.keys() {
let file = outputs.path(*output_type);
match *output_type {
OutputType::Exe => {
for output in sess.crate_types.borrow().iter() {
- let p = link::filename_for_input(sess, *output, id, outputs);
+ let p = link::filename_for_input(sess, *output, crate_name, outputs);
out_filenames.push(p);
}
}
}
}
}
+
+// For use by the `rusti` project (https://github.com/murarth/rusti).
+pub fn reset_thread_local_state() {
+ // These may be left in an incoherent state after a previous compile.
+ syntax::ext::hygiene::reset_hygiene_data();
+ // `clear_ident_interner` can be used to free memory, but it does not restore the initial state.
+ token::reset_ident_interner();
+}
use rustc::session::early_error;
use syntax::{ast, json};
+use syntax::attr::AttrMetaMethods;
use syntax::codemap::{CodeMap, FileLoader, RealFileLoader};
use syntax::feature_gate::{GatedCfg, UnstableFeatures};
use syntax::parse::{self, PResult};
let mut saw_invalid_predicate = false;
for item in sopts.cfg.iter() {
- match item.node {
- ast::MetaItemKind::List(ref pred, _) => {
- saw_invalid_predicate = true;
- handler.emit(&MultiSpan::new(),
- &format!("invalid predicate in --cfg command line argument: `{}`",
- pred),
- errors::Level::Fatal);
- }
- _ => {},
+ if item.is_meta_item_list() {
+ saw_invalid_predicate = true;
+ handler.emit(&MultiSpan::new(),
+ &format!("invalid predicate in --cfg command line argument: `{}`",
+ item.name()),
+ errors::Level::Fatal);
}
}
for req in &sess.opts.prints {
match *req {
PrintRequest::TargetList => {
- let mut targets = rustc_back::target::TARGETS.to_vec();
+ let mut targets = rustc_back::target::get_targets().collect::<Vec<String>>();
targets.sort();
println!("{}", targets.join("\n"));
},
if !allow_unstable_cfg && GatedCfg::gate(&*cfg).is_some() {
continue;
}
- match cfg.node {
- ast::MetaItemKind::Word(ref word) => println!("{}", word),
- ast::MetaItemKind::NameValue(ref name, ref value) => {
- println!("{}=\"{}\"", name, match value.node {
- ast::LitKind::Str(ref s, _) => s,
- _ => continue,
- });
+ if cfg.is_word() {
+ println!("{}", cfg.name());
+ } else if cfg.is_value_str() {
+ if let Some(s) = cfg.value_str() {
+ println!("{}=\"{}\"", cfg.name(), s);
}
+ } else if cfg.is_meta_item_list() {
// Right now there are not and should not be any
// MetaItemKind::List items in the configuration returned by
// `build_configuration`.
- ast::MetaItemKind::List(..) => {
- panic!("MetaItemKind::List encountered in default cfg")
- }
+ panic!("MetaItemKind::List encountered in default cfg")
}
}
}
DiagnosticBuilder::new(self, Level::Fatal, msg)
}
- pub fn cancel(&mut self, err: &mut DiagnosticBuilder) {
+ pub fn cancel(&self, err: &mut DiagnosticBuilder) {
if err.level == Level::Error || err.level == Level::Fatal {
- assert!(self.has_errors());
- self.err_count.set(self.err_count.get() + 1);
+ self.err_count.set(
+ self.err_count.get().checked_sub(1)
+ .expect("cancelled an error but err_count is 0")
+ );
}
err.cancel();
}
if attr.check_name(IF_THIS_CHANGED) {
let mut id = None;
for meta_item in attr.meta_item_list().unwrap_or_default() {
- match meta_item.node {
- ast::MetaItemKind::Word(ref s) if id.is_none() => id = Some(s.clone()),
- _ => {
- self.tcx.sess.span_err(
- meta_item.span,
- &format!("unexpected meta-item {:?}", meta_item.node));
- }
+ if meta_item.is_word() && id.is_none() {
+ id = Some(meta_item.name().clone());
+ } else {
+ // FIXME better-encapsulate meta_item (don't directly access `node`)
+ span_bug!(meta_item.span(), "unexpected meta-item {:?}", meta_item.node)
}
}
let id = id.unwrap_or(InternedString::new(ID));
let mut dep_node_interned = None;
let mut id = None;
for meta_item in attr.meta_item_list().unwrap_or_default() {
- match meta_item.node {
- ast::MetaItemKind::Word(ref s) if dep_node_interned.is_none() =>
- dep_node_interned = Some(s.clone()),
- ast::MetaItemKind::Word(ref s) if id.is_none() =>
- id = Some(s.clone()),
- _ => {
- self.tcx.sess.span_err(
- meta_item.span,
- &format!("unexpected meta-item {:?}", meta_item.node));
- }
+ if meta_item.is_word() && dep_node_interned.is_none() {
+ dep_node_interned = Some(meta_item.name().clone());
+ } else if meta_item.is_word() && id.is_none() {
+ id = Some(meta_item.name().clone());
+ } else {
+ // FIXME better-encapsulate meta_item (don't directly access `node`)
+ span_bug!(meta_item.span(), "unexpected meta-item {:?}", meta_item.node)
}
}
let dep_node = match dep_node_interned {
//! Calculation of a Strict Version Hash for crates. For a length
//! comment explaining the general idea, see `librustc/middle/svh.rs`.
+use syntax::attr::AttributeMethods;
use std::hash::{Hash, SipHasher, Hasher};
use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
use rustc::hir::svh::Svh;
// to ensure it is not incorporating implementation artifacts into
// the hash that are not otherwise visible.)
- let crate_disambiguator = self.sess.crate_disambiguator.get();
+ let crate_disambiguator = self.sess.local_crate_disambiguator();
let krate = self.map.krate();
// FIXME: this should use SHA1, not SipHash. SipHash is not built to
// FIXME(#32753) -- at (*) we `to_le` for endianness, but is
// this enough, and does it matter anyway?
"crate_disambiguator".hash(&mut state);
- crate_disambiguator.as_str().len().to_le().hash(&mut state); // (*)
- crate_disambiguator.as_str().hash(&mut state);
+ crate_disambiguator.len().to_le().hash(&mut state); // (*)
+ crate_disambiguator.hash(&mut state);
- debug!("crate_disambiguator: {:?}", crate_disambiguator.as_str());
+ debug!("crate_disambiguator: {:?}", crate_disambiguator);
debug!("state: {:?}", state);
{
// to avoid hashing the AttrId
for attr in &krate.attrs {
debug!("krate attr {:?}", attr);
- attr.node.value.hash(&mut state);
+ attr.meta().hash(&mut state);
}
Svh::new(state.finish())
use rustc::ty::TyCtxt;
use rustc::hir;
use rustc::hir::*;
+ use rustc::hir::map::DefPath;
use rustc::hir::intravisit as visit;
use rustc::hir::intravisit::{Visitor, FnKind};
-> Self {
StrictVersionHashVisitor { st: st, tcx: tcx }
}
+
+ fn hash_def_path(&mut self, path: &DefPath) {
+ self.tcx.crate_name(path.krate).hash(self.st);
+ self.tcx.crate_disambiguator(path.krate).hash(self.st);
+ for data in &path.data {
+ data.data.as_interned_str().hash(self.st);
+ data.disambiguator.hash(self.st);
+ }
+ }
}
// To off-load the bulk of the hash-computation on #[derive(Hash)],
impl<'a, 'tcx> Visitor<'a> for StrictVersionHashVisitor<'a, 'tcx> {
fn visit_nested_item(&mut self, item: ItemId) {
- debug!("visit_nested_item: {:?} st={:?}", item, self.st);
- let def_path = self.tcx.map.def_path_from_id(item.id);
- def_path.hash(self.st);
+ let def_path = self.tcx.map.def_path_from_id(item.id).unwrap();
+ debug!("visit_nested_item: def_path={:?} st={:?}", def_path, self.st);
+ self.hash_def_path(&def_path);
}
fn visit_variant_data(&mut self, s: &'a VariantData, name: Name,
g: &'a Generics, _: NodeId, _: Span) {
+ debug!("visit_variant_data: st={:?}", self.st);
SawStructDef(name.as_str()).hash(self.st);
visit::walk_generics(self, g);
visit::walk_struct_def(self, s)
}
fn visit_variant(&mut self, v: &'a Variant, g: &'a Generics, item_id: NodeId) {
+ debug!("visit_variant: st={:?}", self.st);
SawVariant.hash(self.st);
// walk_variant does not call walk_generics, so do it here.
visit::walk_generics(self, g);
// pattern, please move that method up above this comment.)
fn visit_name(&mut self, _: Span, name: Name) {
+ debug!("visit_name: st={:?}", self.st);
SawIdent(name.as_str()).hash(self.st);
}
fn visit_lifetime(&mut self, l: &'a Lifetime) {
+ debug!("visit_lifetime: st={:?}", self.st);
SawLifetime(l.name.as_str()).hash(self.st);
}
fn visit_lifetime_def(&mut self, l: &'a LifetimeDef) {
+ debug!("visit_lifetime_def: st={:?}", self.st);
SawLifetimeDef(l.lifetime.name.as_str()).hash(self.st);
}
// that a change to a crate body will require downstream
// crates to be recompiled.
fn visit_expr(&mut self, ex: &'a Expr) {
+ debug!("visit_expr: st={:?}", self.st);
SawExpr(saw_expr(&ex.node)).hash(self.st); visit::walk_expr(self, ex)
}
fn visit_stmt(&mut self, s: &'a Stmt) {
+ debug!("visit_stmt: st={:?}", self.st);
SawStmt(saw_stmt(&s.node)).hash(self.st); visit::walk_stmt(self, s)
}
fn visit_foreign_item(&mut self, i: &'a ForeignItem) {
+ debug!("visit_foreign_item: st={:?}", self.st);
+
// FIXME (#14132) ideally we would incorporate privacy (or
// perhaps reachability) somewhere here, so foreign items
// that do not leak into downstream crates would not be
fn visit_item(&mut self, i: &'a Item) {
debug!("visit_item: {:?} st={:?}", i, self.st);
+
// FIXME (#14132) ideally would incorporate reachability
// analysis somewhere here, so items that never leak into
// downstream crates (e.g. via monomorphisation or
SawItem.hash(self.st); visit::walk_item(self, i)
}
- fn visit_mod(&mut self, m: &'a Mod, _s: Span, _n: NodeId) {
- SawMod.hash(self.st); visit::walk_mod(self, m)
+ fn visit_mod(&mut self, m: &'a Mod, _s: Span, n: NodeId) {
+ debug!("visit_mod: st={:?}", self.st);
+ SawMod.hash(self.st); visit::walk_mod(self, m, n)
}
fn visit_decl(&mut self, d: &'a Decl) {
+ debug!("visit_decl: st={:?}", self.st);
SawDecl.hash(self.st); visit::walk_decl(self, d)
}
fn visit_ty(&mut self, t: &'a Ty) {
+ debug!("visit_ty: st={:?}", self.st);
SawTy.hash(self.st); visit::walk_ty(self, t)
}
fn visit_generics(&mut self, g: &'a Generics) {
+ debug!("visit_generics: st={:?}", self.st);
SawGenerics.hash(self.st); visit::walk_generics(self, g)
}
fn visit_fn(&mut self, fk: FnKind<'a>, fd: &'a FnDecl,
- b: &'a Block, s: Span, _: NodeId) {
- SawFn.hash(self.st); visit::walk_fn(self, fk, fd, b, s)
+ b: &'a Block, s: Span, n: NodeId) {
+ debug!("visit_fn: st={:?}", self.st);
+ SawFn.hash(self.st); visit::walk_fn(self, fk, fd, b, s, n)
}
fn visit_trait_item(&mut self, ti: &'a TraitItem) {
+ debug!("visit_trait_item: st={:?}", self.st);
SawTraitItem.hash(self.st); visit::walk_trait_item(self, ti)
}
fn visit_impl_item(&mut self, ii: &'a ImplItem) {
+ debug!("visit_impl_item: st={:?}", self.st);
SawImplItem.hash(self.st); visit::walk_impl_item(self, ii)
}
fn visit_struct_field(&mut self, s: &'a StructField) {
+ debug!("visit_struct_field: st={:?}", self.st);
SawStructField.hash(self.st); visit::walk_struct_field(self, s)
}
fn visit_path(&mut self, path: &'a Path, _: ast::NodeId) {
+ debug!("visit_path: st={:?}", self.st);
SawPath.hash(self.st); visit::walk_path(self, path)
}
fn visit_block(&mut self, b: &'a Block) {
+ debug!("visit_block: st={:?}", self.st);
SawBlock.hash(self.st); visit::walk_block(self, b)
}
fn visit_pat(&mut self, p: &'a Pat) {
+ debug!("visit_pat: st={:?}", self.st);
SawPat.hash(self.st); visit::walk_pat(self, p)
}
fn visit_local(&mut self, l: &'a Local) {
+ debug!("visit_local: st={:?}", self.st);
SawLocal.hash(self.st); visit::walk_local(self, l)
}
fn visit_arm(&mut self, a: &'a Arm) {
+ debug!("visit_arm: st={:?}", self.st);
SawArm.hash(self.st); visit::walk_arm(self, a)
}
}
html_root_url = "https://doc.rust-lang.org/nightly/")]
#![cfg_attr(not(stage0), deny(warnings))]
+#![feature(question_mark)]
#![feature(rustc_private)]
#![feature(staged_api)]
pub use calculate_svh::SvhCalculate;
pub use persist::load_dep_graph;
pub use persist::save_dep_graph;
+pub use persist::save_trans_partition;
+pub use persist::save_work_products;
+pub use persist::in_incr_comp_dir;
//! The data that we will serialize and deserialize.
-use rustc::dep_graph::DepNode;
+use rustc::dep_graph::{DepNode, WorkProduct, WorkProductId};
use rustc::hir::def_id::DefIndex;
+use std::sync::Arc;
use super::directory::DefPathIndex;
pub hash: u64,
}
+#[derive(Debug, RustcEncodable, RustcDecodable)]
+pub struct SerializedWorkProduct {
+ /// node that produced the work-product
+ pub id: Arc<WorkProductId>,
+
+ /// work-product data itself
+ pub work_product: WorkProduct,
+}
+
/// Data for use when downstream crates get recompiled.
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct SerializedMetadataHashes {
use rbml::opaque::Decoder;
use rustc::dep_graph::DepNode;
use rustc::hir::def_id::DefId;
+use rustc::session::Session;
use rustc::ty::TyCtxt;
use rustc_data_structures::fnv::FnvHashSet;
use rustc_serialize::Decodable as RustcDecodable;
use std::io::Read;
-use std::fs::File;
-use std::path::Path;
+use std::fs::{self, File};
+use std::path::{Path};
use super::data::*;
use super::directory::*;
/// actually it doesn't matter all that much.) See `README.md` for
/// more general overview.
pub fn load_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+ if tcx.sess.opts.incremental.is_none() {
+ return;
+ }
+
let _ignore = tcx.dep_graph.in_ignore();
+ load_dep_graph_if_exists(tcx);
+ dirty_clean::check_dirty_clean_annotations(tcx);
+}
- if let Some(dep_graph) = dep_graph_path(tcx) {
- // FIXME(#32754) lock file?
- load_dep_graph_if_exists(tcx, &dep_graph);
- dirty_clean::check_dirty_clean_annotations(tcx);
+fn load_dep_graph_if_exists<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+ let dep_graph_path = dep_graph_path(tcx).unwrap();
+ let dep_graph_data = match load_data(tcx.sess, &dep_graph_path) {
+ Some(p) => p,
+ None => return // no file
+ };
+
+ let work_products_path = tcx_work_products_path(tcx).unwrap();
+ let work_products_data = match load_data(tcx.sess, &work_products_path) {
+ Some(p) => p,
+ None => return // no file
+ };
+
+ match decode_dep_graph(tcx, &dep_graph_data, &work_products_data) {
+ Ok(()) => return,
+ Err(err) => {
+ tcx.sess.warn(
+ &format!("decoding error in dep-graph from `{}` and `{}`: {}",
+ dep_graph_path.display(),
+ work_products_path.display(),
+ err));
+ }
}
}
-pub fn load_dep_graph_if_exists<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, path: &Path) {
+fn load_data(sess: &Session, path: &Path) -> Option<Vec<u8>> {
if !path.exists() {
- return;
+ return None;
}
let mut data = vec![];
File::open(path)
.and_then(|mut file| file.read_to_end(&mut data))
{
- Ok(_) => { }
+ Ok(_) => {
+ Some(data)
+ }
Err(err) => {
- tcx.sess.err(
+ sess.err(
&format!("could not load dep-graph from `{}`: {}",
path.display(), err));
- return;
+ None
}
}
- match decode_dep_graph(tcx, &data) {
- Ok(dirty) => dirty,
- Err(err) => {
- bug!("decoding error in dep-graph from `{}`: {}", path.display(), err);
- }
- }
}
+/// Decode the dep graph and load the edges/nodes that are still clean
+/// into `tcx.dep_graph`.
pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- data: &[u8])
+ dep_graph_data: &[u8],
+ work_products_data: &[u8])
-> Result<(), Error>
{
// Deserialize the directory and dep-graph.
- let mut decoder = Decoder::new(data, 0);
- let directory = try!(DefIdDirectory::decode(&mut decoder));
- let serialized_dep_graph = try!(SerializedDepGraph::decode(&mut decoder));
+ let mut dep_graph_decoder = Decoder::new(dep_graph_data, 0);
+ let directory = try!(DefIdDirectory::decode(&mut dep_graph_decoder));
+ let serialized_dep_graph = try!(SerializedDepGraph::decode(&mut dep_graph_decoder));
debug!("decode_dep_graph: directory = {:#?}", directory);
debug!("decode_dep_graph: serialized_dep_graph = {:#?}", serialized_dep_graph);
// Add nodes and edges that are not dirty into our main graph.
let dep_graph = tcx.dep_graph.clone();
for (source, target) in clean_edges.into_iter().chain(clean_nodes) {
- let _task = dep_graph.in_task(target.clone());
- dep_graph.read(source.clone());
-
debug!("decode_dep_graph: clean edge: {:?} -> {:?}", source, target);
+
+ let _task = dep_graph.in_task(target);
+ dep_graph.read(source);
}
+ // Add in work-products that are still clean, and delete those that are
+ // dirty.
+ let mut work_product_decoder = Decoder::new(work_products_data, 0);
+ let work_products = try!(<Vec<SerializedWorkProduct>>::decode(&mut work_product_decoder));
+ reconcile_work_products(tcx, work_products, &dirty_nodes);
+
Ok(())
}
match hash.node.map_def(|&i| retraced.def_id(i)) {
Some(dep_node) => {
let current_hash = hcx.hash(&dep_node).unwrap();
- debug!("initial_dirty_nodes: hash of {:?} is {:?}, was {:?}",
- dep_node, current_hash, hash.hash);
if current_hash != hash.hash {
+ debug!("initial_dirty_nodes: {:?} is dirty as hash is {:?}, was {:?}",
+ dep_node, current_hash, hash.hash);
dirty_nodes.insert(dep_node);
}
}
clean_edges.push((source, target))
} else {
// source removed, target must be dirty
+ debug!("compute_clean_edges: {:?} dirty because {:?} no longer exists",
+ target, serialized_source);
dirty_nodes.insert(target);
}
} else {
clean_edges
}
+
+/// Go through the list of work-products produced in the previous run.
+/// Delete any whose nodes have been found to be dirty or which are
+/// otherwise no longer applicable.
+fn reconcile_work_products<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ work_products: Vec<SerializedWorkProduct>,
+ dirty_nodes: &DirtyNodes) {
+ debug!("reconcile_work_products({:?})", work_products);
+ for swp in work_products {
+ let dep_node = DepNode::WorkProduct(swp.id.clone());
+ if dirty_nodes.contains(&dep_node) {
+ debug!("reconcile_work_products: dep-node for {:?} is dirty", swp);
+ delete_dirty_work_product(tcx, swp);
+ } else {
+ let all_files_exist =
+ swp.work_product
+ .saved_files
+ .iter()
+ .all(|&(_, ref file_name)| {
+ let path = in_incr_comp_dir(tcx.sess, &file_name).unwrap();
+ path.exists()
+ });
+ if all_files_exist {
+ debug!("reconcile_work_products: all files for {:?} exist", swp);
+ tcx.dep_graph.insert_previous_work_product(&swp.id, swp.work_product);
+ } else {
+ debug!("reconcile_work_products: some file for {:?} does not exist", swp);
+ delete_dirty_work_product(tcx, swp);
+ }
+ }
+ }
+}
+
+fn delete_dirty_work_product(tcx: TyCtxt,
+ swp: SerializedWorkProduct) {
+ debug!("delete_dirty_work_product({:?})", swp);
+ for &(_, ref file_name) in &swp.work_product.saved_files {
+ let path = in_incr_comp_dir(tcx.sess, file_name).unwrap();
+ match fs::remove_file(&path) {
+ Ok(()) => { }
+ Err(err) => {
+ tcx.sess.warn(
+ &format!("file-system error deleting outdated file `{}`: {}",
+ path.display(), err));
+ }
+ }
+ }
+}
mod load;
mod save;
mod util;
+mod work_product;
pub use self::load::load_dep_graph;
pub use self::save::save_dep_graph;
+pub use self::save::save_work_products;
+pub use self::work_product::save_trans_partition;
+pub use self::util::in_incr_comp_dir;
use rbml::opaque::Encoder;
use rustc::dep_graph::DepNode;
use rustc::middle::cstore::LOCAL_CRATE;
+use rustc::session::Session;
use rustc::ty::TyCtxt;
use rustc_serialize::{Encodable as RustcEncodable};
use std::hash::{Hasher, SipHasher};
use super::util::*;
pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+ debug!("save_dep_graph()");
let _ignore = tcx.dep_graph.in_ignore();
+ let sess = tcx.sess;
let mut hcx = HashContext::new(tcx);
- save_in(&mut hcx, dep_graph_path(tcx), encode_dep_graph);
- save_in(&mut hcx, metadata_hash_path(tcx, LOCAL_CRATE), encode_metadata_hashes);
+ save_in(sess, dep_graph_path(tcx), |e| encode_dep_graph(&mut hcx, e));
+ save_in(sess, metadata_hash_path(tcx, LOCAL_CRATE), |e| encode_metadata_hashes(&mut hcx, e));
}
-fn save_in<'a, 'tcx, F>(hcx: &mut HashContext<'a, 'tcx>,
- opt_path_buf: Option<PathBuf>,
- encode: F)
- where F: FnOnce(&mut HashContext<'a, 'tcx>, &mut Encoder) -> io::Result<()>
-{
- let tcx = hcx.tcx;
+pub fn save_work_products(sess: &Session, local_crate_name: &str) {
+ debug!("save_work_products()");
+ let _ignore = sess.dep_graph.in_ignore();
+ let path = sess_work_products_path(sess, local_crate_name);
+ save_in(sess, path, |e| encode_work_products(sess, e));
+}
+fn save_in<F>(sess: &Session,
+ opt_path_buf: Option<PathBuf>,
+ encode: F)
+ where F: FnOnce(&mut Encoder) -> io::Result<()>
+{
let path_buf = match opt_path_buf {
Some(p) => p,
None => return
match fs::remove_file(&path_buf) {
Ok(()) => { }
Err(err) => {
- tcx.sess.err(
+ sess.err(
&format!("unable to delete old dep-graph at `{}`: {}",
path_buf.display(), err));
return;
// generate the data in a memory buffer
let mut wr = Cursor::new(Vec::new());
- match encode(hcx, &mut Encoder::new(&mut wr)) {
+ match encode(&mut Encoder::new(&mut wr)) {
Ok(()) => { }
Err(err) => {
- tcx.sess.err(
+ sess.err(
&format!("could not encode dep-graph to `{}`: {}",
path_buf.display(), err));
return;
{
Ok(_) => { }
Err(err) => {
- tcx.sess.err(
+ sess.err(
&format!("failed to write dep-graph to `{}`: {}",
path_buf.display(), err));
return;
Ok(())
}
+
+pub fn encode_work_products(sess: &Session,
+ encoder: &mut Encoder)
+ -> io::Result<()>
+{
+ let work_products: Vec<_> =
+ sess.dep_graph.work_products()
+ .iter()
+ .map(|(id, work_product)| {
+ SerializedWorkProduct {
+ id: id.clone(),
+ work_product: work_product.clone(),
+ }
+ })
+ .collect();
+
+ work_products.encode(encoder)
+}
+
// except according to those terms.
use rustc::middle::cstore::LOCAL_CRATE;
+use rustc::session::Session;
use rustc::ty::TyCtxt;
use std::fs;
use syntax::ast;
pub fn dep_graph_path(tcx: TyCtxt) -> Option<PathBuf> {
- path(tcx, LOCAL_CRATE, "local")
+ tcx_path(tcx, LOCAL_CRATE, "local")
}
pub fn metadata_hash_path(tcx: TyCtxt, cnum: ast::CrateNum) -> Option<PathBuf> {
- path(tcx, cnum, "metadata")
+ tcx_path(tcx, cnum, "metadata")
}
-fn path(tcx: TyCtxt, cnum: ast::CrateNum, suffix: &str) -> Option<PathBuf> {
+pub fn tcx_work_products_path(tcx: TyCtxt) -> Option<PathBuf> {
+ let crate_name = tcx.crate_name(LOCAL_CRATE);
+ sess_work_products_path(tcx.sess, &crate_name)
+}
+
+pub fn sess_work_products_path(sess: &Session,
+ local_crate_name: &str)
+ -> Option<PathBuf> {
+ let crate_disambiguator = sess.local_crate_disambiguator();
+ path(sess, local_crate_name, &crate_disambiguator, "work-products")
+}
+
+pub fn in_incr_comp_dir(sess: &Session, file_name: &str) -> Option<PathBuf> {
+ sess.opts.incremental.as_ref().map(|incr_dir| incr_dir.join(file_name))
+}
+
+fn tcx_path(tcx: TyCtxt,
+ cnum: ast::CrateNum,
+ middle: &str)
+ -> Option<PathBuf> {
+ path(tcx.sess, &tcx.crate_name(cnum), &tcx.crate_disambiguator(cnum), middle)
+}
+
+fn path(sess: &Session,
+ crate_name: &str,
+ crate_disambiguator: &str,
+ middle: &str)
+ -> Option<PathBuf> {
// For now, just save/load dep-graph from
// directory/dep_graph.rbml
- tcx.sess.opts.incremental.as_ref().and_then(|incr_dir| {
+ sess.opts.incremental.as_ref().and_then(|incr_dir| {
match create_dir_racy(&incr_dir) {
Ok(()) => {}
Err(err) => {
- tcx.sess.err(
+ sess.err(
&format!("could not create the directory `{}`: {}",
incr_dir.display(), err));
return None;
}
}
- let crate_name = tcx.crate_name(cnum);
- let crate_disambiguator = tcx.crate_disambiguator(cnum);
- let file_name = format!("{}-{}.{}.bin",
- crate_name,
- crate_disambiguator,
- suffix);
+ let file_name = format!("{}-{}.{}.bin", crate_name, crate_disambiguator, middle);
+
Some(incr_dir.join(file_name))
})
}
--- /dev/null
+// Copyright 2012-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.
+
+//! This module contains files for saving intermediate work-products.
+
+use persist::util::*;
+use rustc::dep_graph::{WorkProduct, WorkProductId};
+use rustc::session::Session;
+use rustc::session::config::OutputType;
+use rustc::util::fs::link_or_copy;
+use std::path::PathBuf;
+use std::sync::Arc;
+
+pub fn save_trans_partition(sess: &Session,
+ cgu_name: &str,
+ partition_hash: u64,
+ files: &[(OutputType, PathBuf)]) {
+ debug!("save_trans_partition({:?},{},{:?})",
+ cgu_name,
+ partition_hash,
+ files);
+ if sess.opts.incremental.is_none() {
+ return;
+ }
+ let work_product_id = Arc::new(WorkProductId(cgu_name.to_string()));
+
+ let saved_files: Option<Vec<_>> =
+ files.iter()
+ .map(|&(kind, ref path)| {
+ let file_name = format!("cgu-{}.{}", cgu_name, kind.extension());
+ let path_in_incr_dir = in_incr_comp_dir(sess, &file_name).unwrap();
+ match link_or_copy(path, &path_in_incr_dir) {
+ Ok(_) => Some((kind, file_name)),
+ Err(err) => {
+ sess.warn(&format!("error copying object file `{}` \
+ to incremental directory as `{}`: {}",
+ path.display(),
+ path_in_incr_dir.display(),
+ err));
+ None
+ }
+ }
+ })
+ .collect();
+ let saved_files = match saved_files {
+ Some(v) => v,
+ None => return,
+ };
+
+ let work_product = WorkProduct {
+ input_hash: partition_hash,
+ saved_files: saved_files,
+ };
+
+ sess.dep_graph.insert_work_product(&work_product_id, work_product);
+}
use std::collections::HashSet;
use syntax::{ast};
-use syntax::attr::{self, AttrMetaMethods};
+use syntax::attr::{self, AttrMetaMethods, AttributeMethods};
use syntax_pos::{self, Span};
use rustc::hir::{self, PatKind};
}
}
- let has_doc = attrs.iter().any(|a| {
- match a.node.value.node {
- ast::MetaItemKind::NameValue(ref name, _) if *name == "doc" => true,
- _ => false
- }
- });
+ let has_doc = attrs.iter().any(|a| a.is_value_str() && a.name() == "doc");
if !has_doc {
cx.span_lint(MISSING_DOCS, sp,
&format!("missing documentation for {}", desc));
impl LateLintPass for UnstableFeatures {
fn check_attribute(&mut self, ctx: &LateContext, attr: &ast::Attribute) {
- if attr::contains_name(&[attr.node.value.clone()], "feature") {
- if let Some(items) = attr.node.value.meta_item_list() {
+ if attr::contains_name(&[attr.meta().clone()], "feature") {
+ if let Some(items) = attr.meta().meta_item_list() {
for item in items {
- ctx.span_lint(UNSTABLE_FEATURES, item.span, "unstable feature");
+ ctx.span_lint(UNSTABLE_FEATURES, item.span(), "unstable feature");
}
}
}
use rustc::hir;
use rustc::hir::fold;
use rustc::hir::fold::Folder;
-use rustc::hir::intravisit::{IdRange, IdRangeComputingVisitor, IdVisitingOperation};
+use rustc::hir::intravisit::{Visitor, IdRangeComputingVisitor, IdRange};
use common as c;
use cstore;
rbml_w: &'a mut Encoder<'b>,
}
-impl<'a, 'b, 'c, 'tcx> IdVisitingOperation for
+impl<'a, 'b, 'c, 'tcx, 'v> Visitor<'v> for
SideTableEncodingIdVisitor<'a, 'b, 'c, 'tcx> {
fn visit_id(&mut self, id: ast::NodeId) {
encode_side_tables_for_id(self.ecx, self.rbml_w, id)
rbml_w: &mut Encoder,
ii: &InlinedItem) {
rbml_w.start_tag(c::tag_table as usize);
- ii.visit_ids(&mut SideTableEncodingIdVisitor {
+ ii.visit(&mut SideTableEncodingIdVisitor {
ecx: ecx,
rbml_w: rbml_w
});
}
}
-fn inlined_item_id_range(v: &InlinedItem) -> IdRange {
+fn inlined_item_id_range(ii: &InlinedItem) -> IdRange {
let mut visitor = IdRangeComputingVisitor::new();
- v.visit_ids(&mut visitor);
+ ii.visit(&mut visitor);
visitor.result()
}
// Check for (potential) conflicts with the local crate
if self.local_crate_name == crate_name &&
- self.sess.crate_disambiguator.get().as_str() == disambiguator {
+ self.sess.local_crate_disambiguator() == disambiguator {
span_fatal!(self.sess, span, E0519,
"the current crate is indistinguishable from one of its \
dependencies: it has the same crate-name `{}` and was \
// an attribute
assert_eq!(meta_items.len(), 1);
let meta_item = meta_items.into_iter().nth(0).unwrap();
- codemap::Spanned {
- node: ast::Attribute_ {
- id: attr::mk_attr_id(),
- style: ast::AttrStyle::Outer,
- value: meta_item,
- is_sugared_doc: is_sugared_doc,
- },
- span: syntax_pos::DUMMY_SP
- }
+ attr::mk_doc_attr_outer(attr::mk_attr_id(), meta_item, is_sugared_doc)
}).collect()
},
None => vec![],
use std::u32;
use syntax::abi::Abi;
use syntax::ast::{self, NodeId, Name, CRATE_NODE_ID, CrateNum};
-use syntax::attr;
+use syntax::attr::{self,AttrMetaMethods,AttributeMethods};
use errors::Handler;
use syntax;
use syntax_pos::BytePos;
}
fn encode_meta_item(rbml_w: &mut Encoder, mi: &ast::MetaItem) {
- match mi.node {
- ast::MetaItemKind::Word(ref name) => {
+ if mi.is_word() {
+ let name = mi.name();
rbml_w.start_tag(tag_meta_item_word);
- rbml_w.wr_tagged_str(tag_meta_item_name, name);
+ rbml_w.wr_tagged_str(tag_meta_item_name, &name);
rbml_w.end_tag();
- }
- ast::MetaItemKind::NameValue(ref name, ref value) => {
- match value.node {
- ast::LitKind::Str(ref value, _) => {
- rbml_w.start_tag(tag_meta_item_name_value);
- rbml_w.wr_tagged_str(tag_meta_item_name, name);
- rbml_w.wr_tagged_str(tag_meta_item_value, value);
- rbml_w.end_tag();
- }
- _ => {/* FIXME (#623): encode other variants */ }
- }
- }
- ast::MetaItemKind::List(ref name, ref items) => {
+ } else if mi.is_value_str() {
+ let name = mi.name();
+ /* FIXME (#623): support other literal kinds */
+ let value = mi.value_str().unwrap();
+ rbml_w.start_tag(tag_meta_item_name_value);
+ rbml_w.wr_tagged_str(tag_meta_item_name, &name);
+ rbml_w.wr_tagged_str(tag_meta_item_value, &value);
+ rbml_w.end_tag();
+ } else { // it must be a list
+ let name = mi.name();
+ let items = mi.meta_item_list().unwrap();
rbml_w.start_tag(tag_meta_item_list);
- rbml_w.wr_tagged_str(tag_meta_item_name, name);
+ rbml_w.wr_tagged_str(tag_meta_item_name, &name);
for inner_item in items {
encode_meta_item(rbml_w, &inner_item);
}
rbml_w.end_tag();
- }
}
}
for attr in attrs {
rbml_w.start_tag(tag_attribute);
rbml_w.wr_tagged_u8(tag_attribute_is_sugared_doc, attr.node.is_sugared_doc as u8);
- encode_meta_item(rbml_w, &attr.node.value);
+ encode_meta_item(rbml_w, attr.meta());
rbml_w.end_tag();
}
rbml_w.end_tag();
encode_crate_name(rbml_w, &ecx.link_meta.crate_name);
encode_crate_triple(rbml_w, &ecx.tcx.sess.opts.target_triple);
encode_hash(rbml_w, &ecx.link_meta.crate_hash);
- encode_crate_disambiguator(rbml_w, &ecx.tcx.sess.crate_disambiguator.get().as_str());
+ encode_crate_disambiguator(rbml_w, &ecx.tcx.sess.local_crate_disambiguator());
encode_dylib_dependency_formats(rbml_w, &ecx);
encode_panic_strategy(rbml_w, &ecx);
}
if let (Some(sel), Some(names)) = (import.as_mut(), names) {
for attr in names {
- if let ast::MetaItemKind::Word(ref name) = attr.node {
- sel.insert(name.clone(), attr.span);
+ if attr.is_word() {
+ sel.insert(attr.name().clone(), attr.span());
} else {
- span_err!(self.sess, attr.span, E0466, "bad macro import");
+ span_err!(self.sess, attr.span(), E0466, "bad macro import");
}
}
}
};
for attr in names {
- if let ast::MetaItemKind::Word(ref name) = attr.node {
- reexport.insert(name.clone(), attr.span);
+ if attr.is_word() {
+ reexport.insert(attr.name().clone(), attr.span());
} else {
- call_bad_macro_reexport(self.sess, attr.span);
+ call_bad_macro_reexport(self.sess, attr.span());
}
}
}
build::construct_fn(cx, id, arguments, fn_sig.output, body)
});
- intravisit::walk_fn(self, fk, decl, body, span);
+ intravisit::walk_fn(self, fk, decl, body, span, id);
}
}
use rustc::middle::mem_categorization::Categorization;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::traits::ProjectionMode;
+use rustc::util::common::ErrorReported;
use rustc::util::nodemap::NodeMap;
use rustc::middle::const_qualif::ConstQualif;
use rustc::lint::builtin::CONST_ERR;
_ => self.tcx.sess.add_lint(CONST_ERR, expr.id, expr.span,
format!("constant evaluation error: {}. This will \
become a HARD ERROR in the future",
- err.description())),
+ err.description().into_oneline())),
}
}
self.with_mode(mode, |this| {
let qualif = self.with_mode(mode, |this| {
this.with_euv(Some(fn_id), |euv| euv.walk_fn(fd, b));
- intravisit::walk_fn(this, fk, fd, b, s);
+ intravisit::walk_fn(this, fk, fd, b, s, fn_id);
this.qualif
});
}
}
}
-
- fn msg(&self) -> &'static str {
- match self.mode {
- Mode::Const => "constant",
- Mode::ConstFn => "constant function",
- Mode::StaticMut | Mode::Static => "static",
- Mode::Var => bug!(),
- }
- }
}
impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
self.global_expr(Mode::Const, &start);
self.global_expr(Mode::Const, &end);
- match compare_lit_exprs(self.tcx, start, end) {
- Some(Ordering::Less) |
- Some(Ordering::Equal) => {}
- Some(Ordering::Greater) => {
+ match compare_lit_exprs(self.tcx, p.span, start, end) {
+ Ok(Ordering::Less) |
+ Ok(Ordering::Equal) => {}
+ Ok(Ordering::Greater) => {
span_err!(self.tcx.sess, start.span, E0030,
"lower range bound must be less than or equal to upper");
}
- None => {
- span_err!(self.tcx.sess, p.span, E0014,
- "paths in {}s may only refer to constants",
- self.msg());
- }
+ Err(ErrorReported) => {}
}
}
_ => intravisit::walk_pat(self, p)
Err(msg) => {
self.tcx.sess.add_lint(CONST_ERR, ex.id,
msg.span,
- msg.description().into_owned())
+ msg.description().into_oneline().into_owned())
}
}
}
#![allow(non_snake_case)]
register_long_diagnostics! {
-
+/*
E0014: r##"
Constants can only be initialized by a constant value or, in a future
version of Rust, a call to a const function. This error indicates the use
const FOO2: i32 = { 0 }; // but brackets are useless here
```
"##,
-
+*/
E0030: r##"
When matching against a range, the compiler verifies that the range is
non-empty. Range patterns include both end-points, so this is equivalent to
let mut euv = euv::ExprUseVisitor::new(&mut delegate, &infcx);
euv.walk_fn(fd, b);
});
- intravisit::walk_fn(self, fk, fd, b, s)
+ intravisit::walk_fn(self, fk, fd, b, s, fn_id)
}
}
}
}
- intravisit::walk_mod(self, m);
+ intravisit::walk_mod(self, m, id);
}
fn visit_macro_def(&mut self, md: &'v hir::MacroDef) {
Import {
binding: &'a NameBinding<'a>,
directive: &'a ImportDirective<'a>,
- // Some(error) if using this imported name causes the import to be a privacy error
- privacy_error: Option<Box<PrivacyError<'a>>>,
},
}
self.used_crates.insert(krate);
}
- let (directive, privacy_error) = match binding.kind {
- NameBindingKind::Import { directive, ref privacy_error, .. } =>
- (directive, privacy_error),
+ let directive = match binding.kind {
+ NameBindingKind::Import { directive, .. } => directive,
_ => return,
};
- if let Some(error) = privacy_error.as_ref() {
- self.privacy_errors.push((**error).clone());
- }
-
if !self.make_glob_map {
return;
}
let resolution = if let Some(resolution) = self.resolve_possibly_assoc_item(pat_id,
qself, path, namespace) {
if resolution.depth == 0 {
- if expected_fn(resolution.base_def) {
+ if expected_fn(resolution.base_def) || resolution.base_def == Def::Err {
resolution
} else {
resolve_error(
);
None
}
- Def::Local(..) | Def::Upvar(..) | Def::Fn(..) => {
+ Def::Local(..) | Def::Upvar(..) | Def::Fn(..) | Def::Err => {
// These entities are explicitly allowed
// to be shadowed by fresh bindings.
None
impl<'a> ImportDirective<'a> {
// Given the binding to which this directive resolves in a particular namespace,
// this returns the binding for the name this directive defines in that namespace.
- fn import(&'a self, binding: &'a NameBinding<'a>, privacy_error: Option<Box<PrivacyError<'a>>>)
- -> NameBinding<'a> {
+ fn import(&'a self, binding: &'a NameBinding<'a>) -> NameBinding<'a> {
NameBinding {
kind: NameBindingKind::Import {
binding: binding,
directive: self,
- privacy_error: privacy_error,
},
span: self.span,
vis: self.vis,
fn define_in_glob_importers(&self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>) {
if !binding.is_importable() || !binding.is_pseudo_public() { return }
for &(importer, directive) in self.glob_importers.borrow_mut().iter() {
- let _ = importer.try_define_child(name, ns, directive.import(binding, None));
+ let _ = importer.try_define_child(name, ns, directive.import(binding));
}
}
}
span: DUMMY_SP,
vis: ty::Visibility::Public,
});
- let dummy_binding = directive.import(dummy_binding, None);
+ let dummy_binding = directive.import(dummy_binding);
let _ = source_module.try_define_child(target, ValueNS, dummy_binding.clone());
let _ = source_module.try_define_child(target, TypeNS, dummy_binding);
self.resolver.resolve_name_in_module(target_module, source, TypeNS, false, true);
let module_ = self.resolver.current_module;
+ let mut privacy_error = true;
for &(ns, result, determined) in &[(ValueNS, &value_result, value_determined),
(TypeNS, &type_result, type_determined)] {
- if determined.get() { continue }
- if let Indeterminate = *result { continue }
-
- determined.set(true);
- if let Success(binding) = *result {
- if !binding.is_importable() {
+ match *result {
+ Failed(..) if !determined.get() => {
+ determined.set(true);
+ module_.update_resolution(target, ns, |resolution| {
+ resolution.single_imports.directive_failed()
+ });
+ }
+ Success(binding) if !binding.is_importable() => {
let msg = format!("`{}` is not directly importable", target);
span_err!(self.resolver.session, directive.span, E0253, "{}", &msg);
// Do not import this illegal binding. Import a dummy binding and pretend
self.import_dummy_binding(module_, directive);
return Success(());
}
-
- let privacy_error = if !self.resolver.is_accessible(binding.vis) {
- Some(Box::new(PrivacyError(directive.span, source, binding)))
- } else {
- None
- };
-
- let imported_binding = directive.import(binding, privacy_error);
- let conflict = module_.try_define_child(target, ns, imported_binding);
- if let Err(old_binding) = conflict {
- let binding = &directive.import(binding, None);
- self.resolver.report_conflict(module_, target, ns, binding, old_binding);
+ Success(binding) if !self.resolver.is_accessible(binding.vis) => {}
+ Success(binding) if !determined.get() => {
+ determined.set(true);
+ let imported_binding = directive.import(binding);
+ let conflict = module_.try_define_child(target, ns, imported_binding);
+ if let Err(old_binding) = conflict {
+ let binding = &directive.import(binding);
+ self.resolver.report_conflict(module_, target, ns, binding, old_binding);
+ }
+ privacy_error = false;
}
- } else {
- module_.update_resolution(target, ns, |resolution| {
- resolution.single_imports.directive_failed();
- });
+ Success(_) => privacy_error = false,
+ _ => {}
}
}
_ => (),
}
+ if privacy_error {
+ for &(ns, result) in &[(ValueNS, &value_result), (TypeNS, &type_result)] {
+ let binding = match *result { Success(binding) => binding, _ => continue };
+ self.resolver.privacy_errors.push(PrivacyError(directive.span, source, binding));
+ let _ = module_.try_define_child(target, ns, directive.import(binding));
+ }
+ }
+
match (&value_result, &type_result) {
(&Success(binding), _) if !binding.pseudo_vis()
.is_at_least(directive.vis, self.resolver) &&
_ => {}
}
- // Report a privacy error here if all successful namespaces are privacy errors.
- let mut privacy_error = None;
- for &ns in &[ValueNS, TypeNS] {
- privacy_error = match module_.resolve_name(target, ns, true) {
- Success(&NameBinding {
- kind: NameBindingKind::Import { ref privacy_error, .. }, ..
- }) => privacy_error.as_ref().map(|error| (**error).clone()),
- _ => continue,
- };
- if privacy_error.is_none() { break }
- }
- privacy_error.map(|error| self.resolver.privacy_errors.push(error));
-
// Record what this import resolves to for later uses in documentation,
// this may resolve to either a value or a type, but for documentation
// purposes it's good enough to just favor one over the other.
}).collect::<Vec<_>>();
for ((name, ns), binding) in bindings {
if binding.is_importable() && binding.is_pseudo_public() {
- let _ = module_.try_define_child(name, ns, directive.import(binding, None));
+ let _ = module_.try_define_child(name, ns, directive.import(binding));
}
}
use llvm::{ValueRef, BasicBlockRef};
use rustc_const_eval::check_match::{self, Constructor, StaticInliner};
-use rustc_const_eval::{compare_lit_exprs, eval_const_expr};
+use rustc_const_eval::{compare_lit_exprs, eval_const_expr, fatal_const_eval_err};
use rustc::hir::def::{Def, DefMap};
use rustc::hir::def_id::DefId;
use middle::expr_use_visitor as euv;
impl<'a> ConstantExpr<'a> {
fn eq<'b, 'tcx>(self, other: ConstantExpr<'a>, tcx: TyCtxt<'b, 'tcx, 'tcx>) -> bool {
- match compare_lit_exprs(tcx, self.0, other.0) {
- Some(result) => result == Ordering::Equal,
- None => bug!("compare_list_exprs: type mismatch"),
+ match compare_lit_exprs(tcx, self.0.span, self.0, other.0) {
+ Ok(result) => result == Ordering::Equal,
+ Err(_) => bug!("compare_list_exprs: type mismatch"),
}
}
}
let expr = consts::const_expr(ccx, &lit_expr, bcx.fcx.param_substs, None, Yes);
let llval = match expr {
Ok((llval, _)) => llval,
- Err(err) => bcx.ccx().sess().span_fatal(lit_expr.span, &err.description()),
+ Err(err) => {
+ fatal_const_eval_err(bcx.tcx(), err.as_inner(), lit_expr.span, "pattern");
+ }
};
let lit_datum = immediate_rvalue(llval, lit_ty);
let lit_datum = unpack_datum!(bcx, lit_datum.to_appropriate_datum(bcx));
ConstantRange(ConstantExpr(ref l1), ConstantExpr(ref l2), _) => {
let l1 = match consts::const_expr(ccx, &l1, bcx.fcx.param_substs, None, Yes) {
Ok((l1, _)) => l1,
- Err(err) => bcx.ccx().sess().span_fatal(l1.span, &err.description()),
+ Err(err) => fatal_const_eval_err(bcx.tcx(), err.as_inner(), l1.span, "pattern"),
};
let l2 = match consts::const_expr(ccx, &l2, bcx.fcx.param_substs, None, Yes) {
Ok((l2, _)) => l2,
- Err(err) => bcx.ccx().sess().span_fatal(l2.span, &err.description()),
+ Err(err) => fatal_const_eval_err(bcx.tcx(), err.as_inner(), l2.span, "pattern"),
};
RangeResult(Result::new(bcx, l1), Result::new(bcx, l2))
}
--- /dev/null
+// Copyright 2012-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.
+
+//! This pass is only used for UNIT TESTS related to incremental
+//! compilation. It tests whether a particular `.o` file will be re-used
+//! from a previous compilation or whether it must be regenerated.
+//!
+//! The user adds annotations to the crate of the following form:
+//!
+//! ```
+//! #![rustc_partition_reused(module="spike", cfg="rpass2")]
+//! #![rustc_partition_translated(module="spike-x", cfg="rpass2")]
+//! ```
+//!
+//! The first indicates (in the cfg `rpass2`) that `spike.o` will be
+//! reused, the second that `spike-x.o` will be recreated. If these
+//! annotations are inaccurate, errors are reported.
+//!
+//! The reason that we use `cfg=...` and not `#[cfg_attr]` is so that
+//! the HIR doesn't change as a result of the annotations, which might
+//! perturb the reuse results.
+
+use rustc::ty::TyCtxt;
+use syntax::ast;
+use syntax::attr::AttrMetaMethods;
+use syntax::parse::token::InternedString;
+
+use {ModuleSource, ModuleTranslation};
+
+const PARTITION_REUSED: &'static str = "rustc_partition_reused";
+const PARTITION_TRANSLATED: &'static str = "rustc_partition_translated";
+
+const MODULE: &'static str = "module";
+const CFG: &'static str = "cfg";
+
+#[derive(Debug, PartialEq)]
+enum Disposition { Reused, Translated }
+
+pub fn assert_module_sources<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ modules: &[ModuleTranslation]) {
+ let _ignore = tcx.dep_graph.in_ignore();
+
+ if tcx.sess.opts.incremental.is_none() {
+ return;
+ }
+
+ let ams = AssertModuleSource { tcx: tcx, modules: modules };
+ for attr in &tcx.map.krate().attrs {
+ ams.check_attr(attr);
+ }
+}
+
+struct AssertModuleSource<'a, 'tcx: 'a> {
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ modules: &'a [ModuleTranslation],
+}
+
+impl<'a, 'tcx> AssertModuleSource<'a, 'tcx> {
+ fn check_attr(&self, attr: &ast::Attribute) {
+ let disposition = if attr.check_name(PARTITION_REUSED) {
+ Disposition::Reused
+ } else if attr.check_name(PARTITION_TRANSLATED) {
+ Disposition::Translated
+ } else {
+ return;
+ };
+
+ if !self.check_config(attr) {
+ debug!("check_attr: config does not match, ignoring attr");
+ return;
+ }
+
+ let mname = self.field(attr, MODULE);
+ let mtrans = self.modules.iter().find(|mtrans| &mtrans.name[..] == &mname[..]);
+ let mtrans = match mtrans {
+ Some(m) => m,
+ None => {
+ debug!("module name `{}` not found amongst:", mname);
+ for mtrans in self.modules {
+ debug!("module named `{}` with disposition {:?}",
+ mtrans.name,
+ self.disposition(mtrans));
+ }
+
+ self.tcx.sess.span_err(
+ attr.span,
+ &format!("no module named `{}`", mname));
+ return;
+ }
+ };
+
+ let mtrans_disposition = self.disposition(mtrans);
+ if disposition != mtrans_disposition {
+ self.tcx.sess.span_err(
+ attr.span,
+ &format!("expected module named `{}` to be {:?} but is {:?}",
+ mname,
+ disposition,
+ mtrans_disposition));
+ }
+ }
+
+ fn disposition(&self, mtrans: &ModuleTranslation) -> Disposition {
+ match mtrans.source {
+ ModuleSource::Preexisting(_) => Disposition::Reused,
+ ModuleSource::Translated(_) => Disposition::Translated,
+ }
+ }
+
+ fn field(&self, attr: &ast::Attribute, name: &str) -> InternedString {
+ for item in attr.meta_item_list().unwrap_or(&[]) {
+ if item.check_name(name) {
+ if let Some(value) = item.value_str() {
+ return value;
+ } else {
+ self.tcx.sess.span_fatal(
+ item.span,
+ &format!("associated value expected for `{}`", name));
+ }
+ }
+ }
+
+ self.tcx.sess.span_fatal(
+ attr.span,
+ &format!("no field `{}`", name));
+ }
+
+ /// Scan for a `cfg="foo"` attribute and check whether we have a
+ /// cfg flag called `foo`.
+ fn check_config(&self, attr: &ast::Attribute) -> bool {
+ let config = &self.tcx.map.krate().config;
+ let value = self.field(attr, CFG);
+ debug!("check_config(config={:?}, value={:?})", config, value);
+ if config.iter().any(|c| c.check_name(&value[..])) {
+ debug!("check_config: matched");
+ return true;
+ }
+ debug!("check_config: no match found");
+ return false;
+ }
+
+}
use back::lto;
use back::link::{get_linker, remove};
+use rustc_incremental::save_trans_partition;
use session::config::{OutputFilenames, Passes, SomePasses, AllPasses};
use session::Session;
use session::config::{self, OutputType};
use llvm;
use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef, ContextRef};
use llvm::SMDiagnosticRef;
-use {CrateTranslation, ModuleTranslation};
+use {CrateTranslation, ModuleLlvm, ModuleSource, ModuleTranslation};
use util::common::time;
use util::common::path2cstr;
+use util::fs::link_or_copy;
use errors::{self, Handler, Level, DiagnosticBuilder};
use errors::emitter::Emitter;
use syntax_pos::MultiSpan;
remark: Passes,
// Worker thread number
worker: usize,
+ // Directory where incremental data is stored (if any)
+ incremental: Option<PathBuf>,
}
impl<'a> CodegenContext<'a> {
plugin_passes: sess.plugin_llvm_passes.borrow().clone(),
remark: sess.opts.cg.remark.clone(),
worker: 0,
+ incremental: sess.opts.incremental.clone(),
}
}
}
// Unsafe due to LLVM calls.
unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
mtrans: ModuleTranslation,
+ mllvm: ModuleLlvm,
config: ModuleConfig,
output_names: OutputFilenames) {
- let llmod = mtrans.llmod;
- let llcx = mtrans.llcx;
+ let llmod = mllvm.llmod;
+ let llcx = mllvm.llcx;
let tm = config.tm;
// llcx doesn't outlive this function, so we can put this on the stack.
if copy_bc_to_obj {
debug!("copying bitcode {:?} to obj {:?}", bc_out, obj_out);
- if let Err(e) = fs::copy(&bc_out, &obj_out) {
+ if let Err(e) = link_or_copy(&bc_out, &obj_out) {
cgcx.handler.err(&format!("failed to copy bitcode to object file: {}", e));
}
}
pub fn cleanup_llvm(trans: &CrateTranslation) {
for module in trans.modules.iter() {
unsafe {
- llvm::LLVMDisposeModule(module.llmod);
- llvm::LLVMContextDispose(module.llcx);
+ match module.source {
+ ModuleSource::Translated(llvm) => {
+ llvm::LLVMDisposeModule(llvm.llmod);
+ llvm::LLVMContextDispose(llvm.llcx);
+ }
+ ModuleSource::Preexisting(_) => {
+ }
+ }
}
}
}
run_work_multithreaded(sess, work_items, num_workers);
}
+ // If in incr. comp. mode, preserve the `.o` files for potential re-use
+ for mtrans in trans.modules.iter() {
+ let mut files = vec![];
+
+ if modules_config.emit_obj {
+ let path = crate_output.temp_path(OutputType::Object, Some(&mtrans.name));
+ files.push((OutputType::Object, path));
+ }
+
+ if modules_config.emit_bc {
+ let path = crate_output.temp_path(OutputType::Bitcode, Some(&mtrans.name));
+ files.push((OutputType::Bitcode, path));
+ }
+
+ save_trans_partition(sess, &mtrans.name, mtrans.symbol_name_hash, &files);
+ }
+
// All codegen is finished.
unsafe {
llvm::LLVMRustDisposeTargetMachine(tm);
fn execute_work_item(cgcx: &CodegenContext,
work_item: WorkItem) {
unsafe {
- optimize_and_codegen(cgcx,
- work_item.mtrans,
- work_item.config,
- work_item.output_names);
+ match work_item.mtrans.source {
+ ModuleSource::Translated(mllvm) => {
+ debug!("llvm-optimizing {:?}", work_item.mtrans.name);
+ optimize_and_codegen(cgcx,
+ work_item.mtrans,
+ mllvm,
+ work_item.config,
+ work_item.output_names);
+ }
+ ModuleSource::Preexisting(wp) => {
+ let incremental = cgcx.incremental.as_ref().unwrap();
+ let name = &work_item.mtrans.name;
+ for (kind, saved_file) in wp.saved_files {
+ let obj_out = work_item.output_names.temp_path(kind, Some(name));
+ let source_file = incremental.join(&saved_file);
+ debug!("copying pre-existing module `{}` from {:?} to {}",
+ work_item.mtrans.name,
+ source_file,
+ obj_out.display());
+ match link_or_copy(&source_file, &obj_out) {
+ Ok(()) => { }
+ Err(err) => {
+ cgcx.handler.err(&format!("unable to copy {} to {}: {}",
+ source_file.display(),
+ obj_out.display(),
+ err));
+ }
+ }
+ }
+ }
+ }
}
}
let mut tx = Some(tx);
futures.push(rx);
+ let incremental = sess.opts.incremental.clone();
+
thread::Builder::new().name(format!("codegen-{}", i)).spawn(move || {
let diag_handler = Handler::with_emitter(true, false, box diag_emitter);
plugin_passes: plugin_passes,
remark: remark,
worker: i,
+ incremental: incremental,
};
loop {
#![allow(non_camel_case_types)]
use super::CrateTranslation;
+use super::ModuleLlvm;
+use super::ModuleSource;
use super::ModuleTranslation;
+use assert_module_sources;
use back::link;
use back::linker::LinkerInfo;
use llvm::{BasicBlockRef, Linkage, ValueRef, Vector, get_param};
use rustc::traits;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::ty::adjustment::CustomCoerceUnsized;
-use rustc::dep_graph::DepNode;
+use rustc::dep_graph::{DepNode, WorkProduct};
use rustc::hir::map as hir_map;
use rustc::util::common::time;
use rustc::mir::mir_map::MirMap;
let instance = Instance::mono(ccx.shared(), main_def_id);
- if !ccx.codegen_unit().items.contains_key(&TransItem::Fn(instance)) {
+ if !ccx.codegen_unit().contains_item(&TransItem::Fn(instance)) {
// We want to create the wrapper in the same codegen unit as Rust's main
// function.
return;
/// Find any symbols that are defined in one compilation unit, but not declared
/// in any other compilation unit. Give these symbols internal linkage.
-fn internalize_symbols<'a, 'tcx>(ccxs: &CrateContextList<'a, 'tcx>,
+fn internalize_symbols<'a, 'tcx>(sess: &Session,
+ ccxs: &CrateContextList<'a, 'tcx>,
symbol_map: &SymbolMap<'tcx>,
reachable: &FnvHashSet<&str>) {
let scx = ccxs.shared();
let tcx = scx.tcx();
+ // In incr. comp. mode, we can't necessarily see all refs since we
+ // don't generate LLVM IR for reused modules, so skip this
+ // step. Later we should get smarter.
+ if sess.opts.debugging_opts.incremental.is_some() {
+ return;
+ }
+
// 'unsafe' because we are holding on to CStr's from the LLVM module within
// this block.
unsafe {
// Collect all symbols that need to stay externally visible because they
// are referenced via a declaration in some other codegen unit.
- for ccx in ccxs.iter() {
+ for ccx in ccxs.iter_need_trans() {
for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) {
let linkage = llvm::LLVMGetLinkage(val);
// We only care about external declarations (not definitions)
// Examine each external definition. If the definition is not used in
// any other compilation unit, and is not reachable from other crates,
// then give it internal linkage.
- for ccx in ccxs.iter() {
+ for ccx in ccxs.iter_need_trans() {
for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) {
let linkage = llvm::LLVMGetLinkage(val);
"\x01__imp_"
};
unsafe {
- for ccx in cx.iter() {
+ for ccx in cx.iter_need_trans() {
let exported: Vec<_> = iter_globals(ccx.llmod())
.filter(|&val| {
llvm::LLVMGetLinkage(val) ==
let metadata_module = ModuleTranslation {
name: "metadata".to_string(),
- llcx: shared_ccx.metadata_llcx(),
- llmod: shared_ccx.metadata_llmod(),
+ symbol_name_hash: 0, // we always rebuild metadata, at least for now
+ source: ModuleSource::Translated(ModuleLlvm {
+ llcx: shared_ccx.metadata_llcx(),
+ llmod: shared_ccx.metadata_llmod(),
+ }),
};
let no_builtins = attr::contains_name(&krate.attrs, "no_builtins");
let symbol_map = Rc::new(symbol_map);
+ let previous_work_products = trans_reuse_previous_work_products(tcx,
+ &codegen_units,
+ &symbol_map);
+
let crate_context_list = CrateContextList::new(&shared_ccx,
codegen_units,
+ previous_work_products,
symbol_map.clone());
- let modules = crate_context_list.iter()
- .map(|ccx| ModuleTranslation {
- name: String::from(&ccx.codegen_unit().name[..]),
- llcx: ccx.llcx(),
- llmod: ccx.llmod()
+ let modules: Vec<_> = crate_context_list.iter_all()
+ .map(|ccx| {
+ let source = match ccx.previous_work_product() {
+ Some(buf) => ModuleSource::Preexisting(buf.clone()),
+ None => ModuleSource::Translated(ModuleLlvm {
+ llcx: ccx.llcx(),
+ llmod: ccx.llmod(),
+ }),
+ };
+
+ ModuleTranslation {
+ name: String::from(ccx.codegen_unit().name()),
+ symbol_name_hash: ccx.codegen_unit().compute_symbol_name_hash(tcx, &symbol_map),
+ source: source,
+ }
})
.collect();
+ assert_module_sources::assert_module_sources(tcx, &modules);
+
// Skip crate items and just output metadata in -Z no-trans mode.
if tcx.sess.opts.no_trans {
let linker_info = LinkerInfo::new(&shared_ccx, &[]);
}
// Instantiate translation items without filling out definitions yet...
- for ccx in crate_context_list.iter() {
- let trans_items = ccx.codegen_unit()
- .items_in_deterministic_order(tcx, &symbol_map);
+ for ccx in crate_context_list.iter_need_trans() {
+ let cgu = ccx.codegen_unit();
+ let trans_items = cgu.items_in_deterministic_order(tcx, &symbol_map);
- for (trans_item, linkage) in trans_items {
- trans_item.predefine(&ccx, linkage);
- }
+ tcx.dep_graph.with_task(cgu.work_product_dep_node(), || {
+ for (trans_item, linkage) in trans_items {
+ trans_item.predefine(&ccx, linkage);
+ }
+ });
}
// ... and now that we have everything pre-defined, fill out those definitions.
- for ccx in crate_context_list.iter() {
- let trans_items = ccx.codegen_unit()
- .items_in_deterministic_order(tcx, &symbol_map);
-
- for (trans_item, _) in trans_items {
- trans_item.define(&ccx);
- }
+ for ccx in crate_context_list.iter_need_trans() {
+ let cgu = ccx.codegen_unit();
+ let trans_items = cgu.items_in_deterministic_order(tcx, &symbol_map);
+ tcx.dep_graph.with_task(cgu.work_product_dep_node(), || {
+ for (trans_item, _) in trans_items {
+ trans_item.define(&ccx);
+ }
- // If this codegen unit contains the main function, also create the
- // wrapper here
- maybe_create_entry_wrapper(&ccx);
+ // If this codegen unit contains the main function, also create the
+ // wrapper here
+ maybe_create_entry_wrapper(&ccx);
- // Run replace-all-uses-with for statics that need it
- for &(old_g, new_g) in ccx.statics_to_rauw().borrow().iter() {
- unsafe {
- let bitcast = llvm::LLVMConstPointerCast(new_g, llvm::LLVMTypeOf(old_g));
- llvm::LLVMReplaceAllUsesWith(old_g, bitcast);
- llvm::LLVMDeleteGlobal(old_g);
+ // Run replace-all-uses-with for statics that need it
+ for &(old_g, new_g) in ccx.statics_to_rauw().borrow().iter() {
+ unsafe {
+ let bitcast = llvm::LLVMConstPointerCast(new_g, llvm::LLVMTypeOf(old_g));
+ llvm::LLVMReplaceAllUsesWith(old_g, bitcast);
+ llvm::LLVMDeleteGlobal(old_g);
+ }
}
- }
- // Finalize debuginfo
- if ccx.sess().opts.debuginfo != NoDebugInfo {
- debuginfo::finalize(&ccx);
- }
+ // Finalize debuginfo
+ if ccx.sess().opts.debuginfo != NoDebugInfo {
+ debuginfo::finalize(&ccx);
+ }
+ });
}
symbol_names_test::report_symbol_names(&shared_ccx);
}
time(shared_ccx.sess().time_passes(), "internalize symbols", || {
- internalize_symbols(&crate_context_list,
+ internalize_symbols(sess,
+ &crate_context_list,
&symbol_map,
&reachable_symbols.iter()
.map(|s| &s[..])
}
}
+/// For each CGU, identify if we can reuse an existing object file (or
+/// maybe other context).
+fn trans_reuse_previous_work_products(tcx: TyCtxt,
+ codegen_units: &[CodegenUnit],
+ symbol_map: &SymbolMap)
+ -> Vec<Option<WorkProduct>> {
+ debug!("trans_reuse_previous_work_products()");
+ codegen_units
+ .iter()
+ .map(|cgu| {
+ let id = cgu.work_product_id();
+
+ let hash = cgu.compute_symbol_name_hash(tcx, symbol_map);
+
+ debug!("trans_reuse_previous_work_products: id={:?} hash={}", id, hash);
+
+ if let Some(work_product) = tcx.dep_graph.previous_work_product(&id) {
+ if work_product.input_hash == hash {
+ debug!("trans_reuse_previous_work_products: reusing {:?}", work_product);
+ return Some(work_product);
+ } else {
+ debug!("trans_reuse_previous_work_products: \
+ not reusing {:?} because hash changed to {:?}",
+ work_product, hash);
+ }
+ }
+
+ None
+ })
+ .collect()
+}
+
fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>)
-> (Vec<CodegenUnit<'tcx>>, SymbolMap<'tcx>) {
let time_passes = scx.sess().time_passes();
let mut item_to_cgus = HashMap::new();
for cgu in &codegen_units {
- for (&trans_item, &linkage) in &cgu.items {
+ for (&trans_item, &linkage) in cgu.items() {
item_to_cgus.entry(trans_item)
.or_insert(Vec::new())
- .push((cgu.name.clone(), linkage));
+ .push((cgu.name().clone(), linkage));
}
}
use llvm::{InternalLinkage, ValueRef, Bool, True};
use middle::const_qualif::ConstQualif;
use rustc_const_eval::{ConstEvalErr, lookup_const_fn_by_id, lookup_const_by_id, ErrKind};
-use rustc_const_eval::eval_repeat_count;
+use rustc_const_eval::{eval_length, report_const_eval_err, note_const_eval_err};
use rustc::hir::def::Def;
use rustc::hir::def_id::DefId;
use rustc::hir::map as hir_map;
use rustc::hir;
use std::ffi::{CStr, CString};
-use std::borrow::Cow;
use libc::c_uint;
use syntax::ast::{self, LitKind};
use syntax::attr::{self, AttrMetaMethods};
Compiletime(e) => e,
}
}
- pub fn description(&self) -> Cow<str> {
+
+ pub fn as_inner(&self) -> &ConstEvalErr {
match self {
- &Runtime(ref e) => e.description(),
- &Compiletime(ref e) => e.description(),
+ &Runtime(ref e) => e,
+ &Compiletime(ref e) => e,
}
}
}
let empty_substs = ccx.tcx().mk_substs(Substs::empty());
match get_const_expr_as_global(ccx, expr, ConstQualif::empty(), empty_substs, TrueConst::Yes) {
Err(Runtime(err)) => {
- ccx.tcx().sess.span_err(expr.span, &err.description());
+ report_const_eval_err(ccx.tcx(), &err, expr.span, "expression").emit();
Err(Compiletime(err))
},
other => other,
(Ok(x), _) => Ok(x),
(Err(err), TrueConst::Yes) => {
let err = ConstEvalErr{ span: span, kind: err };
- cx.tcx().sess.span_err(span, &err.description());
+ report_const_eval_err(cx.tcx(), &err, span, "expression").emit();
Err(Compiletime(err))
},
(Err(err), TrueConst::No) => {
let err = ConstEvalErr{ span: span, kind: err };
- cx.tcx().sess.span_warn(span, &err.description());
+ let mut diag = cx.tcx().sess.struct_span_warn(
+ span, "this expression will panic at run-time");
+ note_const_eval_err(cx.tcx(), &err, span, "expression", &mut diag);
+ diag.emit();
Err(Runtime(err))
},
}
hir::ExprRepeat(ref elem, ref count) => {
let unit_ty = ety.sequence_element_type(cx.tcx());
let llunitty = type_of::type_of(cx, unit_ty);
- let n = eval_repeat_count(cx.tcx(), count);
+ let n = eval_length(cx.tcx(), count, "repeat count").unwrap();
let unit_val = const_expr(cx, &elem, param_substs, fn_args, trueconst)?.0;
let vs = vec![unit_val; n];
if val_ty(unit_val) != llunitty {
assert!(!ccx.external_srcs().borrow().contains_key(&id));
let defined_in_current_codegen_unit = ccx.codegen_unit()
- .items
+ .items()
.contains_key(&TransItem::Static(id));
if defined_in_current_codegen_unit {
if declare::get_declared_value(ccx, sym).is_none() {
use llvm;
use llvm::{ContextRef, ModuleRef, ValueRef, BuilderRef};
-use rustc::dep_graph::{DepNode, DepTrackingMap, DepTrackingMapConfig};
+use rustc::dep_graph::{DepNode, DepTrackingMap, DepTrackingMapConfig, WorkProduct};
use middle::cstore::LinkMeta;
use rustc::hir::def::ExportMap;
use rustc::hir::def_id::DefId;
pub struct LocalCrateContext<'tcx> {
llmod: ModuleRef,
llcx: ContextRef,
+ previous_work_product: Option<WorkProduct>,
tn: TypeNames, // FIXME: This seems to be largely unused.
codegen_unit: CodegenUnit<'tcx>,
needs_unwind_cleanup_cache: RefCell<FnvHashMap<Ty<'tcx>, bool>>,
}
impl<'a, 'tcx: 'a> CrateContextList<'a, 'tcx> {
-
pub fn new(shared_ccx: &'a SharedCrateContext<'a, 'tcx>,
codegen_units: Vec<CodegenUnit<'tcx>>,
+ previous_work_products: Vec<Option<WorkProduct>>,
symbol_map: Rc<SymbolMap<'tcx>>)
-> CrateContextList<'a, 'tcx> {
CrateContextList {
shared: shared_ccx,
- local_ccxs: codegen_units.into_iter().map(|codegen_unit| {
- LocalCrateContext::new(shared_ccx, codegen_unit, symbol_map.clone())
+ local_ccxs: codegen_units.into_iter().zip(previous_work_products).map(|(cgu, wp)| {
+ LocalCrateContext::new(shared_ccx, cgu, wp, symbol_map.clone())
}).collect()
}
}
- pub fn iter<'b>(&'b self) -> CrateContextIterator<'b, 'tcx> {
+ /// Iterate over all crate contexts, whether or not they need
+ /// translation. That is, whether or not a `.o` file is available
+ /// for re-use from a previous incr. comp.).
+ pub fn iter_all<'b>(&'b self) -> CrateContextIterator<'b, 'tcx> {
CrateContextIterator {
shared: self.shared,
index: 0,
- local_ccxs: &self.local_ccxs[..]
+ local_ccxs: &self.local_ccxs[..],
+ filter_to_previous_work_product_unavail: false,
+ }
+ }
+
+ /// Iterator over all CCX that need translation (cannot reuse results from
+ /// previous incr. comp.).
+ pub fn iter_need_trans<'b>(&'b self) -> CrateContextIterator<'b, 'tcx> {
+ CrateContextIterator {
+ shared: self.shared,
+ index: 0,
+ local_ccxs: &self.local_ccxs[..],
+ filter_to_previous_work_product_unavail: true,
}
}
shared: &'a SharedCrateContext<'a, 'tcx>,
local_ccxs: &'a [LocalCrateContext<'tcx>],
index: usize,
+
+ /// if true, only return results where `previous_work_product` is none
+ filter_to_previous_work_product_unavail: bool,
}
impl<'a, 'tcx> Iterator for CrateContextIterator<'a,'tcx> {
type Item = CrateContext<'a, 'tcx>;
fn next(&mut self) -> Option<CrateContext<'a, 'tcx>> {
- if self.index >= self.local_ccxs.len() {
- return None;
- }
+ loop {
+ if self.index >= self.local_ccxs.len() {
+ return None;
+ }
- let index = self.index;
- self.index += 1;
+ let index = self.index;
+ self.index += 1;
- Some(CrateContext {
- shared: self.shared,
- index: index,
- local_ccxs: self.local_ccxs,
- })
+ let ccx = CrateContext {
+ shared: self.shared,
+ index: index,
+ local_ccxs: self.local_ccxs,
+ };
+
+ if
+ self.filter_to_previous_work_product_unavail &&
+ ccx.previous_work_product().is_some()
+ {
+ continue;
+ }
+
+ return Some(ccx);
+ }
}
}
impl<'tcx> LocalCrateContext<'tcx> {
fn new<'a>(shared: &SharedCrateContext<'a, 'tcx>,
codegen_unit: CodegenUnit<'tcx>,
+ previous_work_product: Option<WorkProduct>,
symbol_map: Rc<SymbolMap<'tcx>>)
-> LocalCrateContext<'tcx> {
unsafe {
// crashes if the module identifier is same as other symbols
// such as a function name in the module.
// 1. http://llvm.org/bugs/show_bug.cgi?id=11479
- let llmod_id = format!("{}.rs", codegen_unit.name);
+ let llmod_id = format!("{}.rs", codegen_unit.name());
let (llcx, llmod) = create_context_and_module(&shared.tcx.sess,
&llmod_id[..]);
let local_ccx = LocalCrateContext {
llmod: llmod,
llcx: llcx,
+ previous_work_product: previous_work_product,
codegen_unit: codegen_unit,
tn: TypeNames::new(),
needs_unwind_cleanup_cache: RefCell::new(FnvHashMap()),
self.local().llcx
}
+ pub fn previous_work_product(&self) -> Option<&WorkProduct> {
+ self.local().previous_work_product.as_ref()
+ }
+
pub fn codegen_unit(&self) -> &CodegenUnit<'tcx> {
&self.local().codegen_unit
}
Falling back to on-demand instantiation.",
g,
TransItem::DropGlue(g).to_raw_string(),
- ccx.codegen_unit().name);
+ ccx.codegen_unit().name());
ccx.stats().n_fallback_instantiations.set(ccx.stats()
.n_fallback_instantiations
use rustc::ty::subst::FnSpace;
use abi::{Abi, FnType};
use adt;
-use attributes;
use base::*;
use build::*;
use callee::{self, Callee};
use type_::Type;
use rustc::ty::{self, Ty};
use Disr;
-use rustc::ty::subst::Substs;
use rustc::hir;
use syntax::ast;
use syntax::ptr::P;
use syntax::parse::token;
use rustc::session::Session;
+use rustc_const_eval::fatal_const_eval_err;
use syntax_pos::{Span, DUMMY_SP};
use std::cmp::Ordering;
dloc: DebugLoc) -> Block<'blk, 'tcx> {
let llfn = get_rust_try_fn(bcx.fcx, &mut |bcx| {
let ccx = bcx.ccx();
- let tcx = ccx.tcx();
let dloc = DebugLoc::None;
// Translates the shims described above:
// expected to be `*mut *mut u8` for this to actually work, but that's
// managed by the standard library.
- attributes::emit_uwtable(bcx.fcx.llfn, true);
- let target = &bcx.sess().target.target;
- let catch_pers = if target.arch == "arm" && target.target_os != "ios" {
- // Only ARM still uses a separate catch personality (for now)
- match tcx.lang_items.eh_personality_catch() {
- Some(did) => {
- Callee::def(ccx, did, tcx.mk_substs(Substs::empty())).reify(ccx).val
- }
- None => bug!("eh_personality_catch not defined"),
- }
- } else {
- bcx.fcx.eh_personality()
- };
-
let then = bcx.fcx.new_temp_block("then");
let catch = bcx.fcx.new_temp_block("catch");
// rust_try ignores the selector.
let lpad_ty = Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)],
false);
- let vals = LandingPad(catch, lpad_ty, catch_pers, 1);
+ let vals = LandingPad(catch, lpad_ty, bcx.fcx.eh_personality(), 1);
AddClause(catch, vals, C_null(Type::i8p(ccx)));
let ptr = ExtractValue(catch, vals, 0);
Store(catch, ptr, BitCast(catch, local_ptr, Type::i8p(ccx).ptr_to()));
// this should probably help simd error reporting
consts::TrueConst::Yes) {
Ok((vector, _)) => vector,
- Err(err) => bcx.sess().span_fatal(span, &err.description()),
+ Err(err) => {
+ fatal_const_eval_err(bcx.tcx(), err.as_inner(), span,
+ "shuffle indices");
+ }
}
}
None => llargs[2]
#![feature(unicode)]
#![feature(question_mark)]
+use rustc::dep_graph::WorkProduct;
+
extern crate arena;
extern crate flate;
extern crate getopts;
mod abi;
mod adt;
mod asm;
+mod assert_module_sources;
mod attributes;
mod base;
mod basic_block;
#[derive(Clone)]
pub struct ModuleTranslation {
+ /// The name of the module. When the crate may be saved between
+ /// compilations, incremental compilation requires that name be
+ /// unique amongst **all** crates. Therefore, it should contain
+ /// something unique to this crate (e.g., a module path) as well
+ /// as the crate name and disambiguator.
pub name: String,
+ pub symbol_name_hash: u64,
+ pub source: ModuleSource,
+}
+
+#[derive(Clone)]
+pub enum ModuleSource {
+ /// Copy the `.o` files or whatever from the incr. comp. directory.
+ Preexisting(WorkProduct),
+
+ /// Rebuild from this LLVM module.
+ Translated(ModuleLlvm),
+}
+
+#[derive(Copy, Clone)]
+pub struct ModuleLlvm {
pub llcx: llvm::ContextRef,
pub llmod: llvm::ModuleRef,
}
}
Err(ConstEvalFailure::Runtime(err)) => {
span_bug!(constant.span,
- "MIR constant {:?} results in runtime panic: {}",
+ "MIR constant {:?} results in runtime panic: {:?}",
constant, err.description())
}
}
debug!("leaving monomorphic fn {:?}", instance);
return (val, mono_ty);
} else {
- assert!(!ccx.codegen_unit().items.contains_key(&TransItem::Fn(instance)));
+ assert!(!ccx.codegen_unit().contains_item(&TransItem::Fn(instance)));
}
debug!("monomorphic_fn({:?})", instance);
use collector::InliningMap;
use llvm;
use monomorphize;
+use rustc::dep_graph::{DepNode, WorkProductId};
use rustc::hir::def_id::DefId;
use rustc::hir::map::DefPathData;
use rustc::session::config::NUMBERED_CODEGEN_UNIT_MARKER;
use rustc::ty::TyCtxt;
use rustc::ty::item_path::characteristic_def_id_of_type;
use std::cmp::Ordering;
+use std::hash::{Hash, Hasher, SipHasher};
+use std::sync::Arc;
use symbol_map::SymbolMap;
use syntax::ast::NodeId;
use syntax::parse::token::{self, InternedString};
}
pub struct CodegenUnit<'tcx> {
- pub name: InternedString,
- pub items: FnvHashMap<TransItem<'tcx>, llvm::Linkage>,
+ /// A name for this CGU. Incremental compilation requires that
+ /// name be unique amongst **all** crates. Therefore, it should
+ /// contain something unique to this crate (e.g., a module path)
+ /// as well as the crate name and disambiguator.
+ name: InternedString,
+
+ items: FnvHashMap<TransItem<'tcx>, llvm::Linkage>,
}
impl<'tcx> CodegenUnit<'tcx> {
+ pub fn new(name: InternedString,
+ items: FnvHashMap<TransItem<'tcx>, llvm::Linkage>)
+ -> Self {
+ CodegenUnit {
+ name: name,
+ items: items,
+ }
+ }
+
+ pub fn empty(name: InternedString) -> Self {
+ Self::new(name, FnvHashMap())
+ }
+
+ pub fn contains_item(&self, item: &TransItem<'tcx>) -> bool {
+ self.items.contains_key(item)
+ }
+
+ pub fn name(&self) -> &str {
+ &self.name
+ }
+
+ pub fn items(&self) -> &FnvHashMap<TransItem<'tcx>, llvm::Linkage> {
+ &self.items
+ }
+
+ pub fn work_product_id(&self) -> Arc<WorkProductId> {
+ Arc::new(WorkProductId(self.name().to_string()))
+ }
+
+ pub fn work_product_dep_node(&self) -> DepNode<DefId> {
+ DepNode::WorkProduct(self.work_product_id())
+ }
+
+ pub fn compute_symbol_name_hash(&self, tcx: TyCtxt, symbol_map: &SymbolMap) -> u64 {
+ let mut state = SipHasher::new();
+ let all_items = self.items_in_deterministic_order(tcx, symbol_map);
+ for (item, _) in all_items {
+ let symbol_name = symbol_map.get(item).unwrap();
+ symbol_name.hash(&mut state);
+ }
+ state.finish()
+ }
+
pub fn items_in_deterministic_order(&self,
tcx: TyCtxt,
symbol_map: &SymbolMap)
};
let make_codegen_unit = || {
- CodegenUnit {
- name: codegen_unit_name.clone(),
- items: FnvHashMap(),
- }
+ CodegenUnit::empty(codegen_unit_name.clone())
};
let mut codegen_unit = codegen_units.entry(codegen_unit_name.clone())
if codegen_units.is_empty() {
let codegen_unit_name = InternedString::new(FALLBACK_CODEGEN_UNIT);
codegen_units.entry(codegen_unit_name.clone())
- .or_insert_with(|| CodegenUnit {
- name: codegen_unit_name.clone(),
- items: FnvHashMap(),
- });
+ .or_insert_with(|| CodegenUnit::empty(codegen_unit_name.clone()));
}
PreInliningPartitioning {
// we reach the target count
while codegen_units.len() < target_cgu_count {
let index = codegen_units.len();
- codegen_units.push(CodegenUnit {
- name: numbered_codegen_unit_name(crate_name, index),
- items: FnvHashMap()
- });
+ codegen_units.push(
+ CodegenUnit::empty(numbered_codegen_unit_name(crate_name, index)));
}
}
follow_inlining(*root, inlining_map, &mut reachable);
}
- let mut new_codegen_unit = CodegenUnit {
- name: codegen_unit.name.clone(),
- items: FnvHashMap(),
- };
+ let mut new_codegen_unit =
+ CodegenUnit::empty(codegen_unit.name.clone());
// Add all translation items that are not already there
for trans_item in reachable {
items.insert(trans_item, linkage);
}
- CodegenUnit {
- name: numbered_codegen_unit_name(&tcx.crate_name[..], 0),
- items: items
- }
+ CodegenUnit::new(
+ numbered_codegen_unit_name(&tcx.crate_name[..], 0),
+ items)
}
fn numbered_codegen_unit_name(crate_name: &str, index: usize) -> InternedString {
use llvm;
use monomorphize::{self, Instance};
use inline;
+use rustc::dep_graph::DepNode;
use rustc::hir;
use rustc::hir::map as hir_map;
use rustc::hir::def_id::DefId;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::ty::subst;
-use rustc::dep_graph::DepNode;
+use rustc_const_eval::fatal_const_eval_err;
use std::hash::{Hash, Hasher};
use syntax::ast::{self, NodeId};
use syntax::{attr,errors};
impl<'a, 'tcx> TransItem<'tcx> {
pub fn define(&self, ccx: &CrateContext<'a, 'tcx>) {
-
debug!("BEGIN IMPLEMENTING '{} ({})' in cgu {}",
self.to_string(ccx.tcx()),
self.to_raw_string(),
- ccx.codegen_unit().name);
+ ccx.codegen_unit().name());
+
+ // (*) This code executes in the context of a dep-node for the
+ // entire CGU. In some cases, we introduce dep-nodes for
+ // particular items that we are translating (these nodes will
+ // have read edges coming into the CGU node). These smaller
+ // nodes are not needed for correctness -- we always
+ // invalidate an entire CGU at a time -- but they enable
+ // finer-grained testing, since you can write tests that check
+ // that the incoming edges to a particular fn are from a
+ // particular set.
self.register_reads(ccx);
match *self {
TransItem::Static(node_id) => {
+ let def_id = ccx.tcx().map.local_def_id(node_id);
+ let _task = ccx.tcx().dep_graph.in_task(DepNode::TransCrateItem(def_id)); // (*)
let item = ccx.tcx().map.expect_item(node_id);
if let hir::ItemStatic(_, m, ref expr) = item.node {
match consts::trans_static(&ccx, m, expr, item.id, &item.attrs) {
Ok(_) => { /* Cool, everything's alright. */ },
- Err(err) => ccx.tcx().sess.span_fatal(expr.span, &err.description()),
+ Err(err) => {
+ // FIXME: shouldn't this be a `span_err`?
+ fatal_const_eval_err(
+ ccx.tcx(), &err, expr.span, "static");
+ }
};
} else {
span_bug!(item.span, "Mismatch between hir::Item type and TransItem type")
}
}
TransItem::Fn(instance) => {
+ let _task = ccx.tcx().dep_graph.in_task(
+ DepNode::TransCrateItem(instance.def)); // (*)
+
base::trans_instance(&ccx, instance);
}
TransItem::DropGlue(dg) => {
debug!("END IMPLEMENTING '{} ({})' in cgu {}",
self.to_string(ccx.tcx()),
self.to_raw_string(),
- ccx.codegen_unit().name);
+ ccx.codegen_unit().name());
}
/// If necessary, creates a subtask for trans'ing a particular item and registers reads on
debug!("BEGIN PREDEFINING '{} ({})' in cgu {}",
self.to_string(ccx.tcx()),
self.to_raw_string(),
- ccx.codegen_unit().name);
+ ccx.codegen_unit().name());
let symbol_name = ccx.symbol_map()
.get_or_compute(ccx.shared(), *self);
debug!("END PREDEFINING '{} ({})' in cgu {}",
self.to_string(ccx.tcx()),
self.to_raw_string(),
- ccx.codegen_unit().name);
+ ccx.codegen_unit().name());
}
fn predefine_static(ccx: &CrateContext<'a, 'tcx>,
use rustc::ty::{self, Ty};
use rustc::hir;
-use rustc_const_eval::eval_repeat_count;
+use rustc_const_eval::eval_length;
use syntax::ast;
use syntax::parse::token::InternedString;
return expr::trans_into(bcx, &element, Ignore);
}
SaveIn(lldest) => {
- match eval_repeat_count(bcx.tcx(), &count_expr) {
+ match eval_length(bcx.tcx(), &count_expr, "repeat count").unwrap() {
0 => expr::trans_into(bcx, &element, Ignore),
1 => expr::trans_into(bcx, &element, SaveIn(lldest)),
count => {
},
hir::ExprVec(ref es) => es.len(),
hir::ExprRepeat(_, ref count_expr) => {
- eval_repeat_count(bcx.tcx(), &count_expr)
+ eval_length(bcx.tcx(), &count_expr, "repeat count").unwrap()
}
_ => span_bug!(content_expr.span, "unexpected vec content")
}
//! case but `&a` in the second. Basically, defaults that appear inside
//! an rptr (`&r.T`) use the region `r` that appears in the rptr.
-use middle::const_val::ConstVal;
-use rustc_const_eval::{eval_const_expr_partial, ConstEvalErr};
-use rustc_const_eval::EvalHint::UncheckedExprHint;
-use rustc_const_eval::ErrKind::ErroneousReferencedConstant;
+use rustc_const_eval::eval_length;
use hir::{self, SelfKind};
use hir::def::{Def, PathResolution};
use hir::def_id::DefId;
use util::common::{ErrorReported, FN_OUTPUT_NAME};
use util::nodemap::{NodeMap, FnvHashSet};
-use rustc_const_math::ConstInt;
use std::cell::RefCell;
use syntax::{abi, ast};
use syntax::feature_gate::{GateIssue, emit_feature_err};
ty
}
hir::TyFixedLengthVec(ref ty, ref e) => {
- let hint = UncheckedExprHint(tcx.types.usize);
- match eval_const_expr_partial(tcx.global_tcx(), &e, hint, None) {
- Ok(ConstVal::Integral(ConstInt::Usize(i))) => {
- let i = i.as_u64(tcx.sess.target.uint_type);
- assert_eq!(i as usize as u64, i);
- tcx.mk_array(self.ast_ty_to_ty(rscope, &ty), i as usize)
- },
- Ok(val) => {
- span_err!(tcx.sess, ast_ty.span, E0249,
- "expected usize value for array length, got {}",
- val.description());
- self.tcx().types.err
- },
- // array length errors happen before the global constant check
- // so we need to report the real error
- Err(ConstEvalErr { kind: ErroneousReferencedConstant(box r), ..}) |
- Err(r) => {
- let mut err = struct_span_err!(tcx.sess, r.span, E0250,
- "array length constant \
- evaluation error: {}",
- r.description());
- if !ast_ty.span.contains(r.span) {
- span_note!(&mut err, ast_ty.span, "for array length here")
- }
- err.emit();
- self.tcx().types.err
- }
+ if let Ok(length) = eval_length(tcx.global_tcx(), &e, "array length") {
+ tcx.mk_array(self.ast_ty_to_ty(rscope, &ty), length)
+ } else {
+ self.tcx().types.err
}
}
hir::TyTypeof(ref _e) => {
return;
}
- // Check that the types of the end-points can be unified.
- let types_unify = self.require_same_types(pat.span, rhs_ty, lhs_ty,
- "mismatched types in range");
-
- // It's ok to return without a message as `require_same_types` prints an error.
- if !types_unify {
- return;
- }
-
// Now that we know the types can be unified we find the unified type and use
// it to type the entire expression.
let common_type = self.resolve_type_vars_if_possible(&lhs_ty);
// subtyping doesn't matter here, as the value is some kind of scalar
self.demand_eqtype(pat.span, expected, lhs_ty);
+ self.demand_eqtype(pat.span, expected, rhs_ty);
}
PatKind::Binding(bm, _, ref sub) => {
let typ = self.local_ty(pat.span, pat.id);
_ => {
let mut err = self.type_error_struct(call_expr.span, |actual| {
format!("expected function, found `{}`", actual)
- }, callee_ty, None);
+ }, callee_ty);
if let hir::ExprCall(ref expr, _) = call_expr.node {
let tcx = self.tcx;
format!("casting `{}` as `{}` is invalid",
actual,
fcx.ty_to_string(self.cast_ty))
- }, self.expr_ty, None)
+ }, self.expr_ty)
.help(&format!("cast through {} first", match e {
CastError::NeedViaPtr => "a raw pointer",
CastError::NeedViaThinPtr => "a thin pointer",
CastError::CastToChar => {
fcx.type_error_message(self.span, |actual| {
format!("only `u8` can be cast as `char`, not `{}`", actual)
- }, self.expr_ty, None);
+ }, self.expr_ty);
}
CastError::NonScalar => {
fcx.type_error_message(self.span, |actual| {
format!("non-scalar cast: `{}` as `{}`",
actual,
fcx.ty_to_string(self.cast_ty))
- }, self.expr_ty, None);
+ }, self.expr_ty);
}
CastError::IllegalCast => {
fcx.type_error_message(self.span, |actual| {
format!("casting `{}` as `{}` is invalid",
actual,
fcx.ty_to_string(self.cast_ty))
- }, self.expr_ty, None);
+ }, self.expr_ty);
}
CastError::SizedUnsizedCast => {
fcx.type_error_message(self.span, |actual| {
format!("cannot cast thin pointer `{}` to fat pointer `{}`",
actual,
fcx.ty_to_string(self.cast_ty))
- }, self.expr_ty, None)
+ }, self.expr_ty)
}
CastError::DifferingKinds => {
fcx.type_error_struct(self.span, |actual| {
format!("casting `{}` as `{}` is invalid",
actual,
fcx.ty_to_string(self.cast_ty))
- }, self.expr_ty, None)
+ }, self.expr_ty)
.note("vtable kinds may not match")
.emit();
}
let tstr = fcx.ty_to_string(self.cast_ty);
let mut err = fcx.type_error_struct(self.span, |actual| {
format!("cast to unsized type: `{}` as `{}`", actual, tstr)
- }, self.expr_ty, None);
+ }, self.expr_ty);
match self.expr_ty.sty {
ty::TyRef(_, ty::TypeAndMut { mutbl: mt, .. }) => {
let mtstr = match mt {
traits::type_known_to_meet_builtin_bound(self, ty, ty::BoundSized, span)
}
}
-
use rustc::infer::{self, InferOk, TypeOrigin};
use rustc::ty;
use rustc::traits::{self, ProjectionMode};
+use rustc::ty::error::ExpectedFound;
use rustc::ty::subst::{self, Subst, Substs, VecPerParamSpace};
use syntax::ast;
debug!("sub_types failed: impl ty {:?}, trait ty {:?}",
impl_fty,
trait_fty);
- span_err!(tcx.sess, impl_m_span, E0053,
- "method `{}` has an incompatible type for trait: {}",
- trait_m.name,
- terr);
+
+ let mut diag = struct_span_err!(
+ tcx.sess, origin.span(), E0053,
+ "method `{}` has an incompatible type for trait", trait_m.name
+ );
+ infcx.note_type_err(
+ &mut diag, origin,
+ Some(infer::ValuePairs::Types(ExpectedFound {
+ expected: trait_fty,
+ found: impl_fty
+ })), &terr
+ );
+ diag.emit();
return
}
// Compute skolemized form of impl and trait const tys.
let impl_ty = impl_c.ty.subst(tcx, impl_to_skol_substs);
let trait_ty = trait_c.ty.subst(tcx, &trait_to_skol_substs);
+ let origin = TypeOrigin::Misc(impl_c_span);
let err = infcx.commit_if_ok(|_| {
- let origin = TypeOrigin::Misc(impl_c_span);
-
// There is no "body" here, so just pass dummy id.
let impl_ty =
assoc::normalize_associated_types_in(&infcx,
debug!("checking associated const for compatibility: impl ty {:?}, trait ty {:?}",
impl_ty,
trait_ty);
- span_err!(tcx.sess, impl_c_span, E0326,
- "implemented const `{}` has an incompatible type for \
- trait: {}",
- trait_c.name,
- terr);
+ let mut diag = struct_span_err!(
+ tcx.sess, origin.span(), E0326,
+ "implemented const `{}` has an incompatible type for trait",
+ trait_c.name
+ );
+ infcx.note_type_err(
+ &mut diag, origin,
+ Some(infer::ValuePairs::Types(ExpectedFound {
+ expected: trait_ty,
+ found: impl_ty
+ })), &terr
+ );
+ diag.emit();
}
});
}
}
pub fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
- let origin = TypeOrigin::Misc(sp);
+ self.demand_eqtype_with_origin(TypeOrigin::Misc(sp), expected, actual);
+ }
+
+ pub fn demand_eqtype_with_origin(&self,
+ origin: TypeOrigin,
+ expected: Ty<'tcx>,
+ actual: Ty<'tcx>)
+ {
match self.eq_types(false, origin, actual, expected) {
Ok(InferOk { obligations, .. }) => {
// FIXME(#32730) propagate obligations
self.report_mismatched_types(origin, expected, expr_ty, e);
}
}
-
- pub fn require_same_types(&self, span: Span, t1: Ty<'tcx>, t2: Ty<'tcx>, msg: &str)
- -> bool {
- if let Err(err) = self.eq_types(false, TypeOrigin::Misc(span), t1, t2) {
- let found_ty = self.resolve_type_vars_if_possible(&t1);
- let expected_ty = self.resolve_type_vars_if_possible(&t2);
- ::emit_type_err(self.tcx, span, found_ty, expected_ty, &err, msg);
- false
- } else {
- true
- }
- }
}
//! intrinsics that the compiler exposes.
use intrinsics;
+use rustc::infer::TypeOrigin;
use rustc::ty::subst::{self, Substs};
use rustc::ty::FnSig;
use rustc::ty::{self, Ty};
i_n_tps, n_tps);
} else {
require_same_types(ccx,
- it.span,
+ TypeOrigin::IntrinsicType(it.span),
i_ty.ty,
- fty,
- "intrinsic has wrong type");
+ fty);
}
}
item_name,
actual)
},
- rcvr_ty,
- None);
+ rcvr_ty);
// If the item has the name of a field, give a help note
if let (&ty::TyStruct(def, substs), Some(expr)) = (&rcvr_ty.sty, rcvr_expr) {
use rustc::hir::{self, PatKind};
use rustc::hir::print as pprust;
use rustc_back::slice;
-use rustc_const_eval::eval_repeat_count;
+use rustc_const_eval::eval_length;
mod assoc;
mod autoderef;
self.type_error_message(arg.span, |t| {
format!("can't pass an `{}` to variadic \
function, cast to `c_double`", t)
- }, arg_ty, None);
+ }, arg_ty);
}
ty::TyInt(ast::IntTy::I8) | ty::TyInt(ast::IntTy::I16) | ty::TyBool => {
self.type_error_message(arg.span, |t| {
format!("can't pass `{}` to variadic \
function, cast to `c_int`",
t)
- }, arg_ty, None);
+ }, arg_ty);
}
ty::TyUint(ast::UintTy::U8) | ty::TyUint(ast::UintTy::U16) => {
self.type_error_message(arg.span, |t| {
format!("can't pass `{}` to variadic \
function, cast to `c_uint`",
t)
- }, arg_ty, None);
+ }, arg_ty);
}
ty::TyFnDef(_, _, f) => {
let ptr_ty = self.tcx.mk_fn_ptr(f);
|t| {
format!("can't pass `{}` to variadic \
function, cast to `{}`", t, ptr_ty)
- }, arg_ty, None);
+ }, arg_ty);
}
_ => {}
}
self.type_error_struct(field.span, |actual| {
format!("attempted to take value of method `{}` on type \
`{}`", field.node, actual)
- }, expr_t, None)
- .help(
- "maybe a `()` to call it is missing? \
+ }, expr_t)
+ .help("maybe a `()` to call it is missing? \
If not, try an anonymous function")
.emit();
self.write_error(expr.id);
format!("attempted access of field `{}` on type `{}`, \
but no field with that name was found",
field.node, actual)
- }, expr_t, None);
+ }, expr_t);
if let ty::TyStruct(def, _) = expr_t.sty {
Self::suggest_field_names(&mut err, def.struct_variant(), field, vec![]);
}
actual)
}
},
- expr_t, None);
+ expr_t);
self.write_error(expr.id);
}
variant: ty::VariantDef<'tcx>,
field: &hir::Field,
skip_fields: &[hir::Field]) {
- let mut err = self.type_error_struct(
+ let mut err = self.type_error_struct_with_diag(
field.name.span,
|actual| if let ty::TyEnum(..) = ty.sty {
- format!("struct variant `{}::{}` has no field named `{}`",
- actual, variant.name.as_str(), field.name.node)
+ struct_span_err!(self.tcx.sess, field.name.span, E0559,
+ "struct variant `{}::{}` has no field named `{}`",
+ actual, variant.name.as_str(), field.name.node)
} else {
- format!("structure `{}` has no field named `{}`",
- actual, field.name.node)
+ struct_span_err!(self.tcx.sess, field.name.span, E0560,
+ "structure `{}` has no field named `{}`",
+ actual, field.name.node)
},
- ty,
- None);
+ ty);
// prevent all specified fields from being suggested
let skip_fields = skip_fields.iter().map(|ref x| x.name.node.as_str());
Self::suggest_field_names(&mut err, variant, &field.name, skip_fields.collect());
self.type_error_message(expr.span, |actual| {
format!("type `{}` cannot be \
dereferenced", actual)
- }, oprnd_t, None);
+ }, oprnd_t);
oprnd_t = tcx.types.err;
}
}
}
hir::ExprRepeat(ref element, ref count_expr) => {
self.check_expr_has_type(&count_expr, tcx.types.usize);
- let count = eval_repeat_count(self.tcx.global_tcx(), &count_expr);
+ let count = eval_length(self.tcx.global_tcx(), &count_expr, "repeat count")
+ .unwrap_or(0);
let uty = match expected {
ExpectHasType(uty) => {
format!("cannot index a value of type `{}`",
actual)
},
- base_t,
- None);
+ base_t);
// Try to give some advice about indexing tuples.
if let ty::TyTuple(_) = base_t.sty {
let mut needs_note = true;
if !self.is_tainted_by_errors() {
self.type_error_message(sp, |_actual| {
"the type of this value must be known in this context".to_string()
- }, ty, None);
+ }, ty);
}
self.demand_suptype(sp, self.tcx.types.err, ty);
ty = self.tcx.types.err;
self.type_error_message(ex.span, |actual| {
format!("cannot apply unary operator `{}` to type `{}`",
op_str, actual)
- }, operand_ty, None);
+ }, operand_ty);
self.tcx.types.err
}
}
span: Span,
id: ast::NodeId)
{
- intravisit::walk_fn(self, fn_kind, decl, body, span);
+ intravisit::walk_fn(self, fn_kind, decl, body, span, id);
self.analyze_closure(id, span, decl, body);
}
}
use CrateCtxt;
use hir::def_id::DefId;
use middle::region::{CodeExtent};
+use rustc::infer::TypeOrigin;
use rustc::ty::subst::{self, TypeSpace, FnSpace, ParamSpace, SelfSpace};
use rustc::traits;
use rustc::ty::{self, Ty, TyCtxt};
}
}
- fn check_trait_or_impl_item(&mut self, item_id: ast::NodeId, span: Span) {
+ fn check_trait_or_impl_item(&mut self,
+ item_id: ast::NodeId,
+ span: Span,
+ sig_if_method: Option<&hir::MethodSig>) {
let code = self.code.clone();
self.for_id(item_id, span).with_fcx(|fcx, this| {
let free_substs = &fcx.parameter_environment.free_substs;
let predicates = fcx.instantiate_bounds(span, free_substs, &method.predicates);
this.check_fn_or_method(fcx, span, &method_ty, &predicates,
free_id_outlive, &mut implied_bounds);
- this.check_method_receiver(fcx, span, &method,
+ let sig_if_method = sig_if_method.expect("bad signature for method");
+ this.check_method_receiver(fcx, sig_if_method, &method,
free_id_outlive, self_ty);
}
ty::TypeTraitItem(assoc_type) => {
fn check_method_receiver<'fcx, 'tcx>(&mut self,
fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
- span: Span,
+ method_sig: &hir::MethodSig,
method: &ty::Method<'tcx>,
free_id_outlive: CodeExtent,
self_ty: ty::Ty<'tcx>)
{
// check that the type of the method's receiver matches the
// method's first parameter.
-
- let free_substs = &fcx.parameter_environment.free_substs;
- let fty = fcx.instantiate_type_scheme(span, free_substs, &method.fty);
- let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &fty.sig);
-
- debug!("check_method_receiver({:?},cat={:?},self_ty={:?},sig={:?})",
- method.name, method.explicit_self, self_ty, sig);
+ debug!("check_method_receiver({:?},cat={:?},self_ty={:?})",
+ method.name, method.explicit_self, self_ty);
let rcvr_ty = match method.explicit_self {
ty::ExplicitSelfCategory::Static => return,
}
ty::ExplicitSelfCategory::ByBox => fcx.tcx.mk_box(self_ty)
};
+
+ let span = method_sig.decl.inputs[0].pat.span;
+
+ let free_substs = &fcx.parameter_environment.free_substs;
+ let fty = fcx.instantiate_type_scheme(span, free_substs, &method.fty);
+ let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &fty.sig);
+
+ debug!("check_method_receiver: sig={:?}", sig);
+
let rcvr_ty = fcx.instantiate_type_scheme(span, free_substs, &rcvr_ty);
let rcvr_ty = fcx.tcx.liberate_late_bound_regions(free_id_outlive,
&ty::Binder(rcvr_ty));
debug!("check_method_receiver: receiver ty = {:?}", rcvr_ty);
- fcx.require_same_types(span, sig.inputs[0], rcvr_ty,
- "mismatched method receiver");
+ let origin = TypeOrigin::MethodReceiver(span);
+ fcx.demand_eqtype_with_origin(origin, rcvr_ty, sig.inputs[0]);
}
fn check_variances_for_type_defn(&self,
fn visit_trait_item(&mut self, trait_item: &'v hir::TraitItem) {
debug!("visit_trait_item: {:?}", trait_item);
- self.check_trait_or_impl_item(trait_item.id, trait_item.span);
+ let method_sig = match trait_item.node {
+ hir::TraitItem_::MethodTraitItem(ref sig, _) => Some(sig),
+ _ => None
+ };
+ self.check_trait_or_impl_item(trait_item.id, trait_item.span, method_sig);
intravisit::walk_trait_item(self, trait_item)
}
fn visit_impl_item(&mut self, impl_item: &'v hir::ImplItem) {
debug!("visit_impl_item: {:?}", impl_item);
- self.check_trait_or_impl_item(impl_item.id, impl_item.span);
+ let method_sig = match impl_item.node {
+ hir::ImplItemKind::Method(ref sig, _) => Some(sig),
+ _ => None
+ };
+ self.check_trait_or_impl_item(impl_item.id, impl_item.span, method_sig);
intravisit::walk_impl_item(self, impl_item)
}
}
use middle::lang_items::SizedTraitLangItem;
use middle::const_val::ConstVal;
use rustc_const_eval::EvalHint::UncheckedExprHint;
-use rustc_const_eval::{eval_const_expr_partial, ConstEvalErr};
-use rustc_const_eval::ErrKind::ErroneousReferencedConstant;
+use rustc_const_eval::{eval_const_expr_partial, report_const_eval_err};
use rustc::ty::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace, VecPerParamSpace};
use rustc::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer};
use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeScheme};
},
// enum variant evaluation happens before the global constant check
// so we need to report the real error
- Err(ConstEvalErr { kind: ErroneousReferencedConstant(box err), ..}) |
Err(err) => {
- let mut diag = struct_span_err!(ccx.tcx.sess, err.span, E0080,
- "constant evaluation error: {}",
- err.description());
- if !e.span.contains(err.span) {
- diag.span_note(e.span, "for enum discriminant here");
- }
+ let mut diag = report_const_eval_err(
+ ccx.tcx, &err, e.span, "enum discriminant");
diag.emit();
None
}
```
"##,
-E0080: r##"
-This error indicates that the compiler was unable to sensibly evaluate an
-integer expression provided as an enum discriminant. Attempting to divide by 0
-or causing integer overflow are two ways to induce this error. For example:
-
-```compile_fail
-enum Enum {
- X = (1 << 500),
- Y = (1 / 0)
-}
-```
-
-Ensure that the expressions given can be evaluated as the desired integer type.
-See the FFI section of the Reference for more information about using a custom
-integer type:
-
-https://doc.rust-lang.org/reference.html#ffi-attributes
-"##,
-
E0081: r##"
Enum discriminants are used to differentiate enum variants stored in memory.
This error indicates that the same value was used for two or more variants,
[RFC 1023]: https://github.com/rust-lang/rfcs/pull/1023
"##,
+/*
E0211: r##"
You used a function or type which doesn't fit the requirements for where it was
used. Erroneous code examples:
}
```
"##,
+ */
E0214: r##"
A generic type was described using parentheses rather than angle brackets. For
behavior for specific enum variants.
"##,
-E0249: r##"
-This error indicates a constant expression for the array length was found, but
-it was not an integer (signed or unsigned) expression.
-
-Some examples of code that produces this error are:
-
-```compile_fail
-const A: [u32; "hello"] = []; // error
-const B: [u32; true] = []; // error
-const C: [u32; 0.0] = []; // error
-"##,
-
-E0250: r##"
-There was an error while evaluating the expression for the length of a fixed-
-size array type.
-
-Some examples of this error are:
-
-```compile_fail
-// divide by zero in the length expression
-const A: [u32; 1/0] = [];
-
-// Rust currently will not evaluate the function `foo` at compile time
-fn foo() -> usize { 12 }
-const B: [u32; foo()] = [];
-
-// it is an error to try to add `u8` and `f64`
-use std::{f64, u8};
-const C: [u32; u8::MAX + f64::EPSILON] = [];
-```
-"##,
-
E0318: r##"
Default impls for a trait must be located in the same crate where the trait was
defined. For more information see the [opt-in builtin traits RFC](https://github
```
"##,
+E0559: r##"
+An unknown field was specified into an enum's structure variant.
+
+Erroneous code example:
+
+```compile_fail,E0559
+enum Field {
+ Fool { x: u32 },
+}
+
+let s = Field::Fool { joke: 0 };
+// error: struct variant `Field::Fool` has no field named `joke`
+```
+
+Verify you didn't misspell the field's name or that the field exists. Example:
+
+```
+enum Field {
+ Fool { joke: u32 },
+}
+
+let s = Field::Fool { joke: 0 }; // ok!
+```
+"##,
+
+E0560: r##"
+An unknown field was specified into a structure.
+
+Erroneous code example:
+
+```compile_fail,E0560
+struct Simba {
+ mother: u32,
+}
+
+let s = Simba { mother: 1, father: 0 };
+// error: structure `Simba` has no field named `father`
+```
+
+Verify you didn't misspell the field's name or that the field exists. Example:
+
+```
+struct Simba {
+ mother: u32,
+ father: u32,
+}
+
+let s = Simba { mother: 1, father: 0 }; // ok!
+```
+"##,
+
}
register_diagnostics! {
E0245, // not a trait
// E0246, // invalid recursive type
// E0247,
+// E0249,
// E0319, // trait impls for defaulted traits allowed just for structs/enums
E0320, // recursive overflow during dropck
E0328, // cannot implement Unsize explicitly
}
}
-pub fn emit_type_err<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
- span: Span,
- found_ty: Ty<'tcx>,
- expected_ty: Ty<'tcx>,
- terr: &ty::error::TypeError<'tcx>,
- msg: &str) {
- let mut err = struct_span_err!(tcx.sess, span, E0211, "{}", msg);
- err.span_label(span, &terr);
- err.note_expected_found(&"type", &expected_ty, &found_ty);
- tcx.note_and_explain_type_err(&mut err, terr, span);
- err.emit();
-}
-
fn require_same_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
- span: Span,
+ origin: TypeOrigin,
t1: Ty<'tcx>,
- t2: Ty<'tcx>,
- msg: &str)
+ t2: Ty<'tcx>)
-> bool {
ccx.tcx.infer_ctxt(None, None, ProjectionMode::AnyFinal).enter(|infcx| {
- if let Err(err) = infcx.eq_types(false, TypeOrigin::Misc(span), t1, t2) {
- emit_type_err(infcx.tcx, span, t1, t2, &err, msg);
+ if let Err(err) = infcx.eq_types(false, origin.clone(), t1, t2) {
+ infcx.report_mismatched_types(origin, t1, t2, err);
false
} else {
true
})
}));
- require_same_types(ccx, main_span, main_t, se_ty,
- "main function has wrong type");
+ require_same_types(
+ ccx,
+ TypeOrigin::MainFunctionType(main_span),
+ main_t,
+ se_ty);
}
_ => {
span_bug!(main_span,
}),
}));
- require_same_types(ccx, start_span, start_t, se_ty,
- "start function has wrong type");
+ require_same_types(
+ ccx,
+ TypeOrigin::StartFunctionType(start_span),
+ start_t,
+ se_ty);
}
_ => {
span_bug!(start_span,
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::char::{MAX, from_digit, from_u32, from_u32_unchecked};
#[stable(feature = "rust1", since = "1.0.0")]
-pub use core::char::{EncodeUtf16, EncodeUtf8, EscapeDefault, EscapeUnicode};
+pub use core::char::{EncodeUtf16, EncodeUtf8, EscapeDebug, EscapeDefault, EscapeUnicode};
// unstable reexports
#[unstable(feature = "decode_utf8", issue = "33906")]
C::escape_unicode(self)
}
+ /// Returns an iterator that yields the literal escape code of a `char`.
+ ///
+ /// This will escape the characters similar to the `Debug` implementations
+ /// of `str` or `char`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// for i in '\n'.escape_default() {
+ /// println!("{}", i);
+ /// }
+ /// ```
+ ///
+ /// This prints:
+ ///
+ /// ```text
+ /// \
+ /// n
+ /// ```
+ ///
+ /// Collecting into a `String`:
+ ///
+ /// ```
+ /// let quote: String = '\n'.escape_default().collect();
+ ///
+ /// assert_eq!(quote, "\\n");
+ /// ```
+ #[unstable(feature = "char_escape_debug", issue = "35068")]
+ #[inline]
+ pub fn escape_debug(self) -> EscapeDebug {
+ C::escape_debug(self)
+ }
+
/// Returns an iterator that yields the literal escape code of a `char`.
///
/// The default is chosen with a bias toward producing literals that are
#![cfg_attr(not(stage0), deny(warnings))]
#![no_std]
+#![feature(char_escape_debug)]
#![feature(core_char_ext)]
#![feature(decode_utf8)]
#![feature(lang_items)]
impl Clean<Attribute> for ast::MetaItem {
fn clean(&self, cx: &DocContext) -> Attribute {
- match self.node {
- ast::MetaItemKind::Word(ref s) => Word(s.to_string()),
- ast::MetaItemKind::List(ref s, ref l) => {
- List(s.to_string(), l.clean(cx))
- }
- ast::MetaItemKind::NameValue(ref s, ref v) => {
- NameValue(s.to_string(), lit_to_string(v))
- }
- }
+ if self.is_word() {
+ Word(self.name().to_string())
+ } else if let Some(v) = self.value_str() {
+ NameValue(self.name().to_string(), v.to_string())
+ } else { // must be a list
+ let l = self.meta_item_list().unwrap();
+ List(self.name().to_string(), l.clean(cx))
+ }
}
}
impl Clean<Attribute> for ast::Attribute {
fn clean(&self, cx: &DocContext) -> Attribute {
- self.with_desugared_doc(|a| a.node.value.clean(cx))
+ self.with_desugared_doc(|a| a.meta().clean(cx))
}
}
}
}
fn meta_item_list<'a>(&'a self) -> Option<&'a [P<ast::MetaItem>]> { None }
+
+ fn is_word(&self) -> bool {
+ match *self {
+ Word(_) => true,
+ _ => false,
+ }
+ }
+
+ fn is_value_str(&self) -> bool {
+ match *self {
+ NameValue(..) => true,
+ _ => false,
+ }
+ }
+
+ fn is_meta_item_list(&self) -> bool {
+ match *self {
+ List(..) => true,
+ _ => false,
+ }
+ }
+
fn span(&self) -> syntax_pos::Span { unimplemented!() }
}
}
}
-fn lit_to_string(lit: &ast::Lit) -> String {
- match lit.node {
- ast::LitKind::Str(ref st, _) => st.to_string(),
- ast::LitKind::ByteStr(ref data) => format!("{:?}", data),
- ast::LitKind::Byte(b) => {
- let mut res = String::from("b'");
- for c in (b as char).escape_default() {
- res.push(c);
- }
- res.push('\'');
- res
- },
- ast::LitKind::Char(c) => format!("'{}'", c),
- ast::LitKind::Int(i, _t) => i.to_string(),
- ast::LitKind::Float(ref f, _t) => f.to_string(),
- ast::LitKind::FloatUnsuffixed(ref f) => f.to_string(),
- ast::LitKind::Bool(b) => b.to_string(),
- }
-}
-
fn name_from_pat(p: &hir::Pat) -> String {
use rustc::hir::*;
debug!("Trying to get a name from pattern: {:?}", p);
if structhead {"struct "} else {""},
it.name.as_ref().unwrap())?;
if let Some(g) = g {
- write!(w, "{}{}", *g, WhereClause(g))?
+ write!(w, "{}", g)?
}
match ty {
doctree::Plain => {
+ if let Some(g) = g {
+ write!(w, "{}", WhereClause(g))?
+ }
write!(w, " {{\n{}", tab)?;
for field in fields {
if let clean::StructFieldItem(ref ty) = field.inner {
_ => unreachable!()
}
}
- write!(w, ");")?;
+ write!(w, ")")?;
+ if let Some(g) = g {
+ write!(w, "{}", WhereClause(g))?
+ }
+ write!(w, ";")?;
}
doctree::Unit => {
+ // Needed for PhantomData.
+ if let Some(g) = g {
+ write!(w, "{}", WhereClause(g))?
+ }
write!(w, ";")?;
}
}
gcc = "0.3"
[features]
+backtrace = []
jemalloc = ["alloc_jemalloc"]
debug-jemalloc = ["alloc_jemalloc/debug"]
let target = env::var("TARGET").unwrap();
let host = env::var("HOST").unwrap();
- if !target.contains("apple") && !target.contains("msvc") && !target.contains("emscripten"){
+ if cfg!(feature = "backtrace") && !target.contains("apple") && !target.contains("msvc") &&
+ !target.contains("emscripten") {
build_libbacktrace(&host, &target);
}
///
/// This field may not be available on all platforms, and will return an
/// `Err` on platforms where it is not available.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # fn foo() -> std::io::Result<()> {
+ /// use std::fs;
+ ///
+ /// let metadata = try!(fs::metadata("foo.txt"));
+ ///
+ /// if let Ok(time) = metadata.modified() {
+ /// println!("{:?}", time);
+ /// } else {
+ /// println!("Not supported on this platform");
+ /// }
+ /// # Ok(())
+ /// # }
+ /// ```
#[stable(feature = "fs_time", since = "1.10.0")]
pub fn modified(&self) -> io::Result<SystemTime> {
self.0.modified().map(FromInner::from_inner)
///
/// This field may not be available on all platforms, and will return an
/// `Err` on platforms where it is not available.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # fn foo() -> std::io::Result<()> {
+ /// use std::fs;
+ ///
+ /// let metadata = try!(fs::metadata("foo.txt"));
+ ///
+ /// if let Ok(time) = metadata.accessed() {
+ /// println!("{:?}", time);
+ /// } else {
+ /// println!("Not supported on this platform");
+ /// }
+ /// # Ok(())
+ /// # }
+ /// ```
#[stable(feature = "fs_time", since = "1.10.0")]
pub fn accessed(&self) -> io::Result<SystemTime> {
self.0.accessed().map(FromInner::from_inner)
///
/// This field may not be available on all platforms, and will return an
/// `Err` on platforms where it is not available.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # fn foo() -> std::io::Result<()> {
+ /// use std::fs;
+ ///
+ /// let metadata = try!(fs::metadata("foo.txt"));
+ ///
+ /// if let Ok(time) = metadata.created() {
+ /// println!("{:?}", time);
+ /// } else {
+ /// println!("Not supported on this platform");
+ /// }
+ /// # Ok(())
+ /// # }
+ /// ```
#[stable(feature = "fs_time", since = "1.10.0")]
pub fn created(&self) -> io::Result<SystemTime> {
self.0.created().map(FromInner::from_inner)
#![feature(associated_consts)]
#![feature(borrow_state)]
#![feature(box_syntax)]
-#![feature(cfg_target_vendor)]
#![feature(cfg_target_thread_local)]
+#![feature(cfg_target_vendor)]
+#![feature(char_escape_debug)]
#![feature(char_internals)]
#![feature(collections)]
#![feature(collections_bound)]
#![feature(dropck_parametricity)]
#![feature(float_extras)]
#![feature(float_from_str_radix)]
-#![feature(fnbox)]
#![feature(fn_traits)]
-#![feature(heap_api)]
+#![feature(fnbox)]
#![feature(hashmap_hasher)]
+#![feature(heap_api)]
#![feature(inclusive_range)]
#![feature(int_error_internals)]
#![feature(into_cow)]
#![feature(linkage)]
#![feature(macro_reexport)]
#![cfg_attr(test, feature(map_values_mut))]
+#![feature(needs_panic_runtime)]
#![feature(num_bits_bytes)]
#![feature(old_wrapping)]
#![feature(on_unimplemented)]
#![feature(optin_builtin_traits)]
#![feature(panic_unwind)]
#![feature(placement_in_syntax)]
+#![feature(question_mark)]
#![feature(rand)]
#![feature(raw)]
-#![feature(repr_simd)]
#![feature(reflect_marker)]
+#![feature(repr_simd)]
#![feature(rustc_attrs)]
#![feature(shared)]
#![feature(sip_hash_13)]
#![feature(str_utf16)]
#![feature(test, rustc_private)]
#![feature(thread_local)]
+#![feature(try_from)]
#![feature(unboxed_closures)]
#![feature(unicode)]
#![feature(unique)]
#![feature(unwind_attributes)]
#![feature(vec_push_all)]
#![feature(zero_one)]
-#![feature(question_mark)]
-#![feature(try_from)]
-#![feature(needs_panic_runtime)]
// Issue# 30592: Systematically use alloc_system during stage0 since jemalloc
// might be unavailable or disabled
use mem;
use raw;
use sys_common::rwlock::RWLock;
-use sync::atomic::{AtomicBool, Ordering};
use sys::stdio::Stderr;
-use sys_common::backtrace;
use sys_common::thread_info;
use sys_common::util;
use thread;
static HOOK_LOCK: RWLock = RWLock::new();
static mut HOOK: Hook = Hook::Default;
-static FIRST_PANIC: AtomicBool = AtomicBool::new(true);
/// Registers a custom panic hook, replacing any that was previously registered.
///
}
fn default_hook(info: &PanicInfo) {
- let panics = PANIC_COUNT.with(|c| c.get());
+ #[cfg(any(not(cargobuild), feature = "backtrace"))]
+ use sys_common::backtrace;
// If this is a double panic, make sure that we print a backtrace
// for this panic. Otherwise only print it if logging is enabled.
- let log_backtrace = panics >= 2 || backtrace::log_enabled();
+ #[cfg(any(not(cargobuild), feature = "backtrace"))]
+ let log_backtrace = {
+ let panics = PANIC_COUNT.with(|c| c.get());
+
+ panics >= 2 || backtrace::log_enabled()
+ };
let file = info.location.file;
let line = info.location.line;
let _ = writeln!(err, "thread '{}' panicked at '{}', {}:{}",
name, msg, file, line);
- if log_backtrace {
- let _ = backtrace::write(err);
- } else if FIRST_PANIC.compare_and_swap(true, false, Ordering::SeqCst) {
- let _ = writeln!(err, "note: Run with `RUST_BACKTRACE=1` for a backtrace.");
+ #[cfg(any(not(cargobuild), feature = "backtrace"))]
+ {
+ use sync::atomic::{AtomicBool, Ordering};
+
+ static FIRST_PANIC: AtomicBool = AtomicBool::new(true);
+
+ if log_backtrace {
+ let _ = backtrace::write(err);
+ } else if FIRST_PANIC.compare_and_swap(true, false, Ordering::SeqCst) {
+ let _ = writeln!(err, "note: Run with `RUST_BACKTRACE=1` for a backtrace.");
+ }
}
};
pub mod args;
pub mod at_exit_imp;
+#[cfg(any(not(cargobuild), feature = "backtrace"))]
pub mod backtrace;
pub mod condvar;
pub mod io;
pub mod util;
pub mod wtf8;
+#[cfg(any(not(cargobuild), feature = "backtrace"))]
#[cfg(any(all(unix, not(any(target_os = "macos", target_os = "ios", target_os = "emscripten"))),
all(windows, target_env = "gnu")))]
pub mod gnu;
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
fn write_str_escaped(f: &mut fmt::Formatter, s: &str) -> fmt::Result {
use fmt::Write;
- for c in s.chars().flat_map(|c| c.escape_default()) {
+ for c in s.chars().flat_map(|c| c.escape_debug()) {
f.write_char(c)?
}
Ok(())
#[test]
fn wtf8buf_show() {
- let mut string = Wtf8Buf::from_str("a\té 💩\r");
+ let mut string = Wtf8Buf::from_str("a\té \u{7f}💩\r");
string.push(CodePoint::from_u32(0xD800).unwrap());
- assert_eq!(format!("{:?}", string), r#""a\t\u{e9} \u{1f4a9}\r\u{D800}""#);
+ assert_eq!(format!("{:?}", string), "\"a\\té \\u{7f}\u{1f4a9}\\r\\u{D800}\"");
}
#[test]
pub trait PermissionsExt {
/// Returns the underlying raw `mode_t` bits that are the standard Unix
/// permissions for this file.
+ ///
+ /// # Examples
+ ///
+ /// ```rust,ignore
+ /// use std::fs::File;
+ /// use std::os::unix::fs::PermissionsExt;
+ ///
+ /// let f = try!(File::create("foo.txt"));
+ /// let metadata = try!(f.metadata());
+ /// let permissions = metadata.permissions();
+ ///
+ /// println!("permissions: {}", permissions.mode());
+ /// ```
#[stable(feature = "fs_ext", since = "1.1.0")]
fn mode(&self) -> u32;
/// Sets the underlying raw bits for this set of permissions.
+ ///
+ /// # Examples
+ ///
+ /// ```rust,ignore
+ /// use std::fs::File;
+ /// use std::os::unix::fs::PermissionsExt;
+ ///
+ /// let f = try!(File::create("foo.txt"));
+ /// let metadata = try!(f.metadata());
+ /// let mut permissions = metadata.permissions();
+ ///
+ /// permissions.set_mode(0o644); // Read/write for owner and read for others.
+ /// assert_eq!(permissions.mode(), 0o644);
+ /// ```
#[stable(feature = "fs_ext", since = "1.1.0")]
fn set_mode(&mut self, mode: u32);
/// Creates a new instance of `Permissions` from the given set of Unix
/// permission bits.
+ ///
+ /// # Examples
+ ///
+ /// ```rust,ignore
+ /// use std::fs::Permissions;
+ /// use std::os::unix::fs::PermissionsExt;
+ ///
+ /// // Read/write for owner and read for others.
+ /// let permissions = Permissions::from_mode(0o644);
+ /// assert_eq!(permissions.mode(), 0o644);
+ /// ```
#[stable(feature = "fs_ext", since = "1.1.0")]
fn from_mode(mode: u32) -> Self;
}
/// If no `mode` is set, the default of `0o666` will be used.
/// The operating system masks out bits with the systems `umask`, to produce
/// the final permissions.
+ ///
+ /// # Examples
+ ///
+ /// ```rust,ignore
+ /// extern crate libc;
+ /// use std::fs::OpenOptions;
+ /// use std::os::unix::fs::OpenOptionsExt;
+ ///
+ /// let mut options = OpenOptions::new();
+ /// options.mode(0o644); // Give read/write for owner and read for others.
+ /// let file = options.open("foo.txt");
+ /// ```
#[stable(feature = "fs_ext", since = "1.1.0")]
fn mode(&mut self, mode: u32) -> &mut Self;
pub mod weak;
pub mod android;
+#[cfg(any(not(cargobuild), feature = "backtrace"))]
pub mod backtrace;
pub mod condvar;
pub mod ext;
// this option, however, was added in 2.6.27, and we still support
// 2.6.18 as a kernel, so if the returned error is EINVAL we
// fallthrough to the fallback.
- if cfg!(linux) {
+ if cfg!(target_os = "linux") {
match cvt(libc::socket(fam, ty | SOCK_CLOEXEC, 0)) {
Ok(fd) => return Ok(Socket(FileDesc::new(fd))),
Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {}
let mut fds = [0, 0];
// Like above, see if we can set cloexec atomically
- if cfg!(linux) {
+ if cfg!(target_os = "linux") {
match cvt(libc::socketpair(fam, ty | SOCK_CLOEXEC, 0, fds.as_mut_ptr())) {
Ok(_) => {
return Ok((Socket(FileDesc::new(fds[0])), Socket(FileDesc::new(fds[1]))));
use ast;
use ast::{AttrId, Attribute, Attribute_, MetaItem, MetaItemKind};
use ast::{Expr, Item, Local, Stmt, StmtKind};
-use codemap::{spanned, dummy_spanned, Spanned};
-use syntax_pos::{Span, BytePos};
+use codemap::{respan, spanned, dummy_spanned, Spanned};
+use syntax_pos::{Span, BytePos, DUMMY_SP};
use errors::Handler;
use feature_gate::{Features, GatedCfg};
use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
/// Gets a list of inner meta items from a list MetaItem type.
fn meta_item_list(&self) -> Option<&[P<MetaItem>]>;
+ /// Indicates if the attribute is a Word.
+ fn is_word(&self) -> bool;
+
+ /// Indicates if the attribute is a Value String.
+ fn is_value_str(&self) -> bool {
+ self.value_str().is_some()
+ }
+
+ /// Indicates if the attribute is a Meta-Item List.
+ fn is_meta_item_list(&self) -> bool {
+ self.meta_item_list().is_some()
+ }
+
fn span(&self) -> Span;
}
self.meta().value_str()
}
fn meta_item_list(&self) -> Option<&[P<MetaItem>]> {
- self.node.value.meta_item_list()
+ self.meta().meta_item_list()
}
+
+ fn is_word(&self) -> bool { self.meta().is_word() }
+
fn span(&self) -> Span { self.meta().span }
}
_ => None
}
}
+
+ fn is_word(&self) -> bool {
+ match self.node {
+ MetaItemKind::Word(_) => true,
+ _ => false,
+ }
+ }
+
fn span(&self) -> Span { self.span }
}
fn meta_item_list(&self) -> Option<&[P<MetaItem>]> {
(**self).meta_item_list()
}
+ fn is_word(&self) -> bool { (**self).is_word() }
+ fn is_value_str(&self) -> bool { (**self).is_value_str() }
+ fn is_meta_item_list(&self) -> bool { (**self).is_meta_item_list() }
fn span(&self) -> Span { (**self).span() }
}
pub fn mk_name_value_item_str(name: InternedString, value: InternedString)
-> P<MetaItem> {
let value_lit = dummy_spanned(ast::LitKind::Str(value, ast::StrStyle::Cooked));
- mk_name_value_item(name, value_lit)
+ mk_spanned_name_value_item(DUMMY_SP, name, value_lit)
}
pub fn mk_name_value_item(name: InternedString, value: ast::Lit)
-> P<MetaItem> {
- P(dummy_spanned(MetaItemKind::NameValue(name, value)))
+ mk_spanned_name_value_item(DUMMY_SP, name, value)
}
pub fn mk_list_item(name: InternedString, items: Vec<P<MetaItem>>) -> P<MetaItem> {
- P(dummy_spanned(MetaItemKind::List(name, items)))
+ mk_spanned_list_item(DUMMY_SP, name, items)
}
pub fn mk_word_item(name: InternedString) -> P<MetaItem> {
- P(dummy_spanned(MetaItemKind::Word(name)))
+ mk_spanned_word_item(DUMMY_SP, name)
+}
+
+pub fn mk_spanned_name_value_item(sp: Span, name: InternedString, value: ast::Lit)
+ -> P<MetaItem> {
+ P(respan(sp, MetaItemKind::NameValue(name, value)))
+}
+
+pub fn mk_spanned_list_item(sp: Span, name: InternedString, items: Vec<P<MetaItem>>)
+ -> P<MetaItem> {
+ P(respan(sp, MetaItemKind::List(name, items)))
+}
+
+pub fn mk_spanned_word_item(sp: Span, name: InternedString) -> P<MetaItem> {
+ P(respan(sp, MetaItemKind::Word(name)))
}
+
+
thread_local! { static NEXT_ATTR_ID: Cell<usize> = Cell::new(0) }
pub fn mk_attr_id() -> AttrId {
/// Returns an inner attribute with the given value.
pub fn mk_attr_inner(id: AttrId, item: P<MetaItem>) -> Attribute {
- dummy_spanned(Attribute_ {
- id: id,
- style: ast::AttrStyle::Inner,
- value: item,
- is_sugared_doc: false,
- })
+ mk_spanned_attr_inner(DUMMY_SP, id, item)
+}
+
+/// Returns an innter attribute with the given value and span.
+pub fn mk_spanned_attr_inner(sp: Span, id: AttrId, item: P<MetaItem>) -> Attribute {
+ respan(sp,
+ Attribute_ {
+ id: id,
+ style: ast::AttrStyle::Inner,
+ value: item,
+ is_sugared_doc: false,
+ })
}
+
/// Returns an outer attribute with the given value.
pub fn mk_attr_outer(id: AttrId, item: P<MetaItem>) -> Attribute {
+ mk_spanned_attr_outer(DUMMY_SP, id, item)
+}
+
+/// Returns an outer attribute with the given value and span.
+pub fn mk_spanned_attr_outer(sp: Span, id: AttrId, item: P<MetaItem>) -> Attribute {
+ respan(sp,
+ Attribute_ {
+ id: id,
+ style: ast::AttrStyle::Outer,
+ value: item,
+ is_sugared_doc: false,
+ })
+}
+
+pub fn mk_doc_attr_outer(id: AttrId, item: P<MetaItem>, is_sugared_doc: bool) -> Attribute {
dummy_spanned(Attribute_ {
id: id,
style: ast::AttrStyle::Outer,
value: item,
- is_sugared_doc: false,
+ is_sugared_doc: is_sugared_doc,
})
}
};
let err_count = sess.span_diagnostic.err_count();
- let krate_attrs = strip_unconfigured.process_cfg_attrs(krate.attrs.clone());
+ let krate_attrs = strip_unconfigured.configure(krate.attrs.clone()).unwrap_or_default();
features = get_features(&sess.span_diagnostic, &krate_attrs);
if err_count < sess.span_diagnostic.err_count() {
krate.attrs = krate_attrs.clone(); // Avoid reconfiguring malformed `cfg_attr`s
}
fn attribute(&self, sp: Span, mi: P<ast::MetaItem>) -> ast::Attribute {
- respan(sp, ast::Attribute_ {
- id: attr::mk_attr_id(),
- style: ast::AttrStyle::Outer,
- value: mi,
- is_sugared_doc: false,
- })
+ attr::mk_spanned_attr_outer(sp, attr::mk_attr_id(), mi)
}
fn meta_word(&self, sp: Span, w: InternedString) -> P<ast::MetaItem> {
- P(respan(sp, ast::MetaItemKind::Word(w)))
+ attr::mk_spanned_word_item(sp, w)
}
- fn meta_list(&self,
- sp: Span,
- name: InternedString,
- mis: Vec<P<ast::MetaItem>> )
+ fn meta_list(&self, sp: Span, name: InternedString, mis: Vec<P<ast::MetaItem>>)
-> P<ast::MetaItem> {
- P(respan(sp, ast::MetaItemKind::List(name, mis)))
+ attr::mk_spanned_list_item(sp, name, mis)
}
- fn meta_name_value(&self,
- sp: Span,
- name: InternedString,
- value: ast::LitKind)
+ fn meta_name_value(&self, sp: Span, name: InternedString, value: ast::LitKind)
-> P<ast::MetaItem> {
- P(respan(sp, ast::MetaItemKind::NameValue(name, respan(sp, value))))
+ attr::mk_spanned_name_value_item(sp, name, respan(sp, value))
}
fn item_use(&self, sp: Span,
};
if is_use {
- match attr.node.value.node {
- ast::MetaItemKind::Word(..) => (),
- _ => fld.cx.span_err(attr.span, "arguments to macro_use are not allowed here"),
+ if !attr.is_word() {
+ fld.cx.span_err(attr.span, "arguments to macro_use are not allowed here");
}
return true;
}
use errors::{Handler, DiagnosticBuilder};
use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal};
use parse::token::{DocComment, MatchNt, SubstNt};
-use parse::token::{Token, NtIdent, SpecialMacroVar};
+use parse::token::{Token, Interpolated, NtIdent, NtTT, SpecialMacroVar};
use parse::token;
use parse::lexer::TokenAndSpan;
use tokenstream::{self, TokenTree};
}
// FIXME #2887: think about span stuff here
TokenTree::Token(sp, SubstNt(ident)) => {
- r.stack.last_mut().unwrap().idx += 1;
match lookup_cur_matched(r, ident) {
None => {
+ r.stack.last_mut().unwrap().idx += 1;
r.cur_span = sp;
r.cur_tok = SubstNt(ident);
return ret_val;
// (a) idents can be in lots of places, so it'd be a pain
// (b) we actually can, since it's a token.
MatchedNonterminal(NtIdent(ref sn)) => {
+ r.stack.last_mut().unwrap().idx += 1;
r.cur_span = sn.span;
r.cur_tok = token::Ident(sn.node);
return ret_val;
}
+ MatchedNonterminal(NtTT(ref tt)) => {
+ r.stack.push(TtFrame {
+ forest: TokenTree::Token(sp, Interpolated(NtTT(tt.clone()))),
+ idx: 0,
+ dotdotdoted: false,
+ sep: None,
+ });
+ }
MatchedNonterminal(ref other_whole_nt) => {
+ r.stack.last_mut().unwrap().idx += 1;
// FIXME(pcwalton): Bad copy.
r.cur_span = sp;
- r.cur_tok = token::Interpolated((*other_whole_nt).clone());
+ r.cur_tok = Interpolated((*other_whole_nt).clone());
return ret_val;
}
MatchedSeq(..) => {
is just used for rustc unit tests \
and will never be stable",
cfg_fn!(rustc_attrs))),
+ ("rustc_partition_reused", Whitelisted, Gated("rustc_attrs",
+ "this attribute \
+ is just used for rustc unit tests \
+ and will never be stable",
+ cfg_fn!(rustc_attrs))),
+ ("rustc_partition_translated", Whitelisted, Gated("rustc_attrs",
+ "this attribute \
+ is just used for rustc unit tests \
+ and will never be stable",
+ cfg_fn!(rustc_attrs))),
("rustc_symbol_name", Whitelisted, Gated("rustc_attrs",
"internal rustc attributes will never be stable",
cfg_fn!(rustc_attrs))),
}
Some(list) => {
for mi in list {
- let name = match mi.node {
- ast::MetaItemKind::Word(ref word) => (*word).clone(),
- _ => {
- span_err!(span_handler, mi.span, E0556,
- "malformed feature, expected just one word");
- continue
- }
- };
+ let name = if mi.is_word() {
+ mi.name()
+ } else {
+ span_err!(span_handler, mi.span, E0556,
+ "malformed feature, expected just one word");
+ continue
+ };
if let Some(&(_, _, _, setter)) = ACTIVE_FEATURES.iter()
.find(|& &(n, _, _, _)| name == n) {
*(setter(&mut features)) = true;
}
TokenTree::Token(_, token::SpecialVarNt(..)) => 2,
TokenTree::Token(_, token::MatchNt(..)) => 3,
+ TokenTree::Token(_, token::Interpolated(Nonterminal::NtTT(..))) => 1,
TokenTree::Delimited(_, ref delimed) => delimed.tts.len() + 2,
TokenTree::Sequence(_, ref seq) => seq.tts.len(),
TokenTree::Token(..) => 0,
TokenTree::Token(sp, token::Ident(kind))];
v[index].clone()
}
+ (&TokenTree::Token(_, token::Interpolated(Nonterminal::NtTT(ref tt))), _) => {
+ tt.clone().unwrap()
+ }
(&TokenTree::Sequence(_, ref seq), _) => seq.tts[index].clone(),
_ => panic!("Cannot expand a token tree"),
}
//! The compiler code necessary to implement the `#[derive]` extensions.
-use syntax::ast::{self, MetaItem, MetaItemKind};
+use syntax::ast::{MetaItem, self};
use syntax::attr::AttrMetaMethods;
use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxEnv};
use syntax::ext::base::{MultiDecorator, MultiItemDecorator, MultiModifier};
let mut eq_span = None;
for titem in traits.iter().rev() {
- let tname = match titem.node {
- MetaItemKind::Word(ref tname) => tname,
- _ => {
- cx.span_err(titem.span, "malformed `derive` entry");
- continue;
- }
- };
-
- if !(is_builtin_trait(tname) || cx.ecfg.enable_custom_derive()) {
+ let tname = if titem.is_word() {
+ titem.name() }
+ else {
+ cx.span_err(titem.span, "malformed `derive` entry");
+ continue;
+ };
+
+ if !(is_builtin_trait(&tname) || cx.ecfg.enable_custom_derive()) {
feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic,
"custom_derive",
titem.span,
let arg_idx = match arg_index_consumed.get_mut(i) {
None => 0, // error already emitted elsewhere
Some(offset) => {
- let arg_idx = self.arg_index_map[i][*offset];
+ let ref idx_map = self.arg_index_map[i];
+ // unwrap_or branch: error already emitted elsewhere
+ let arg_idx = *idx_map.get(*offset).unwrap_or(&0);
*offset += 1;
arg_idx
}
}
}
+ pub fn from_span(primary_span: Span) -> MultiSpan {
+ MultiSpan {
+ primary_spans: vec![primary_span],
+ span_labels: vec![]
+ }
+ }
+
+ pub fn from_spans(vec: Vec<Span>) -> MultiSpan {
+ MultiSpan {
+ primary_spans: vec,
+ span_labels: vec![]
+ }
+ }
+
pub fn push_span_label(&mut self, span: Span, label: String) {
self.span_labels.push((span, label));
}
impl From<Span> for MultiSpan {
fn from(span: Span) -> MultiSpan {
- MultiSpan {
- primary_spans: vec![span],
- span_labels: vec![]
- }
+ MultiSpan::from_span(span)
}
}
// For code appearing from the command line
pub const COMMAND_LINE_EXPN: ExpnId = ExpnId(!1);
+// For code generated by a procedural macro, without knowing which
+// Used in `qquote!`
+pub const PROC_EXPN: ExpnId = ExpnId(!2);
+
impl ExpnId {
pub fn from_u32(id: u32) -> ExpnId {
ExpnId(id)
#![allow(bad_style)]
-use libc;
-
-#[cfg(any(not(target_arch = "arm"), target_os = "ios"))]
-pub use self::_Unwind_Action::*;
-#[cfg(target_arch = "arm")]
-pub use self::_Unwind_State::*;
-pub use self::_Unwind_Reason_Code::*;
-
-#[cfg(any(not(target_arch = "arm"), target_os = "ios"))]
-#[repr(C)]
-#[derive(Clone, Copy)]
-pub enum _Unwind_Action {
- _UA_SEARCH_PHASE = 1,
- _UA_CLEANUP_PHASE = 2,
- _UA_HANDLER_FRAME = 4,
- _UA_FORCE_UNWIND = 8,
- _UA_END_OF_STACK = 16,
+macro_rules! cfg_if {
+ ( $( if #[cfg( $meta:meta )] { $($it1:item)* } else { $($it2:item)* } )* ) =>
+ ( $( $( #[cfg($meta)] $it1)* $( #[cfg(not($meta))] $it2)* )* )
}
-#[cfg(target_arch = "arm")]
-#[repr(C)]
-#[derive(Clone, Copy)]
-pub enum _Unwind_State {
- _US_VIRTUAL_UNWIND_FRAME = 0,
- _US_UNWIND_FRAME_STARTING = 1,
- _US_UNWIND_FRAME_RESUME = 2,
- _US_ACTION_MASK = 3,
- _US_FORCE_UNWIND = 8,
- _US_END_OF_STACK = 16,
-}
+use libc::{c_int, c_void, uintptr_t};
#[repr(C)]
+#[derive(Copy, Clone, PartialEq)]
pub enum _Unwind_Reason_Code {
_URC_NO_REASON = 0,
_URC_FOREIGN_EXCEPTION_CAUGHT = 1,
_URC_HANDLER_FOUND = 6,
_URC_INSTALL_CONTEXT = 7,
_URC_CONTINUE_UNWIND = 8,
- _URC_FAILURE = 9, // used only by ARM EABI
+ _URC_FAILURE = 9, // used only by ARM EHABI
}
+pub use self::_Unwind_Reason_Code::*;
pub type _Unwind_Exception_Class = u64;
-
-pub type _Unwind_Word = libc::uintptr_t;
-pub type _Unwind_Ptr = libc::uintptr_t;
-
-pub type _Unwind_Trace_Fn = extern "C" fn(ctx: *mut _Unwind_Context, arg: *mut libc::c_void)
+pub type _Unwind_Word = uintptr_t;
+pub type _Unwind_Ptr = uintptr_t;
+pub type _Unwind_Trace_Fn = extern "C" fn(ctx: *mut _Unwind_Context, arg: *mut c_void)
-> _Unwind_Reason_Code;
-
#[cfg(target_arch = "x86")]
pub const unwinder_private_data_size: usize = 5;
pub type _Unwind_Exception_Cleanup_Fn = extern "C" fn(unwind_code: _Unwind_Reason_Code,
exception: *mut _Unwind_Exception);
-
-#[cfg_attr(any(all(target_os = "linux", not(target_env = "musl")),
- target_os = "freebsd",
- target_os = "solaris",
- all(target_os = "linux",
- target_env = "musl",
- not(target_arch = "x86"),
- not(target_arch = "x86_64"))),
- link(name = "gcc_s"))]
-#[cfg_attr(all(target_os = "linux",
- target_env = "musl",
- any(target_arch = "x86", target_arch = "x86_64"),
- not(test)),
- link(name = "unwind", kind = "static"))]
-#[cfg_attr(any(target_os = "android", target_os = "openbsd"),
- link(name = "gcc"))]
-#[cfg_attr(all(target_os = "netbsd", not(target_vendor = "rumprun")),
- link(name = "gcc"))]
-#[cfg_attr(all(target_os = "netbsd", target_vendor = "rumprun"),
- link(name = "unwind"))]
-#[cfg_attr(target_os = "dragonfly",
- link(name = "gcc_pic"))]
-#[cfg_attr(target_os = "bitrig",
- link(name = "c++abi"))]
-#[cfg_attr(all(target_os = "windows", target_env = "gnu"),
- link(name = "gcc_eh"))]
-#[cfg(not(cargobuild))]
-extern "C" {}
-
extern "C" {
- // iOS on armv7 uses SjLj exceptions and requires to link
- // against corresponding routine (..._SjLj_...)
- #[cfg(not(all(target_os = "ios", target_arch = "arm")))]
- #[unwind]
- pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
-
- #[cfg(all(target_os = "ios", target_arch = "arm"))]
- #[unwind]
- fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
-
- pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception);
-
#[unwind]
pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !;
-
- // No native _Unwind_Backtrace on iOS
- #[cfg(not(all(target_os = "ios", target_arch = "arm")))]
- pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
- trace_argument: *mut libc::c_void)
- -> _Unwind_Reason_Code;
-
- // available since GCC 4.2.0, should be fine for our purpose
- #[cfg(all(not(all(target_os = "android", target_arch = "arm")),
- not(all(target_os = "linux", target_arch = "arm"))))]
- pub fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context,
- ip_before_insn: *mut libc::c_int)
- -> libc::uintptr_t;
-
- pub fn _Unwind_GetLanguageSpecificData(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
+ pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception);
+ pub fn _Unwind_GetLanguageSpecificData(ctx: *mut _Unwind_Context) -> *mut c_void;
pub fn _Unwind_GetRegionStart(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
pub fn _Unwind_GetTextRelBase(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
pub fn _Unwind_GetDataRelBase(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
- pub fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: libc::c_int, value: _Unwind_Ptr);
- pub fn _Unwind_SetIP(ctx: *mut _Unwind_Context, value: _Unwind_Ptr);
-
- #[cfg(all(not(target_os = "android"),
- not(all(target_os = "linux", target_arch = "arm"))))]
- pub fn _Unwind_FindEnclosingFunction(pc: *mut libc::c_void) -> *mut libc::c_void;
}
-// ... and now we just providing access to SjLj counterspart
-// through a standard name to hide those details from others
-// (see also comment above regarding _Unwind_RaiseException)
-#[cfg(all(target_os = "ios", target_arch = "arm"))]
-#[inline]
-pub unsafe fn _Unwind_RaiseException(exc: *mut _Unwind_Exception) -> _Unwind_Reason_Code {
- _Unwind_SjLj_RaiseException(exc)
-}
+cfg_if! {
+if #[cfg(not(any(all(target_os = "android", target_arch = "arm"),
+ all(target_os = "linux", target_arch = "arm"))))] {
+ // Not ARM EHABI
+ #[repr(C)]
+ #[derive(Copy, Clone, PartialEq)]
+ pub enum _Unwind_Action {
+ _UA_SEARCH_PHASE = 1,
+ _UA_CLEANUP_PHASE = 2,
+ _UA_HANDLER_FRAME = 4,
+ _UA_FORCE_UNWIND = 8,
+ _UA_END_OF_STACK = 16,
+ }
+ pub use self::_Unwind_Action::*;
+
+ extern "C" {
+ pub fn _Unwind_GetGR(ctx: *mut _Unwind_Context, reg_index: c_int) -> _Unwind_Word;
+ pub fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word);
+ pub fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> _Unwind_Word;
+ pub fn _Unwind_SetIP(ctx: *mut _Unwind_Context, value: _Unwind_Word);
+ pub fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context, ip_before_insn: *mut c_int)
+ -> _Unwind_Word;
+ pub fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void;
+ }
+
+} else {
+ // ARM EHABI
+ #[repr(C)]
+ #[derive(Copy, Clone, PartialEq)]
+ pub enum _Unwind_State {
+ _US_VIRTUAL_UNWIND_FRAME = 0,
+ _US_UNWIND_FRAME_STARTING = 1,
+ _US_UNWIND_FRAME_RESUME = 2,
+ _US_ACTION_MASK = 3,
+ _US_FORCE_UNWIND = 8,
+ _US_END_OF_STACK = 16,
+ }
+ pub use self::_Unwind_State::*;
-// On android, the function _Unwind_GetIP is a macro, and this is the
-// expansion of the macro. This is all copy/pasted directly from the
-// header file with the definition of _Unwind_GetIP.
-#[cfg(any(all(target_os = "android", target_arch = "arm"),
- all(target_os = "linux", target_arch = "arm")))]
-pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> libc::uintptr_t {
#[repr(C)]
enum _Unwind_VRS_Result {
_UVRSR_OK = 0,
_UVRSC_WMMXD = 3,
_UVRSC_WMMXC = 4,
}
+ use self::_Unwind_VRS_RegClass::*;
#[repr(C)]
enum _Unwind_VRS_DataRepresentation {
_UVRSD_UINT32 = 0,
_UVRSD_FLOAT = 4,
_UVRSD_DOUBLE = 5,
}
+ use self::_Unwind_VRS_DataRepresentation::*;
+
+ pub const UNWIND_POINTER_REG: c_int = 12;
+ pub const UNWIND_IP_REG: c_int = 15;
- type _Unwind_Word = libc::c_uint;
extern "C" {
fn _Unwind_VRS_Get(ctx: *mut _Unwind_Context,
- klass: _Unwind_VRS_RegClass,
- word: _Unwind_Word,
+ regclass: _Unwind_VRS_RegClass,
+ regno: _Unwind_Word,
+ repr: _Unwind_VRS_DataRepresentation,
+ data: *mut c_void)
+ -> _Unwind_VRS_Result;
+
+ fn _Unwind_VRS_Set(ctx: *mut _Unwind_Context,
+ regclass: _Unwind_VRS_RegClass,
+ regno: _Unwind_Word,
repr: _Unwind_VRS_DataRepresentation,
- data: *mut libc::c_void)
+ data: *mut c_void)
-> _Unwind_VRS_Result;
}
- let mut val: _Unwind_Word = 0;
- let ptr = &mut val as *mut _Unwind_Word;
- let _ = _Unwind_VRS_Get(ctx,
- _Unwind_VRS_RegClass::_UVRSC_CORE,
- 15,
- _Unwind_VRS_DataRepresentation::_UVRSD_UINT32,
- ptr as *mut libc::c_void);
- (val & !1) as libc::uintptr_t
-}
+ // On Android or ARM/Linux, these are implemented as macros:
+
+ pub unsafe fn _Unwind_GetGR(ctx: *mut _Unwind_Context, reg_index: c_int) -> _Unwind_Word {
+ let mut val: _Unwind_Word = 0;
+ _Unwind_VRS_Get(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32,
+ &mut val as *mut _ as *mut c_void);
+ val
+ }
-// This function doesn't exist on Android or ARM/Linux, so make it same
-// to _Unwind_GetIP
-#[cfg(any(all(target_os = "android", target_arch = "arm"),
- all(target_os = "linux", target_arch = "arm")))]
-pub unsafe fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context,
- ip_before_insn: *mut libc::c_int)
- -> libc::uintptr_t {
- *ip_before_insn = 0;
- _Unwind_GetIP(ctx)
+ pub unsafe fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word) {
+ let mut value = value;
+ _Unwind_VRS_Set(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32,
+ &mut value as *mut _ as *mut c_void);
+ }
+
+ pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context)
+ -> _Unwind_Word {
+ let val = _Unwind_GetGR(ctx, UNWIND_IP_REG);
+ (val & !1) as _Unwind_Word
+ }
+
+ pub unsafe fn _Unwind_SetIP(ctx: *mut _Unwind_Context,
+ value: _Unwind_Word) {
+ // Propagate thumb bit to instruction pointer
+ let thumb_state = _Unwind_GetGR(ctx, UNWIND_IP_REG) & 1;
+ let value = value | thumb_state;
+ _Unwind_SetGR(ctx, UNWIND_IP_REG, value);
+ }
+
+ pub unsafe fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context,
+ ip_before_insn: *mut c_int)
+ -> _Unwind_Word {
+ *ip_before_insn = 0;
+ _Unwind_GetIP(ctx)
+ }
+
+ // This function also doesn't exist on Android or ARM/Linux, so make it a no-op
+ pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void {
+ pc
+ }
}
-// This function also doesn't exist on Android or ARM/Linux, so make it
-// a no-op
-#[cfg(any(target_os = "android",
- all(target_os = "linux", target_arch = "arm")))]
-pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut libc::c_void) -> *mut libc::c_void {
- pc
+if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] {
+ // Not 32-bit iOS
+ extern "C" {
+ #[unwind]
+ pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
+ pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
+ trace_argument: *mut c_void)
+ -> _Unwind_Reason_Code;
+ }
+} else {
+ // 32-bit iOS uses SjLj and does not provide _Unwind_Backtrace()
+ extern "C" {
+ #[unwind]
+ pub fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
+ }
+
+ #[inline]
+ pub unsafe fn _Unwind_RaiseException(exc: *mut _Unwind_Exception) -> _Unwind_Reason_Code {
+ _Unwind_SjLj_RaiseException(exc)
+ }
}
+} // cfg_if!
+
+#[cfg_attr(any(all(target_os = "linux", not(target_env = "musl")),
+ target_os = "freebsd",
+ target_os = "solaris",
+ all(target_os = "linux",
+ target_env = "musl",
+ not(target_arch = "x86"),
+ not(target_arch = "x86_64"))),
+ link(name = "gcc_s"))]
+#[cfg_attr(all(target_os = "linux",
+ target_env = "musl",
+ any(target_arch = "x86", target_arch = "x86_64"),
+ not(test)),
+ link(name = "unwind", kind = "static"))]
+#[cfg_attr(any(target_os = "android", target_os = "openbsd"),
+ link(name = "gcc"))]
+#[cfg_attr(all(target_os = "netbsd", not(target_vendor = "rumprun")),
+ link(name = "gcc"))]
+#[cfg_attr(all(target_os = "netbsd", target_vendor = "rumprun"),
+ link(name = "unwind"))]
+#[cfg_attr(target_os = "dragonfly",
+ link(name = "gcc_pic"))]
+#[cfg_attr(target_os = "bitrig",
+ link(name = "c++abi"))]
+#[cfg_attr(all(target_os = "windows", target_env = "gnu"),
+ link(name = "gcc_eh"))]
+#[cfg(not(cargobuild))]
+extern "C" {}
"rustc 0.0.0",
"rustc_back 0.0.0",
"rustc_const_math 0.0.0",
+ "rustc_errors 0.0.0",
"serialize 0.0.0",
"syntax 0.0.0",
"syntax_pos 0.0.0",
[features]
jemalloc = ["std/jemalloc"]
debug-jemalloc = ["std/debug-jemalloc"]
+backtrace = ["std/backtrace"]
let _x: i32 = [1, 2, 3];
//~^ ERROR mismatched types
//~| expected type `i32`
- //~| found type `[_; 3]`
+ //~| found type `[{integer}; 3]`
//~| expected i32, found array of 3 elements
let x: &[i32] = &[1, 2, 3];
const A: &'static [i32] = &[];
const B: i32 = (&A)[1];
-//~^ ERROR index out of bounds: the len is 0 but the index is 1
+//~^ ERROR constant evaluation error
+//~| index out of bounds: the len is 0 but the index is 1
fn main() {
let _ = B;
const A: [i32; 0] = [];
const B: i32 = A[1];
-//~^ ERROR index out of bounds: the len is 0 but the index is 1
+//~^ ERROR constant evaluation error
+//~| index out of bounds: the len is 0 but the index is 1
fn main() {
let _ = B;
const ID: usize;
}
-const X: [i32; <i32 as Foo>::ID] = [0, 1, 2]; //~ ERROR E0250
+const X: [i32; <i32 as Foo>::ID] = [0, 1, 2]; //~ ERROR E0080
fn main() {
assert_eq!(1, X);
impl Foo for SignedBar {
const BAR: i32 = -1;
- //~^ ERROR implemented const `BAR` has an incompatible type for trait
- //~| expected u32,
- //~| found i32 [E0326]
+ //~^ ERROR implemented const `BAR` has an incompatible type for trait [E0326]
+ //~| expected u32, found i32
}
fn main() {}
}
pub fn test<A: Foo, B: Foo>() {
- let _array = [4; <A as Foo>::Y]; //~ error: expected constant integer
+ let _array = [4; <A as Foo>::Y]; //~ ERROR E0080
+ //~| non-constant path in constant
}
fn main() {
let a = 42;
foo1(a);
//~^ ERROR type mismatch resolving
- //~| expected usize
- //~| found struct `Bar`
+ //~| expected usize, found struct `Bar`
baz(&a);
//~^ ERROR type mismatch resolving
- //~| expected usize
- //~| found struct `Bar`
+ //~| expected usize, found struct `Bar`
}
--- /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(rustc_attrs)]
+
+// revisions: good bad
+
+trait Mirror {
+ type Image;
+}
+
+impl<T> Mirror for T {
+ type Image = T;
+}
+
+#[cfg(bad)]
+fn foo<U, T>(_t: T)
+ where for<'a> &'a T: Mirror<Image=U>
+{}
+
+#[cfg(good)]
+fn foo<U, T>(_t: T)
+ where for<'a> &'a T: Mirror<Image=&'a U>
+{}
+
+#[rustc_error]
+fn main() { //[good]~ ERROR compilation successful
+ foo(());
+ //[bad]~^ ERROR type mismatch resolving `for<'a> <&'a _ as Mirror>::Image == _`
+ //[bad]~| expected bound lifetime parameter 'a, found concrete lifetime
+}
static i: String = 10;
//~^ ERROR mismatched types
//~| expected type `std::string::String`
-//~| found type `_`
+//~| found type `{integer}`
//~| expected struct `std::string::String`, found integral variable
fn main() { println!("{}", i); }
f(&x);
//~^ ERROR mismatched types
//~| expected type `&mut i32`
- //~| found type `&_`
+ //~| found type `&{integer}`
//~| values differ in mutability
}
let _: &[i32] = [0];
//~^ ERROR mismatched types
//~| expected type `&[i32]`
- //~| found type `[_; 1]`
+ //~| found type `[{integer}; 1]`
//~| expected &-ptr, found array of 1 elements
}
const BAR: u32 = FOO[5]; // no error, because the error below occurs before regular const eval
const BLUB: [u32; FOO[4]] = [5, 6];
-//~^ ERROR array length constant evaluation error: index out of bounds: the len is 3 but the index is 4 [E0250]
+//~^ ERROR constant evaluation error [E0080]
+//~| index out of bounds: the len is 3 but the index is 4
fn main() {
let _ = BAR;
}
fn main() {
- let _ = [0; f(2)]; //~ ERROR: non-constant path in constant expression [E0307]
+ let _ = [0; f(2)]; //~ ERROR constant evaluation error [E0080]
+ //~| non-constant path in constant expression
}
// Make sure that the two uses get two errors.
const FOO: u8 = [5u8][1];
-//~^ ERROR index out of bounds: the len is 1 but the index is 1
-//~^^ ERROR index out of bounds: the len is 1 but the index is 1
+//~^ ERROR constant evaluation error
+//~| index out of bounds: the len is 1 but the index is 1
+//~^^^ ERROR constant evaluation error
+//~| index out of bounds: the len is 1 but the index is 1
fn main() {
let a = -std::i8::MIN;
- //~^ WARN attempted to negate with overflow
+ //~^ WARN this expression will panic at run-time
+ //~| attempted to negate with overflow
let b = 200u8 + 200u8 + 200u8;
- //~^ WARN attempted to add with overflow
- //~| WARN attempted to add with overflow
+ //~^ WARN this expression will panic at run-time
+ //~| attempted to add with overflow
+ //~^^^ WARN this expression will panic at run-time
+ //~| attempted to add with overflow
let c = 200u8 * 4;
- //~^ WARN attempted to multiply with overflow
+ //~^ WARN this expression will panic at run-time
+ //~| attempted to multiply with overflow
let d = 42u8 - (42u8 + 1);
- //~^ WARN attempted to subtract with overflow
+ //~^ WARN this expression will panic at run-time
+ //~| attempted to subtract with overflow
let _e = [5u8][1];
- //~^ WARN index out of bounds: the len is 1 but the index is 1
+ //~^ WARN this expression will panic at run-time
+ //~| index out of bounds: the len is 1 but the index is 1
black_box(a);
black_box(b);
black_box(c);
const NEG_128: i8 = -128;
const NEG_NEG_128: i8 = -NEG_128;
-//~^ ERROR constant evaluation error: attempted to negate with overflow
-//~| ERROR attempted to negate with overflow
-//~| ERROR attempted to negate with overflow
+//~^ ERROR constant evaluation error
+//~| attempted to negate with overflow
+//~| ERROR constant evaluation error
+//~| attempted to negate with overflow
+//~| ERROR constant evaluation error
+//~| attempted to negate with overflow
fn main() {
match -128i8 {
- NEG_NEG_128 => println!("A"), //~ NOTE in pattern here
+ NEG_NEG_128 => println!("A"), //~ NOTE for pattern here
_ => println!("B"),
}
}
// self-hosted and a cross-compiled setup; therefore resorting to
// error-pattern for now.
-// error-pattern: expected constant integer for repeat count, but attempted to add with overflow
+// error-pattern: attempted to add with overflow
#![allow(unused_imports)]
const A_I8_T
: [u32; (i8::MAX as i8 + 1u8) as usize]
- //~^ ERROR mismatched types:
- //~| expected `i8`,
- //~| found `u8` [E0250]
+ //~^ ERROR constant evaluation error [E0080]
+ //~| expected i8, found u8
= [0; (i8::MAX as usize) + 1];
const A_BAD_CHAR_USIZE
: [u32; 5i8 as char as usize]
- //~^ ERROR only `u8` can be cast as `char`, not `i8`
+ //~^ ERROR constant evaluation error
+ //~| only `u8` can be cast as `char`, not `i8`
= [0; 5];
fn main() {}
const VALS_I8: (i8, i8, i8, i8) =
(-i8::MIN,
- //~^ ERROR attempted to negate with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to negate with overflow
i8::MIN - 1,
- //~^ ERROR attempted to subtract with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to subtract with overflow
i8::MAX + 1,
- //~^ ERROR attempted to add with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to add with overflow
i8::MIN * 2,
- //~^ ERROR attempted to multiply with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to multiply with overflow
);
const VALS_I16: (i16, i16, i16, i16) =
(-i16::MIN,
- //~^ ERROR attempted to negate with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to negate with overflow
i16::MIN - 1,
- //~^ ERROR attempted to subtract with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to subtract with overflow
i16::MAX + 1,
- //~^ ERROR attempted to add with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to add with overflow
i16::MIN * 2,
- //~^ ERROR attempted to multiply with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to multiply with overflow
);
const VALS_I32: (i32, i32, i32, i32) =
(-i32::MIN,
- //~^ ERROR attempted to negate with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to negate with overflow
i32::MIN - 1,
- //~^ ERROR attempted to subtract with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to subtract with overflow
i32::MAX + 1,
- //~^ ERROR attempted to add with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to add with overflow
i32::MIN * 2,
- //~^ ERROR attempted to multiply with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to multiply with overflow
);
const VALS_I64: (i64, i64, i64, i64) =
(-i64::MIN,
- //~^ ERROR attempted to negate with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to negate with overflow
i64::MIN - 1,
- //~^ ERROR attempted to subtract with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to subtract with overflow
i64::MAX + 1,
- //~^ ERROR attempted to add with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to add with overflow
i64::MAX * 2,
- //~^ ERROR attempted to multiply with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to multiply with overflow
);
const VALS_U8: (u8, u8, u8, u8) =
(-(u8::MIN as i8) as u8,
u8::MIN - 1,
- //~^ ERROR attempted to subtract with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to subtract with overflow
u8::MAX + 1,
- //~^ ERROR attempted to add with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to add with overflow
u8::MAX * 2,
- //~^ ERROR attempted to multiply with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to multiply with overflow
);
const VALS_U16: (u16, u16, u16, u16) =
(-(u16::MIN as i16) as u16,
u16::MIN - 1,
- //~^ ERROR attempted to subtract with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to subtract with overflow
u16::MAX + 1,
- //~^ ERROR attempted to add with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to add with overflow
u16::MAX * 2,
- //~^ ERROR attempted to multiply with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to multiply with overflow
);
const VALS_U32: (u32, u32, u32, u32) =
(-(u32::MIN as i32) as u32,
u32::MIN - 1,
- //~^ ERROR attempted to subtract with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to subtract with overflow
u32::MAX + 1,
- //~^ ERROR attempted to add with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to add with overflow
u32::MAX * 2,
- //~^ ERROR attempted to multiply with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to multiply with overflow
);
const VALS_U64: (u64, u64, u64, u64) =
(-(u64::MIN as i64) as u64,
u64::MIN - 1,
- //~^ ERROR attempted to subtract with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to subtract with overflow
u64::MAX + 1,
- //~^ ERROR attempted to add with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to add with overflow
u64::MAX * 2,
- //~^ ERROR attempted to multiply with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to multiply with overflow
);
fn main() {
struct S(i32);
const CONSTANT: S = S(0);
-//~^ ERROR: unimplemented constant expression: tuple struct constructors [E0080]
+//~^ ERROR E0080
+//~| unimplemented constant expression: tuple struct constructors
enum E {
V = CONSTANT,
for i in 0..x {
sum += i;
}
- sum //~ ERROR: E0250
+ sum //~ ERROR E0080
+ //~| non-constant path in constant
}
#[allow(unused_variables)]
fn main() {
- let a : [i32; f(X)];
+ let a : [i32; f(X)]; //~ NOTE for array length here
}
// except according to those terms.
const ARR: [usize; 1] = [2];
-const ARR2: [i32; ARR[0]] = [5, 6]; //~ ERROR unstable
+const ARR2: [i32; ARR[0]] = [5, 6]; //~ ERROR E0080
+ //~| unstable
fn main() {
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-const X: usize = 42 && 39; //~ ERROR: can't do this op on integrals
+const X: usize = 42 && 39; //~ ERROR E0080
+ //~| can't do this op on integrals
const ARR: [i32; X] = [99; 34]; //~ NOTE: for array length here
-const X1: usize = 42 || 39; //~ ERROR: can't do this op on integrals
+const X1: usize = 42 || 39; //~ ERROR E0080
+ //~| can't do this op on integrals
const ARR1: [i32; X1] = [99; 47]; //~ NOTE: for array length here
-const X2: usize = -42 || -39; //~ ERROR: unary negation of unsigned integer
+const X2: usize = -42 || -39; //~ ERROR E0080
+ //~| unary negation of unsigned integer
const ARR2: [i32; X2] = [99; 18446744073709551607]; //~ NOTE: for array length here
-const X3: usize = -42 && -39; //~ ERROR: unary negation of unsigned integer
+const X3: usize = -42 && -39; //~ ERROR E0080
+ //~| unary negation of unsigned integer
const ARR3: [i32; X3] = [99; 6]; //~ NOTE: for array length here
const Y: usize = 42.0 == 42.0;
-const ARRR: [i32; Y] = [99; 1]; //~ ERROR: expected usize value for array length
+const ARRR: [i32; Y] = [99; 1]; //~ ERROR: expected usize for array length
const Y1: usize = 42.0 >= 42.0;
-const ARRR1: [i32; Y] = [99; 1]; //~ ERROR: expected usize value for array length
+const ARRR1: [i32; Y] = [99; 1]; //~ ERROR: expected usize for array length
const Y2: usize = 42.0 <= 42.0;
-const ARRR2: [i32; Y] = [99; 1]; //~ ERROR: expected usize value for array length
+const ARRR2: [i32; Y] = [99; 1]; //~ ERROR: expected usize for array length
const Y3: usize = 42.0 > 42.0;
-const ARRR3: [i32; Y] = [99; 0]; //~ ERROR: expected usize value for array length
+const ARRR3: [i32; Y] = [99; 0]; //~ ERROR: expected usize for array length
const Y4: usize = 42.0 < 42.0;
-const ARRR4: [i32; Y] = [99; 0]; //~ ERROR: expected usize value for array length
+const ARRR4: [i32; Y] = [99; 0]; //~ ERROR: expected usize for array length
const Y5: usize = 42.0 != 42.0;
-const ARRR5: [i32; Y] = [99; 0]; //~ ERROR: expected usize value for array length
+const ARRR5: [i32; Y] = [99; 0]; //~ ERROR: expected usize for array length
fn main() {
let _ = ARR;
const ONE: usize = 1;
const TWO: usize = 2;
const LEN: usize = ONE - TWO;
-//~^ ERROR array length constant evaluation error: attempted to subtract with overflow [E0250]
+//~^ ERROR E0080
+//~| attempted to subtract with overflow
fn main() {
let a: [i8; LEN] = unimplemented!();
fn main() {
let a: [i8; ONE - TWO] = unimplemented!();
- //~^ ERROR array length constant evaluation error: attempted to subtract with overflow [E0250]
+ //~^ ERROR constant evaluation error [E0080]
+ //~| attempted to subtract with overflow
}
use Cake::*;
const BOO: (Cake, Cake) = (Marmor, BlackForest);
-//~^ ERROR: constant evaluation error: unimplemented constant expression: enum variants [E0471]
+//~^ ERROR: constant evaluation error [E0080]
+//~| unimplemented constant expression: enum variants
const FOO: Cake = BOO.1;
const fn foo() -> Cake {
- Marmor //~ ERROR: constant evaluation error: unimplemented constant expression: enum variants
- //~^ ERROR: unimplemented constant expression: enum variants
+ Marmor
+ //~^ ERROR: constant evaluation error [E0080]
+ //~| unimplemented constant expression: enum variants
+ //~^^^ ERROR: constant evaluation error [E0080]
+ //~| unimplemented constant expression: enum variants
}
const WORKS: Cake = Marmor;
-const GOO: Cake = foo();
+const GOO: Cake = foo(); //~ NOTE for expression here
fn main() {
match BlackForest {
- FOO => println!("hi"), //~ NOTE: in pattern here
- GOO => println!("meh"), //~ NOTE: in pattern here
+ FOO => println!("hi"), //~ NOTE: for pattern here
+ GOO => println!("meh"), //~ NOTE: for pattern here
WORKS => println!("möp"),
_ => println!("bye"),
}
const FOO: &'static[u32] = &[1, 2, 3];
const BAR: u32 = FOO[5];
-//~^ ERROR index out of bounds: the len is 3 but the index is 5
+//~^ ERROR constant evaluation error [E0080]
+//~| index out of bounds: the len is 3 but the index is 5
fn main() {
let _ = BAR;
// Test spans of errors
const TUP: (usize,) = 5 << 64;
-//~^ ERROR: attempted to shift left with overflow [E0250]
+//~^ ERROR E0080
+//~| attempted to shift left with overflow
const ARR: [i32; TUP.0] = [];
fn main() {
Ok = i8::MAX - 1,
Ok2,
OhNo = 0_u8,
- //~^ ERROR mismatched types
+ //~^ ERROR E0080
+ //~| expected i8, found u8
}
let x = A::Ok;
Ok = u8::MAX - 1,
Ok2,
OhNo = 0_i8,
- //~^ ERROR mismatched types
+ //~^ ERROR E0080
+ //~| expected u8, found i8
}
let x = A::Ok;
Ok = i16::MAX - 1,
Ok2,
OhNo = 0_u16,
- //~^ ERROR mismatched types
+ //~^ ERROR E0080
+ //~| expected i16, found u16
}
let x = A::Ok;
Ok = u16::MAX - 1,
Ok2,
OhNo = 0_i16,
- //~^ ERROR mismatched types
+ //~^ ERROR E0080
+ //~| expected u16, found i16
}
let x = A::Ok;
Ok = i32::MAX - 1,
Ok2,
OhNo = 0_u32,
- //~^ ERROR mismatched types
+ //~^ ERROR E0080
+ //~| expected i32, found u32
}
let x = A::Ok;
Ok = u32::MAX - 1,
Ok2,
OhNo = 0_i32,
- //~^ ERROR mismatched types
+ //~^ ERROR E0080
+ //~| expected u32, found i32
}
let x = A::Ok;
Ok = i64::MAX - 1,
Ok2,
OhNo = 0_u64,
- //~^ ERROR mismatched types
+ //~^ ERROR E0080
+ //~| expected i64, found u64
}
let x = A::Ok;
Ok = u64::MAX - 1,
Ok2,
OhNo = 0_i64,
- //~^ ERROR mismatched types
+ //~^ ERROR E0080
+ //~| expected u64, found i64
}
let x = A::Ok;
enum Eu8 {
Au8 = 23,
Bu8 = 223,
- Cu8 = -23, //~ ERROR unary negation of unsigned integer
+ Cu8 = -23, //~ ERROR E0080
+ //~| unary negation of unsigned integer
}
#[repr(u16)]
enum Eu16 {
Au16 = 23,
Bu16 = 55555,
- Cu16 = -22333, //~ ERROR unary negation of unsigned integer
+ Cu16 = -22333, //~ ERROR E0080
+ //~| unary negation of unsigned integer
}
#[repr(u32)]
enum Eu32 {
Au32 = 23,
Bu32 = 3_000_000_000,
- Cu32 = -2_000_000_000, //~ ERROR unary negation of unsigned integer
+ Cu32 = -2_000_000_000, //~ ERROR E0080
+ //~| unary negation of unsigned integer
}
#[repr(u64)]
enum Eu64 {
Au32 = 23,
Bu32 = 3_000_000_000,
- Cu32 = -2_000_000_000, //~ ERROR unary negation of unsigned integer
+ Cu32 = -2_000_000_000, //~ ERROR E0080
+ //~| unary negation of unsigned integer
}
// u64 currently allows negative numbers, and i64 allows numbers greater than `1<<63`. This is a
// except according to those terms.
enum test {
- div_zero = 1/0, //~ERROR constant evaluation error: attempted to divide by zero
+ div_zero = 1/0, //~ ERROR E0080
+ //~| attempted to divide by zero
rem_zero = 1%0,
-//~^ ERROR constant evaluation error: attempted to calculate the remainder with a divisor of zero
+ //~^ ERROR E0080
+ //~| attempted to calculate the remainder with a divisor of zero
}
fn main() {}
}
impl<'a,'b> Foo<'a,'b> {
- fn bar(self: Foo<'b,'a>) {}
- //~^ ERROR mismatched types
+ fn bar(
+ self
+ //~^ ERROR mismatched method receiver
//~| expected type `Foo<'a, 'b>`
//~| found type `Foo<'b, 'a>`
//~| lifetime mismatch
- //~| ERROR mismatched types
+ //~| ERROR mismatched method receiver
//~| expected type `Foo<'a, 'b>`
//~| found type `Foo<'b, 'a>`
//~| lifetime mismatch
+ : Foo<'b,'a>) {}
}
fn main() {}
fn main() {
let a = -1;
- //~^ ERROR unary negation of unsigned integer
+ //~^ ERROR E0080
+ //~| unary negation of unsigned integer
let _b : u8 = a; // for infering variable a to u8.
let _d = -1u8;
- //~^ ERROR unary negation of unsigned integer
+ //~^ ERROR E0080
+ //~| unary negation of unsigned integer
for _ in -10..10u8 {}
- //~^ ERROR unary negation of unsigned integer
+ //~^ ERROR E0080
+ //~| unary negation of unsigned integer
-S; // should not trigger the gate; issue 26840
}
x = 5;
//~^ ERROR mismatched types
//~| expected type `std::option::Option<usize>`
- //~| found type `_`
+ //~| found type `{integer}`
//~| expected enum `std::option::Option`, found integral variable
}
if let Some(b) = None { //~ ERROR: `if let` arms have incompatible types
//~^ expected (), found integral variable
//~| expected type `()`
- //~| found type `_`
+ //~| found type `{integer}`
()
} else { //~ NOTE: `if let` arm with an incompatible type
1
//~^ ERROR invalid reference to argument `0` (no arguments given)
//~^^ ERROR invalid reference to argument `1` (no arguments given)
+ // bad named arguments, #35082
+
+ format!("{valuea} {valueb}", valuea=5, valuec=7);
+ //~^ ERROR there is no argument named `valueb`
+ //~^^ ERROR named argument never used
+
// bad syntax of the format string
format!("{"); //~ ERROR: expected `'}'` but string was terminated
fn main() {
fn bar<T>(_: T) {}
- [0][0u8]; //~ ERROR: `[_]: std::ops::Index<u8>` is not satisfied
+ [0][0u8]; //~ ERROR: `[{integer}]: std::ops::Index<u8>` is not satisfied
[0][0]; // should infer to be a usize
let mut x = 2;
x = 5.0;
//~^ ERROR mismatched types
- //~| expected type `_`
- //~| found type `_`
+ //~| expected type `{integer}`
+ //~| found type `{float}`
//~| expected integral variable, found floating-point variable
}
fn main() {
fn f(a: [u8; u32::DOESNOTEXIST]) {}
- //~^ ERROR unresolved path in constant expression
+ //~^ ERROR constant evaluation error
+ //~| unresolved path in constant expression
}
impl Foo for Baz {
fn bar(&mut self, other: &Foo) {}
- //~^ ERROR method `bar` has an incompatible type for trait: values differ in mutability [E0053]
+ //~^ ERROR method `bar` has an incompatible type for trait
+ //~| expected type `fn(&mut Baz, &mut Foo)`
+ //~| found type `fn(&mut Baz, &Foo)`
}
fn main() {}
let _x: usize = match Some(1) {
Ok(u) => u,
//~^ ERROR mismatched types
- //~| expected type `std::option::Option<_>`
+ //~| expected type `std::option::Option<{integer}>`
//~| found type `std::result::Result<_, _>`
//~| expected enum `std::option::Option`, found enum `std::result::Result`
Err(e) => panic!(e)
//~^ ERROR mismatched types
- //~| expected type `std::option::Option<_>`
+ //~| expected type `std::option::Option<{integer}>`
//~| found type `std::result::Result<_, _>`
//~| expected enum `std::option::Option`, found enum `std::result::Result`
};
type Output = ();
fn call_once(self, _args: ()) {
//~^ ERROR `call_once` has an incompatible type for trait
- //~| expected "rust-call" fn,
- //~| found "Rust" fn
+ //~| expected type `extern "rust-call" fn
+ //~| found type `fn
println!("{:?}", self.x);
}
}
fn main() {
// FIXME (#22405): Replace `Box::new` with `box` here when/if possible.
(|| Box::new(*(&[0][..])))();
- //~^ ERROR `[_]: std::marker::Sized` is not satisfied
+ //~^ ERROR `[{integer}]: std::marker::Sized` is not satisfied
}
impl <'a> Foo<'a>{
fn bar(self: &mut Foo) {
- //~^ mismatched types
+ //~^ mismatched method receiver
//~| expected type `&mut Foo<'a>`
//~| found type `&mut Foo<'_>`
//~| lifetime mismatch
- //~| mismatched types
+ //~| mismatched method receiver
//~| expected type `&mut Foo<'a>`
//~| found type `&mut Foo<'_>`
//~| lifetime mismatch
fn main() {
if let Some(homura) = Some("madoka") { //~ ERROR missing an else clause
//~| expected type `()`
- //~| found type `_`
+ //~| found type `{integer}`
//~| expected (), found integral variable
765
};
type Item = i32;
fn next(&mut self) -> Result<i32, i32> { Ok(7) }
//~^ ERROR method `next` has an incompatible type for trait
- //~| expected enum `std::option::Option`
- //~| found enum `std::result::Result` [E0053]
+ //~| expected enum `std::option::Option`, found enum `std::result::Result`
}
fn main() {}
Pie = 0x1,
Apple = 0x2,
ApplePie = Delicious::Apple as isize | Delicious::PIE as isize,
- //~^ ERROR constant evaluation error: unresolved path in constant expression
+ //~^ ERROR constant evaluation error
+ //~| unresolved path in constant expression
}
const FOO: [u32; u8::MIN as usize] = [];
-//~^ ERROR array length constant evaluation error: unresolved path in constant expression
+//~^ ERROR constant evaluation error
+//~| unresolved path in constant expression
fn main() {}
pub enum SomeEnum {
B = SomeEnum::A,
- //~^ ERROR constant evaluation error: unresolved path in constant expression
+ //~^ ERROR constant evaluation error
+ //~| unresolved path in constant expression
}
fn main() {}
impl Deref for Thing {
//~^ ERROR not all trait items implemented, missing: `Target` [E0046]
fn deref(&self) -> i8 { self.0 }
- //~^ ERROR method `deref` has an incompatible type for trait
- //~| expected &-ptr
- //~| found i8 [E0053]
}
let thing = Thing(72);
}
static STUFF: [u8; S::N] = [0; S::N];
-//~^ ERROR array length constant evaluation error: unresolved path in constant expression
+//~^ ERROR constant evaluation error
+//~| unresolved path in constant expression
fn main() {}
macro_rules! macro_panic {
($not_a_function:expr, $some_argument:ident) => {
$not_a_function($some_argument)
- //~^ ERROR expected function, found `_`
+ //~^ ERROR expected function, found `{integer}`
}
}
//~| expected type `usize`
//~| found type `S`
//~| expected usize, found struct `S`
- //~| ERROR expected positive integer for repeat count, found struct
+ //~| ERROR expected usize for repeat count, found struct
}
match i {
0...index => println!("winner"),
- //~^ ERROR non-constant path in constant expression
+ //~^ ERROR constant evaluation error
+ //~| non-constant path in constant expression
_ => println!("hello"),
}
}
// Regression test for issue #28586
pub trait Foo {}
-impl Foo for [u8; usize::BYTES] {} //~ ERROR E0250
+impl Foo for [u8; usize::BYTES] {} //~ ERROR E0080
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.
+
+use std::vec::IntoIter;
+
+pub fn get_tok(it: &mut IntoIter<u8>) {
+ let mut found_e = false;
+
+ let temp: Vec<u8> = it.take_while(|&x| {
+ found_e = true;
+ false
+ })
+ .cloned()
+ //~^ ERROR type mismatch resolving
+ //~| expected type `u8`
+ //~| found type `&_`
+ .collect(); //~ ERROR no method named `collect`
+}
+
+fn main() {}
enum Stuff {
Bar = foo
//~^ ERROR attempt to use a non-constant value in a constant
- //~^^ ERROR constant evaluation error: non-constant path in constant expression
+ //~^^ ERROR constant evaluation error
+ //~| non-constant path in constant expression
}
println!("{}", Stuff::Bar);
} else if false {
//~^ ERROR if may be missing an else clause
//~| expected type `()`
-//~| found type `_`
+//~| found type `{integer}`
//~| expected (), found integral variable
1
};
fn main() {
match 42 { A => () }
//~^ ERROR mismatched types
- //~| expected type `_`
+ //~| expected type `{integer}`
//~| found type `(isize, isize)`
//~| expected integral variable, found tuple
}
match &Some(42) {
Some(x) => (),
//~^ ERROR mismatched types
- //~| expected type `&std::option::Option<_>`
+ //~| expected type `&std::option::Option<{integer}>`
//~| found type `std::option::Option<_>`
//~| expected &-ptr, found enum `std::option::Option`
None => ()
//~^ ERROR mismatched types
- //~| expected type `&std::option::Option<_>`
+ //~| expected type `&std::option::Option<{integer}>`
//~| found type `std::option::Option<_>`
//~| expected &-ptr, found enum `std::option::Option`
}
enum Foo {
A = 1i64,
- //~^ ERROR mismatched types:
- //~| expected `isize`,
- //~| found `i64` [E0080]
+ //~^ ERROR constant evaluation error
+ //~| expected isize, found i64
B = 2u8
- //~^ ERROR mismatched types:
- //~| expected `isize`,
- //~| found `u8` [E0080]
+ //~^ ERROR constant evaluation error
+ //~| expected isize, found u8
}
fn main() {}
fn main() {
let x: Box<_> = box 3;
take_param(&x);
- //~^ ERROR `Box<_>: std::marker::Copy` is not satisfied
+ //~^ ERROR `Box<{integer}>: std::marker::Copy` is not satisfied
}
impl<'a> Baz<'a> {
fn baz2<'b>(&self, x: &isize) -> (&'b isize, &'b isize) {
- //~^ HELP consider using an explicit lifetime parameter as shown: fn baz2<'b>(&self, x: &'a isize) -> (&'a isize, &'a isize)
+ //~^ HELP consider using an explicit lifetime parameter as shown: fn baz2<'b>(&self, x: &'
+ // FIXME #35038: The above suggestion is different on Linux and Mac.
(self.bar, x) //~ ERROR E0312
//~^ ERROR E0312
}
--- /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(rustc_attrs)]
+
+macro_rules! foo {
+ ($x:tt) => (type Alias = $x<i32>;)
+}
+
+foo!(Box);
+
+#[rustc_error]
+fn main() {} //~ ERROR compilation successful
10 ... "what" => ()
};
//~^^ ERROR only char and numeric types are allowed in range
- //~| start type: _
+ //~| start type: {integer}
//~| end type: &'static str
match 5 {
'c' ... 100 => { }
_ => { }
};
- //~^^^ ERROR mismatched types in range
- //~| expected char, found integral variable
+ //~^^^ ERROR mismatched types
+ //~| expected type `{integer}`
+ //~| found type `char`
}
};
match &[0, 1, 2] {
- [..] => {} //~ ERROR expected an array or slice, found `&[_; 3]`
+ [..] => {} //~ ERROR expected an array or slice, found `&[{integer}; 3]`
};
match &[0, 1, 2] {
//~| expected &-ptr, found struct `Foo`
Foo::bar(&42); //~ ERROR mismatched types
//~| expected type `&Foo`
- //~| found type `&_`
+ //~| found type `&{integer}`
//~| expected struct `Foo`, found integral variable
}
// (separate lines to ensure the spans are accurate)
let &_ //~ ERROR mismatched types
- //~| expected type `&mut _`
+ //~| expected type `&mut {integer}`
//~| found type `&_`
//~| values differ in mutability
= foo;
let bar = &1;
let &_ = bar;
let &mut _ //~ ERROR mismatched types
- //~| expected type `&_`
+ //~| expected type `&{integer}`
//~| found type `&mut _`
//~| values differ in mutability
= bar;
fn main() {
let x = Rc::new(5);
bar(x);
- //~^ ERROR `std::rc::Rc<_>: std::marker::Send` is not satisfied
+ //~^ ERROR `std::rc::Rc<{integer}>: std::marker::Send` is not satisfied
}
fn main() {
[State::ST_NULL; (State::ST_WHITESPACE as usize)];
- //~^ ERROR expected constant integer for repeat count, but unimplemented constant expression
+ //~^ ERROR constant evaluation error
+ //~| unimplemented constant expression: enum variants
}
fn main() {
fn bar(n: usize) {
let _x = [0; n];
- //~^ ERROR expected constant integer for repeat count, found variable
+ //~^ ERROR constant evaluation error
+ //~| non-constant path in constant expression
+ //~| NOTE `n` is a variable
}
}
let x = 0;
match 1 {
0 ... x => {}
- //~^ ERROR non-constant path in constant expression
+ //~^ ERROR constant evaluation error
+ //~| non-constant path in constant expression
};
}
}
fn test_single1() {
- use foo1::Bar; //~ ERROR function `Bar` is private
+ use foo1::Bar;
- Bar();
+ Bar(); //~ ERROR unresolved name `Bar`
}
fn test_list1() {
- use foo1::{Bar,Baz}; //~ ERROR `Bar` is private
+ use foo1::{Bar,Baz};
- Bar();
+ Bar(); //~ ERROR unresolved name `Bar`
}
// private type, public value
}
fn test_single2() {
- use foo2::Bar; //~ ERROR trait `Bar` is private
+ use foo2::Bar;
- let _x : Box<Bar>;
+ let _x : Box<Bar>; //~ ERROR type name `Bar` is undefined
}
fn test_list2() {
- use foo2::{Bar,Baz}; //~ ERROR `Bar` is private
+ use foo2::{Bar,Baz};
- let _x: Box<Bar>;
+ let _x: Box<Bar>; //~ ERROR type name `Bar` is undefined
}
// neither public
// Unsized type.
let arr: &[_] = &[1, 2, 3];
let range = *arr..;
- //~^ ERROR `[_]: std::marker::Sized` is not satisfied
+ //~^ ERROR `[{integer}]: std::marker::Sized` is not satisfied
}
fn main() {
let n = 1;
let a = [0; n];
- //~^ ERROR expected constant integer for repeat count, found variable [E0307]
+ //~^ ERROR constant evaluation error
+ //~| non-constant path in constant expression
let b = [0; ()];
//~^ ERROR mismatched types
//~| expected type `usize`
//~| found type `()`
//~| expected usize, found ()
- //~| ERROR expected positive integer for repeat count, found tuple [E0306]
+ //~| ERROR expected usize for repeat count, found tuple [E0306]
let c = [0; true];
//~^ ERROR mismatched types
//~| expected usize, found bool
- //~| ERROR expected positive integer for repeat count, found boolean [E0306]
+ //~| ERROR expected usize for repeat count, found boolean [E0306]
let d = [0; 0.5];
//~^ ERROR mismatched types
//~| expected type `usize`
- //~| found type `_`
+ //~| found type `{float}`
//~| expected usize, found floating-point variable
- //~| ERROR expected positive integer for repeat count, found float [E0306]
+ //~| ERROR expected usize for repeat count, found float [E0306]
let e = [0; "foo"];
//~^ ERROR mismatched types
//~| expected type `usize`
//~| found type `&'static str`
//~| expected usize, found &-ptr
- //~| ERROR expected positive integer for repeat count, found string literal [E0306]
+ //~| ERROR expected usize for repeat count, found string literal [E0306]
let f = [0; -4_isize];
- //~^ ERROR mismatched types
- //~| expected `usize`
- //~| found `isize`
- //~| ERROR mismatched types:
+ //~^ ERROR constant evaluation error
+ //~| expected usize, found isize
+ //~| ERROR mismatched types
//~| expected usize, found isize
let f = [0_usize; -1_isize];
- //~^ ERROR mismatched types
- //~| expected `usize`
- //~| found `isize`
+ //~^ ERROR constant evaluation error
+ //~| expected usize, found isize
//~| ERROR mismatched types
//~| expected usize, found isize
struct G {
//~| expected type `usize`
//~| found type `main::G`
//~| expected usize, found struct `main::G`
- //~| ERROR expected positive integer for repeat count, found struct [E0306]
+ //~| ERROR expected usize for repeat count, found struct [E0306]
}
match Foo(1.1, marker::PhantomData) {
1 => {}
//~^ ERROR mismatched types
- //~| expected type `Foo<_, _>`
- //~| found type `_`
+ //~| expected type `Foo<{float}, _>`
+ //~| found type `{integer}`
//~| expected struct `Foo`, found integral variable
}
pub fn main() {
let s: &str = "hello";
- let c: u8 = s[4]; //~ ERROR `str: std::ops::Index<_>` is not satisfied
+ let c: u8 = s[4]; //~ ERROR `str: std::ops::Index<{integer}>` is not satisfied
}
//~| expected struct `Foo`, found struct `Bar`
let f__isize = Foo { a: 2, ..4 }; //~ ERROR mismatched types
//~| expected type `Foo`
- //~| found type `_`
+ //~| found type `{integer}`
//~| expected struct `Foo`, found integral variable
}
//~| expected struct `Foo`, found struct `Bar`
static foo_i: Foo = Foo { a: 2, ..4 }; //~ ERROR mismatched types
//~| expected type `Foo`
- //~| found type `_`
+ //~| found type `{integer}`
//~| expected struct `Foo`, found integral variable
fn main() {
// Cannot have a larger effect than the trait:
unsafe fn jumbo(&self, x: &usize) { *self + *x; }
//~^ ERROR method `jumbo` has an incompatible type for trait
- //~| expected normal fn,
- //~| found unsafe fn
+ //~| expected type `fn
+ //~| found type `unsafe fn
}
fn main() {}
fn main() {
is_ee(4);
- //~^ ERROR overflow evaluating the requirement `_: Tweedle
+ //~^ ERROR overflow evaluating the requirement `{integer}: Tweedle
}
let y = first ((1,2.0,3));
//~^ ERROR mismatched types
//~| expected type `(isize, f64)`
- //~| found type `(isize, f64, _)`
+ //~| found type `(isize, f64, {integer})`
//~| expected a tuple with 2 elements, found one with 3 elements
let y = first ((1,));
tuple.0;
tuple.1;
tuple.2;
- //~^ ERROR attempted out-of-bounds tuple index `2` on type `(_, _)`
+ //~^ ERROR attempted out-of-bounds tuple index `2` on type `({integer}, {integer})`
}
fn main() { let a: bool = 1; let b: i32 = true; }
//~^ ERROR mismatched types
//~| expected type `bool`
-//~| found type `_`
+//~| found type `{integer}`
//~| expected bool, found integral variable
//~| ERROR mismatched types
//~| expected i32, found bool
fn main() {
let us = UnsafeCell::new(MySync{u: UnsafeCell::new(0)});
test(us);
- //~^ ERROR `std::cell::UnsafeCell<MySync<_>>: std::marker::Sync` is not satisfied
+ //~^ ERROR `std::cell::UnsafeCell<MySync<{integer}>>: std::marker::Sync` is not satisfied
let uns = UnsafeCell::new(NoSync);
test(uns);
impl<'a, T> SomeTrait for &'a Bar<T> {
fn dummy1(self: &&'a Bar<T>) { }
- fn dummy2(self: &Bar<T>) {} //~ ERROR mismatched types
- //~^ ERROR mismatched types
+ fn dummy2(self: &Bar<T>) {} //~ ERROR mismatched method receiver
+ //~^ ERROR mismatched method receiver
fn dummy3(self: &&Bar<T>) {}
- //~^ ERROR mismatched types
+ //~^ ERROR mismatched method receiver
//~| expected type `&&'a Bar<T>`
//~| found type `&&Bar<T>`
//~| lifetime mismatch
- //~| ERROR mismatched types
+ //~| ERROR mismatched method receiver
//~| expected type `&&'a Bar<T>`
//~| found type `&&Bar<T>`
//~| lifetime mismatch
--- /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.
+
+// Check that unresolved imports do not create additional errors and ICEs
+
+mod m {
+ pub use unresolved; //~ ERROR unresolved import `unresolved`
+
+ fn f() {
+ let unresolved = 0; // OK
+ }
+}
+
+fn main() {
+ match 0u8 {
+ m::unresolved => {} // OK
+ m::unresolved(..) => {} // OK
+ m::unresolved{..} => {} // OK
+ }
+}
impl Foo for u32 {
fn len(&self) -> u32 { *self }
//~^ ERROR method `len` has an incompatible type for trait
- //~| expected unsafe fn,
- //~| found normal fn
+ //~| expected type `unsafe fn(&u32) -> u32`
+ //~| found type `fn(&u32) -> u32`
}
fn main() { }
fn call_it<B:TraitB>(b: B) -> isize {
let y = 4;
- b.gimme_an_a(y) //~ ERROR `_: TraitA` is not satisfied
+ b.gimme_an_a(y) //~ ERROR `{integer}: TraitA` is not satisfied
}
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.
+
+// no-prefer-dynamic
+
+#![crate_type="rlib"]
+
+#[cfg(rpass1)]
+pub type X = u32;
+
+#[cfg(rpass2)]
+pub type X = i32;
+
+// this version doesn't actually change anything:
+#[cfg(rpass3)]
+pub type X = i32;
+
+pub type Y = char;
--- /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.
+
+// Same test as `type_alias_cross_crate`, but with
+// `no-prefer-dynamic`, ensuring that we test what happens when we
+// build rlibs (before we were only testing dylibs, which meant we
+// didn't realize we had to preserve a `bc` file as well).
+
+// aux-build:a.rs
+// revisions:rpass1 rpass2 rpass3
+// no-prefer-dynamic
+
+
+#![feature(rustc_attrs)]
+
+extern crate a;
+
+#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
+#[rustc_clean(label="TypeckItemBody", cfg="rpass3")]
+pub fn use_X() -> u32 {
+ let x: a::X = 22;
+ x as u32
+}
+
+#[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
+#[rustc_clean(label="TypeckItemBody", cfg="rpass3")]
+pub fn use_Y() {
+ let x: a::Y = 'c';
+}
+
+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.
+
+// A variant of the first "spike" test that serves to test the
+// `rustc_partition_reused` and `rustc_partition_translated` tests.
+// Here we change and say that the `x` module will be reused (when in
+// fact it will not), and then indicate that the test itself
+// should-fail (because an error will be reported, and hence the
+// revision rpass2 will not compile, despite being named rpass).
+
+// revisions:rpass1 rpass2
+// should-fail
+
+#![feature(rustc_attrs)]
+
+#![rustc_partition_reused(module="spike_neg1", cfg="rpass2")]
+#![rustc_partition_reused(module="spike_neg1-x", cfg="rpass2")] // this is wrong!
+#![rustc_partition_reused(module="spike_neg1-y", cfg="rpass2")]
+
+mod x {
+ pub struct X {
+ x: u32, y: u32,
+ }
+
+ #[cfg(rpass1)]
+ fn make() -> X {
+ X { x: 22, y: 0 }
+ }
+
+ #[cfg(rpass2)]
+ fn make() -> X {
+ X { x: 11, y: 11 }
+ }
+
+ pub fn new() -> X {
+ make()
+ }
+
+ pub fn sum(x: &X) -> u32 {
+ x.x + x.y
+ }
+}
+
+mod y {
+ use x;
+
+ pub fn assert_sum() -> bool {
+ let x = x::new();
+ x::sum(&x) == 22
+ }
+}
+
+pub fn main() {
+ y::assert_sum();
+}
--- /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.
+
+// A variant of the first "spike" test that serves to test the
+// `rustc_partition_reused` and `rustc_partition_translated` tests.
+// Here we change and say that the `y` module will be translated (when
+// in fact it will not), and then indicate that the test itself
+// should-fail (because an error will be reported, and hence the
+// revision rpass2 will not compile, despite being named rpass).
+
+// revisions:rpass1 rpass2
+// should-fail
+
+#![feature(rustc_attrs)]
+
+#![rustc_partition_reused(module="spike_neg2", cfg="rpass2")]
+#![rustc_partition_translated(module="spike_neg2-x", cfg="rpass2")]
+#![rustc_partition_translated(module="spike_neg2-y", cfg="rpass2")] // this is wrong!
+
+mod x {
+ pub struct X {
+ x: u32, y: u32,
+ }
+
+ #[cfg(rpass1)]
+ fn make() -> X {
+ X { x: 22, y: 0 }
+ }
+
+ #[cfg(rpass2)]
+ fn make() -> X {
+ X { x: 11, y: 11 }
+ }
+
+ pub fn new() -> X {
+ make()
+ }
+
+ pub fn sum(x: &X) -> u32 {
+ x.x + x.y
+ }
+}
+
+mod y {
+ use x;
+
+ pub fn assert_sum() -> bool {
+ let x = x::new();
+ x::sum(&x) == 22
+ }
+}
+
+pub fn main() {
+ y::assert_sum();
+}
--- /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.
+
+// A first "spike" for incremental compilation: here, we change the
+// content of the `make` function, and we find that we can reuse the
+// `y` module entirely (but not the `x` module).
+
+// revisions:rpass1 rpass2
+
+#![feature(rustc_attrs)]
+
+#![rustc_partition_reused(module="spike", cfg="rpass2")]
+#![rustc_partition_translated(module="spike-x", cfg="rpass2")]
+#![rustc_partition_reused(module="spike-y", cfg="rpass2")]
+
+mod x {
+ pub struct X {
+ x: u32, y: u32,
+ }
+
+ #[cfg(rpass1)]
+ fn make() -> X {
+ X { x: 22, y: 0 }
+ }
+
+ #[cfg(rpass2)]
+ fn make() -> X {
+ X { x: 11, y: 11 }
+ }
+
+ #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
+ #[rustc_clean(label="ItemSignature", cfg="rpass2")]
+ pub fn new() -> X {
+ make()
+ }
+
+ #[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
+ #[rustc_clean(label="ItemSignature", cfg="rpass2")]
+ pub fn sum(x: &X) -> u32 {
+ x.x + x.y
+ }
+}
+
+mod y {
+ use x;
+
+ #[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
+ pub fn assert_sum() -> bool {
+ let x = x::new();
+ x::sum(&x) == 22
+ }
+}
+
+pub fn main() {
+ y::assert_sum();
+}
extern crate rustc_resolve;
extern crate rustc_errors;
extern crate rustc_errors as errors;
+extern crate rustc_trans;
#[macro_use] extern crate syntax;
use std::ffi::{CStr, CString};
use rustc_driver::{driver, abort_on_err};
use rustc_resolve::MakeGlobMap;
use rustc_metadata::cstore::CStore;
+use rustc_trans::ModuleSource;
use libc::c_void;
use rustc_errors::registry::Registry;
.filter_map(|(_, p)| p).collect();
assert_eq!(trans.modules.len(), 1);
- let llmod = trans.modules[0].llmod;
+ let llmod = match trans.modules[0].source {
+ ModuleSource::Preexisting(_) => unimplemented!(),
+ ModuleSource::Translated(llvm) => llvm.llmod,
+ };
// Workaround because raw pointers do not impl Send
let modp = llmod as usize;
--- /dev/null
+-include ../tools.mk
+
+all:
+ $(RUSTC) --target x86_64_unknown-linux-musl main.rs 2>&1 | \
+ grep "error: Error loading target specification: Could not find specification for target"
--- /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() {}
extern crate rustc;
extern crate rustc_driver;
extern crate rustc_llvm;
+extern crate rustc_trans;
#[macro_use] extern crate syntax;
extern crate getopts;
use rustc_driver::{CompilerCalls, Compilation};
use rustc_driver::driver::CompileController;
+use rustc_trans::ModuleSource;
use rustc::session::Session;
use syntax::codemap::FileLoader;
use std::io;
state.session.abort_if_errors();
let trans = state.trans.unwrap();
assert_eq!(trans.modules.len(), 1);
- let rs_llmod = trans.modules[0].llmod;
+ let rs_llmod = match trans.modules[0].source {
+ ModuleSource::Preexisting(_) => unimplemented!(),
+ ModuleSource::Translated(llvm) => llvm.llmod,
+ };
unsafe { rustc_llvm::LLVMDumpModule(rs_llmod) };
});
cc
--- /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.
+
+// Check that coercions are propagated through match and if expressions.
+
+// pretty-expanded FIXME #23616
+
+use std::boxed::Box;
+
+pub fn main() {
+ let _: Box<[isize]> = if true { Box::new([1, 2, 3]) } else { Box::new([1]) };
+
+ let _: Box<[isize]> = match true { true => Box::new([1, 2, 3]), false => Box::new([1]) };
+
+ // Check we don't get over-keen at propagating coercions in the case of casts.
+ let x = if true { 42 } else { 42u8 } as u16;
+ let x = match true { true => 42, false => 42u8 } as u16;
+}
--- /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.
+
+// Check that coercions are propagated through match and if expressions.
+
+// pretty-expanded FIXME #23616
+
+#![allow(unknown_features)]
+#![feature(box_syntax)]
+
+pub fn main() {
+ let _: Box<[isize]> =
+ if true { let b: Box<_> = box [1, 2, 3]; b } else { let b: Box<_> = box [1]; b };
+
+ let _: Box<[isize]> = match true {
+ true => { let b: Box<_> = box [1, 2, 3]; b }
+ false => { let b: Box<_> = box [1]; b }
+ };
+
+ // Check we don't get over-keen at propagating coercions in the case of casts.
+ let x = if true { 42 } else { 42u8 } as u16;
+ let x = match true { true => 42, false => 42u8 } as u16;
+}
+++ /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.
-
-// Check that coercions are propagated through match and if expressions.
-
-// pretty-expanded FIXME #23616
-
-use std::boxed::Box;
-
-pub fn main() {
- let _: Box<[isize]> = if true { Box::new([1, 2, 3]) } else { Box::new([1]) };
-
- let _: Box<[isize]> = match true { true => Box::new([1, 2, 3]), false => Box::new([1]) };
-
- // Check we don't get over-keen at propagating coercions in the case of casts.
- let x = if true { 42 } else { 42u8 } as u16;
- let x = match true { true => 42, false => 42u8 } as u16;
-}
+++ /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.
-
-// Check that coercions are propagated through match and if expressions.
-
-// pretty-expanded FIXME #23616
-
-#![allow(unknown_features)]
-#![feature(box_syntax)]
-
-pub fn main() {
- let _: Box<[isize]> =
- if true { let b: Box<_> = box [1, 2, 3]; b } else { let b: Box<_> = box [1]; b };
-
- let _: Box<[isize]> = match true {
- true => { let b: Box<_> = box [1, 2, 3]; b }
- false => { let b: Box<_> = box [1]; b }
- };
-
- // Check we don't get over-keen at propagating coercions in the case of casts.
- let x = if true { 42 } else { 42u8 } as u16;
- let x = match true { true => 42, false => 42u8 } as u16;
-}
t!(format!("{}", '☃'), "☃");
t!(format!("{}", 10), "10");
t!(format!("{}", 10_usize), "10");
- t!(format!("{:?}", '☃'), "'\\u{2603}'");
+ t!(format!("{:?}", '☃'), "'☃'");
t!(format!("{:?}", 10), "10");
t!(format!("{:?}", 10_usize), "10");
t!(format!("{:?}", "true"), "\"true\"");
t!(format!("{:?}", "foo\nbar"), "\"foo\\nbar\"");
t!(format!("{:?}", "foo\n\"bar\"\r\n\'baz\'\t\\qux\\"),
r#""foo\n\"bar\"\r\n\'baz\'\t\\qux\\""#);
- t!(format!("{:?}", "foo\0bar\x01baz\u{3b1}q\u{75}x"),
- r#""foo\u{0}bar\u{1}baz\u{3b1}qux""#);
+ t!(format!("{:?}", "foo\0bar\x01baz\u{7f}q\u{75}x"),
+ r#""foo\u{0}bar\u{1}baz\u{7f}qux""#);
t!(format!("{:o}", 10_usize), "12");
t!(format!("{:x}", 10_usize), "a");
t!(format!("{:X}", 10_usize), "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.
+
+// compile-flags:--test
+// rustc-env:RUSTC_BOOTSTRAP_KEY=
+// ignore-pretty : (#23623) problems when ending with // comments
+
+#![cfg(any())] // This test should be configured away
+#![feature(rustc_attrs)] // Test that this is allowed on stable/beta
+#![feature(iter_arith_traits)] // Test that this is not unused
+#![deny(unused_features)]
+
+#[test]
+fn dummy() {
+ let () = "this should not reach type-checking";
+}
fn main() {
// for char.rs
- all_sync_send!("Я", escape_default, escape_unicode);
+ all_sync_send!("Я", escape_debug, escape_default, escape_unicode);
// for iter.rs
all_sync_send_mutable_ref!([1], iter);
--- /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.
+
+#![crate_name = "foo"]
+
+pub trait Bar {}
+
+// @has foo/struct.Foo.html '//pre' 'pub struct Foo<T>(pub T) where T: Bar;'
+pub struct Foo<T>(pub T) where T: Bar;
pub trait MyTrait { fn dummy(&self) { } }
-// @has foo/struct.Alpha.html '//pre' "pub struct Alpha<A> where A: MyTrait"
+// @has foo/struct.Alpha.html '//pre' "pub struct Alpha<A>(_) where A: MyTrait"
pub struct Alpha<A>(A) where A: MyTrait;
// @has foo/trait.Bravo.html '//pre' "pub trait Bravo<B> where B: MyTrait"
pub trait Bravo<B> where B: MyTrait { fn get(&self, B: B); }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected u64, found usize
$DIR/issue-26480.rs:38:5: 38:19 note: in this expansion of write! (defined in $DIR/issue-26480.rs)
-error: non-scalar cast: `_` as `()`
+error: non-scalar cast: `{integer}` as `()`
--> $DIR/issue-26480.rs:33:19
|
33 | ($x:expr) => ($x as ())