;;
- x86_64-*-musl)
+ x86_64-*-musl | arm-*-musleabi)
if [ ! -f $CFG_MUSL_ROOT/lib/libc.a ]
then
err "musl libc $CFG_MUSL_ROOT/lib/libc.a not found"
--- /dev/null
+# This file is intentially left empty to indicate that, while this target is
+# supported, it's not supported using plain GNU Make builds. Use a --rustbuild
+# instead.
\ No newline at end of file
--- /dev/null
+# This file is intentially left empty to indicate that, while this target is
+# supported, it's not supported using plain GNU Make builds. Use a --rustbuild
+# instead.
\ No newline at end of file
--- /dev/null
+# This file is intentially left empty to indicate that, while this target is
+# supported, it's not supported using plain GNU Make builds. Use a --rustbuild
+# instead.
\ No newline at end of file
endif
ifeq ($$(findstring msvc,$(1)),)
+
+ifeq ($$(findstring freebsd,$(1)),)
COMPRT_OBJS_$(1) += gcc_personality_v0.o
+endif
+
COMPRT_OBJS_$(1) += emutls.o
ifeq ($$(findstring x86_64,$(1)),x86_64)
"filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.31 (git+https://github.com/alexcrichton/gcc-rs)",
"getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
- "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"md5 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
[[package]]
name = "kernel32-sys"
-version = "0.2.1"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "libc"
-version = "0.2.9"
+version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
}
add_to_sysroot(&out_dir, &libdir);
- if target.contains("musl") &&
- (target.contains("x86_64") || target.contains("i686")) {
+ if target.contains("musl") && !target.contains("mips") {
copy_third_party_objects(build, target, &libdir);
}
}
// 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
}
]);
}
} else {
- sources.push("gcc_personality_v0.c");
+ if !target.contains("freebsd") {
+ sources.push("gcc_personality_v0.c");
+ }
if target.contains("x86_64") {
sources.extend(vec![
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
}
// Make sure musl-root is valid if specified
- if target.contains("musl") && (target.contains("x86_64") || target.contains("i686")) {
+ if target.contains("musl") && !target.contains("mips") {
match build.config.musl_root {
Some(ref root) => {
if fs::metadata(root.join("lib/libc.a")).is_err() {
three separate traits to overload with:
```rust
+# #![feature(unboxed_closures)]
# mod foo {
pub trait Fn<Args> : FnMut<Args> {
extern "rust-call" fn call(&self, args: Args) -> Self::Output;
# 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
cp ${PREFIX}/bin/rustc${BIN_SUF} ${TARG_DIR}/stage0/bin/
cp ${PREFIX}/${LIB_DIR}/${RUSTLIBDIR}/${TARG_DIR}/${LIB_DIR}/* ${TARG_DIR}/stage0/${LIB_DIR}/
+cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}arena*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/
cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}extra*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/
cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}rust*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/
cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}std*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/
[build-dependencies]
build_helper = { path = "../build_helper" }
-gcc = "0.3.17"
+gcc = "0.3.27"
[features]
debug = []
.replace("\\", "/"))
.current_dir(&build_dir)
.env("CC", compiler.path())
- .env("EXTRA_CFLAGS", cflags)
+ .env("EXTRA_CFLAGS", cflags.clone())
+ // jemalloc generates Makefile deps using GCC's "-MM" flag. This means
+ // that GCC will run the preprocessor, and only the preprocessor, over
+ // jemalloc's source files. If we don't specify CPPFLAGS, then at least
+ // on ARM that step fails with a "Missing implementation for 32-bit
+ // atomic operations" error. This is because no "-march" flag will be
+ // passed to GCC, and then GCC won't define the
+ // "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4" macro that jemalloc needs to
+ // select an atomic operation implementation.
+ .env("CPPFLAGS", cflags.clone())
.env("AR", &ar)
.env("RANLIB", format!("{} s", ar.display()));
//! 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:
//!
//! ```
/// ```
/// 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) {
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("ประเทศไทย中");
/// 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 {
[build-dependencies]
build_helper = { path = "../build_helper" }
-gcc = "0.3"
+gcc = "0.3.27"
-Subproject commit b0d62534d48b711c8978d1bbe8cca0558ae7b1cb
+Subproject commit 5066b7dcab7e700844b0e2ba71b8af9dc627a59b
}
}
}
- // 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))]
///////////////////////////////////////////////////////////////////////////
+ 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 middle::privacy::AccessLevels;
use ty::TyCtxt;
use session::{config, early_error, Session};
-use lint::{Level, LevelSource, Lint, LintId, LintPass};
+use lint::{Level, LevelSource, Lint, LintId, LintPass, LintSource};
use lint::{EarlyLintPassObject, LateLintPassObject};
use lint::{Default, CommandLine, Node, Allow, Warn, Deny, Forbid};
use lint::builtin;
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)
});
}
};
for (lint_id, level, span) in v {
- let now = self.lints().get_level_source(lint_id).0;
+ let (now, now_source) = self.lints().get_level_source(lint_id);
if now == Forbid && level != Forbid {
let lint_name = lint_id.as_str();
- span_err!(self.sess(), span, E0453,
- "{}({}) overruled by outer forbid({})",
- level.as_str(), lint_name,
- lint_name);
+ let mut diag_builder = struct_span_err!(self.sess(), span, E0453,
+ "{}({}) overruled by outer forbid({})",
+ level.as_str(), lint_name,
+ lint_name);
+ match now_source {
+ LintSource::Default => &mut diag_builder,
+ LintSource::Node(forbid_source_span) => {
+ diag_builder.span_note(forbid_source_span,
+ "`forbid` lint level set here")
+ },
+ LintSource::CommandLine => {
+ diag_builder.note("`forbid` lint level was set on command line")
+ }
+ }.emit()
} else if now != level {
let src = self.lints().get_level_source(lint_id).1;
self.level_stack().push((lint_id, (now, src)));
}
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
}
impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
pub fn new(delegate: &'a mut (Delegate<'tcx>+'a),
- infcx: &'a InferCtxt<'a, 'gcx, 'tcx>) -> Self
+ infcx: &'a InferCtxt<'a, 'gcx, 'tcx>)
+ -> Self
+ {
+ ExprUseVisitor::with_options(delegate, infcx, mc::MemCategorizationOptions::default())
+ }
+
+ pub fn with_options(delegate: &'a mut (Delegate<'tcx>+'a),
+ infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+ options: mc::MemCategorizationOptions)
+ -> Self
{
ExprUseVisitor {
- mc: mc::MemCategorizationContext::new(infcx),
+ mc: mc::MemCategorizationContext::with_options(infcx, options),
delegate: delegate
}
}
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
#[derive(Copy, Clone)]
pub struct MemCategorizationContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
pub infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+ options: MemCategorizationOptions,
+}
+
+#[derive(Copy, Clone, Default)]
+pub struct MemCategorizationOptions {
+ // If true, then when analyzing a closure upvar, if the closure
+ // has a missing kind, we treat it like a Fn closure. When false,
+ // we ICE if the closure has a missing kind. Should be false
+ // except during closure kind inference. It is used by the
+ // mem-categorization code to be able to have stricter assertions
+ // (which are always true except during upvar inference).
+ pub during_closure_kind_inference: bool,
}
pub type McResult<T> = Result<T, ()>;
impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>)
-> MemCategorizationContext<'a, 'gcx, 'tcx> {
- MemCategorizationContext { infcx: infcx }
+ MemCategorizationContext::with_options(infcx, MemCategorizationOptions::default())
+ }
+
+ pub fn with_options(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+ options: MemCategorizationOptions)
+ -> MemCategorizationContext<'a, 'gcx, 'tcx> {
+ MemCategorizationContext {
+ infcx: infcx,
+ options: options,
+ }
}
fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
self.cat_upvar(id, span, var_id, fn_node_id, kind)
}
None => {
- span_bug!(
- span,
- "No closure kind for {:?}",
- closure_id);
+ if !self.options.during_closure_kind_inference {
+ span_bug!(
+ span,
+ "No closure kind for {:?}",
+ closure_id);
+ }
+
+ // during closure kind inference, we
+ // don't know the closure kind yet, but
+ // it's ok because we detect that we are
+ // accessing an upvar and handle that
+ // case specially anyhow. Use Fn
+ // arbitrarily.
+ self.cat_upvar(id, span, var_id, fn_node_id, ty::ClosureKind::Fn)
}
}
}
use syntax::parse::token::InternedString;
use syntax::feature_gate::UnstableFeatures;
-use errors::{ColorConfig, Handler};
+use errors::{ColorConfig, FatalError, Handler};
use getopts;
use std::collections::HashMap;
self.debugging_opts.dump_dep_graph ||
self.debugging_opts.query_dep_graph
}
+
+ pub fn single_codegen_unit(&self) -> bool {
+ self.incremental.is_none() ||
+ self.cg.codegen_units == 1
+ }
}
// The type of entry function, so
"panic strategy to compile crate with"),
}
-
options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
build_debugging_options, "Z", "debugging",
DB_OPTIONS, db_type_desc, dbsetters,
let target = match Target::search(&opts.target_triple) {
Ok(t) => t,
Err(e) => {
- panic!(sp.fatal(&format!("Error loading target specification: {}", e)));
+ sp.struct_fatal(&format!("Error loading target specification: {}", e))
+ .help("Use `--print target-list` for a list of built-in targets")
+ .emit();
+ panic!(FatalError);
}
};
pat_util::arm_contains_ref_binding(arm)
}
+ pub fn has_error_field(self, ty: Ty<'tcx>) -> bool {
+ match ty.sty {
+ ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => {
+ for field in def.all_fields() {
+ let field_ty = field.ty(self, substs);
+ if let TyError = field_ty.sty {
+ return true;
+ }
+ }
+ }
+ _ => ()
+ }
+ false
+ }
+
/// Returns the type of element at index `i` in tuple or tuple-like type `t`.
/// For an enum `t`, `variant` is None only if `t` is a univariant enum.
pub fn positional_element_ty(self,
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
}
- }
+ })
}
--- /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 target::{Target, TargetResult};
+
+pub fn target() -> TargetResult {
+ let mut base = super::linux_musl_base::opts();
+
+ // Most of these settings are copied from the arm_unknown_linux_gnueabi
+ // target.
+ base.features = "+v6".to_string();
+ base.max_atomic_width = 64;
+ Ok(Target {
+ // It's important we use "gnueabi" and not "musleabi" here. LLVM uses it
+ // to determine the calling convention and float ABI, and it doesn't
+ // support the "musleabi" value.
+ llvm_target: "arm-unknown-linux-gnueabi".to_string(),
+ target_endian: "little".to_string(),
+ target_pointer_width: "32".to_string(),
+ data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
+ arch: "arm".to_string(),
+ target_os: "linux".to_string(),
+ target_env: "musl".to_string(),
+ target_vendor: "unknown".to_string(),
+ options: base,
+ })
+}
--- /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 target::{Target, TargetResult};
+
+pub fn target() -> TargetResult {
+ let mut base = super::linux_musl_base::opts();
+
+ // Most of these settings are copied from the arm_unknown_linux_gnueabihf
+ // target.
+ base.features = "+v6,+vfp2".to_string();
+ base.max_atomic_width = 64;
+ Ok(Target {
+ // It's important we use "gnueabihf" and not "musleabihf" here. LLVM
+ // uses it to determine the calling convention and float ABI, and it
+ // doesn't support the "musleabihf" value.
+ llvm_target: "arm-unknown-linux-gnueabihf".to_string(),
+ target_endian: "little".to_string(),
+ target_pointer_width: "32".to_string(),
+ data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
+ arch: "arm".to_string(),
+ target_os: "linux".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, 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
}
- }
+ })
}
--- /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 target::{Target, TargetResult};
+
+pub fn target() -> TargetResult {
+ let mut base = super::linux_musl_base::opts();
+
+ // Most of these settings are copied from the armv7_unknown_linux_gnueabihf
+ // target.
+ base.features = "+v7,+vfp3,+neon".to_string();
+ base.cpu = "cortex-a8".to_string();
+ base.max_atomic_width = 64;
+ Ok(Target {
+ // It's important we use "gnueabihf" and not "musleabihf" here. LLVM
+ // uses it to determine the calling convention and float ABI, and LLVM
+ // doesn't support the "musleabihf" value.
+ llvm_target: "armv7-unknown-linux-gnueabihf".to_string(),
+ target_endian: "little".to_string(),
+ target_pointer_width: "32".to_string(),
+ data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
+ arch: "arm".to_string(),
+ target_os: "linux".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, 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(),
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) -> Option<Target> {
+ fn load_specific(target: &str) -> TargetResult {
match target {
$(
$triple => {
- let mut t = $module::target();
+ 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);
- Some(t)
+ Ok(t)
},
)+
- _ => None
+ _ => 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;)*
+
+ $(
+ #[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);
+ });
+ }
+ )*
+ }
)
}
("powerpc64le-unknown-linux-gnu", powerpc64le_unknown_linux_gnu),
("arm-unknown-linux-gnueabi", arm_unknown_linux_gnueabi),
("arm-unknown-linux-gnueabihf", arm_unknown_linux_gnueabihf),
+ ("arm-unknown-linux-musleabi", arm_unknown_linux_musleabi),
+ ("arm-unknown-linux-musleabihf", arm_unknown_linux_musleabihf),
("armv7-unknown-linux-gnueabihf", armv7_unknown_linux_gnueabihf),
+ ("armv7-unknown-linux-musleabihf", armv7_unknown_linux_musleabihf),
("aarch64-unknown-linux-gnu", aarch64_unknown_linux_gnu),
("x86_64-unknown-linux-musl", x86_64_unknown_linux_musl),
("i686-unknown-linux-musl", i686_unknown_linux_musl),
/// 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,
pub is_like_android: bool,
/// Whether the linker support GNU-like arguments such as -O. Defaults to false.
pub linker_is_gnu: bool,
+ /// The MinGW toolchain has a known issue that prevents it from correctly
+ /// handling COFF object files with more than 2^15 sections. Since each weak
+ /// symbol needs its own COMDAT section, weak linkage implies a large
+ /// number sections that easily exceeds the given limit for larger
+ /// codebases. Consequently we want a way to disallow weak linkage on some
+ /// platforms.
+ pub allows_weak_linkage: bool,
/// Whether the linker support rpaths or not. Defaults to false.
pub has_rpath: bool,
/// Whether to disable linking to compiler-rt. Defaults to false, as LLVM
is_like_android: false,
is_like_msvc: false,
linker_is_gnu: false,
+ allows_weak_linkage: true,
has_rpath: false,
no_compiler_rt: false,
no_default_libraries: true,
}
/// 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!(allows_weak_linkage, 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!(allows_weak_linkage);
+ 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,
- }
+ })
}
staticlib_suffix: ".lib".to_string(),
no_default_libraries: true,
is_like_windows: true,
+ allows_weak_linkage: false,
pre_link_args: vec!(
// And here, we see obscure linker flags #45. On windows, it has been
// found to be necessary to have this flag to compile liblibc.
// 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>,
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};
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);
}
}
}
_ => 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);
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")
}
}
}
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 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())
SawItem.hash(self.st); visit::walk_item(self, i)
}
- fn visit_mod(&mut self, m: &'a Mod, _s: Span, _n: NodeId) {
+ 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)
+ SawMod.hash(self.st); visit::walk_mod(self, m, n)
}
fn visit_decl(&mut self, d: &'a Decl) {
}
fn visit_fn(&mut self, fk: FnKind<'a>, fd: &'a FnDecl,
- b: &'a Block, s: Span, _: NodeId) {
+ 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)
+ SawFn.hash(self.st); visit::walk_fn(self, fk, fd, b, s, n)
}
fn visit_trait_item(&mut self, ti: &'a TraitItem) {
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");
}
}
}
[build-dependencies]
build_helper = { path = "../build_helper" }
-gcc = "0.3"
+gcc = "0.3.27"
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()
}
use syntax::attr;
use syntax::parse::token;
use syntax::ast;
-use syntax::abi::Abi;
use syntax::codemap;
use syntax::print::pprust;
use syntax::ptr::P;
// 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![],
let applicable = match item_family(item_doc) {
ImmStatic | MutStatic => true,
Fn => {
- let ty::TypeScheme { generics, ty } = get_type(cdata, id, tcx);
+ let ty::TypeScheme { generics, .. } = get_type(cdata, id, tcx);
let no_generics = generics.types.is_empty();
- match ty.sty {
- ty::TyFnDef(_, _, fn_ty) | ty::TyFnPtr(fn_ty)
- if fn_ty.abi != Abi::Rust => return no_generics,
- _ => no_generics,
- }
+ no_generics
},
_ => false,
};
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();
}
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);
}
}
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
});
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;
}
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));
}
}
llfn
}
+fn translating_closure_body_via_mir_will_fail(ccx: &CrateContext,
+ closure_def_id: DefId)
+ -> bool {
+ let default_to_mir = ccx.sess().opts.debugging_opts.orbit;
+ let invert = if default_to_mir { "rustc_no_mir" } else { "rustc_mir" };
+ let use_mir = default_to_mir ^ ccx.tcx().has_attr(closure_def_id, invert);
+
+ !use_mir
+}
+
+pub fn trans_closure_body_via_mir<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+ closure_def_id: DefId,
+ closure_substs: ty::ClosureSubsts<'tcx>) {
+ use syntax::ast::DUMMY_NODE_ID;
+ use syntax_pos::DUMMY_SP;
+ use syntax::ptr::P;
+
+ trans_closure_expr(Dest::Ignore(ccx),
+ &hir::FnDecl {
+ inputs: P::new(),
+ output: hir::NoReturn(DUMMY_SP),
+ variadic: false
+ },
+ &hir::Block {
+ stmts: P::new(),
+ expr: None,
+ id: DUMMY_NODE_ID,
+ rules: hir::DefaultBlock,
+ span: DUMMY_SP
+ },
+ DUMMY_NODE_ID,
+ closure_def_id,
+ closure_substs);
+}
+
pub enum Dest<'a, 'tcx: 'a> {
SaveIn(Block<'a, 'tcx>, ValueRef),
Ignore(&'a CrateContext<'a, 'tcx>)
// If we have not done so yet, translate this closure's body
if !ccx.instances().borrow().contains_key(&instance) {
let llfn = get_or_create_closure_declaration(ccx, closure_def_id, closure_substs);
- llvm::SetLinkage(llfn, llvm::WeakODRLinkage);
- llvm::SetUniqueComdat(ccx.llmod(), llfn);
+
+ if ccx.sess().target.target.options.allows_weak_linkage {
+ llvm::SetLinkage(llfn, llvm::WeakODRLinkage);
+ llvm::SetUniqueComdat(ccx.llmod(), llfn);
+ } else {
+ llvm::SetLinkage(llfn, llvm::InternalLinkage);
+ }
// set an inline hint for all closures
attributes::inline(llfn, attributes::InlineAttr::Hint);
// If this is a closure, redirect to it.
let llfn = get_or_create_closure_declaration(ccx, closure_def_id, substs);
+ // If weak linkage is not allowed, we have to make sure that a local,
+ // private copy of the closure is available in this codegen unit
+ if !ccx.sess().target.target.options.allows_weak_linkage &&
+ !ccx.sess().opts.single_codegen_unit() {
+
+ if let Some(node_id) = ccx.tcx().map.as_local_node_id(closure_def_id) {
+ // If the closure is defined in the local crate, we can always just
+ // translate it.
+ let (decl, body) = match ccx.tcx().map.expect_expr(node_id).node {
+ hir::ExprClosure(_, ref decl, ref body, _) => (decl, body),
+ _ => { unreachable!() }
+ };
+
+ trans_closure_expr(Dest::Ignore(ccx),
+ decl,
+ body,
+ node_id,
+ closure_def_id,
+ substs);
+ } else {
+ // If the closure is defined in an upstream crate, we can only
+ // translate it if MIR-trans is active.
+
+ if translating_closure_body_via_mir_will_fail(ccx, closure_def_id) {
+ ccx.sess().fatal("You have run into a known limitation of the \
+ MingW toolchain. Either compile with -Zorbit or \
+ with -Ccodegen-units=1 to work around it.");
+ }
+
+ trans_closure_body_via_mir(ccx, closure_def_id, substs);
+ }
+ }
+
// If the closure is a Fn closure, but a FnOnce is needed (etc),
// then adapt the self type
let llfn_closure_kind = ccx.tcx().closure_kind(closure_def_id);
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;
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()));
// FIXME Shouldn't need to manually trigger closure instantiations.
if let mir::AggregateKind::Closure(def_id, substs) = *kind {
- use rustc::hir;
- use syntax::ast::DUMMY_NODE_ID;
- use syntax::ptr::P;
use closure;
-
- closure::trans_closure_expr(closure::Dest::Ignore(self.ccx),
- &hir::FnDecl {
- inputs: P::new(),
- output: hir::NoReturn(DUMMY_SP),
- variadic: false
- },
- &hir::Block {
- stmts: P::new(),
- expr: None,
- id: DUMMY_NODE_ID,
- rules: hir::DefaultBlock,
- span: DUMMY_SP
- },
- DUMMY_NODE_ID, def_id,
- self.monomorphize(&substs));
+ closure::trans_closure_body_via_mir(self.ccx,
+ def_id,
+ self.monomorphize(&substs));
}
let val = if let mir::AggregateKind::Adt(adt_def, index, _) = *kind {
_ => {
// FIXME Shouldn't need to manually trigger closure instantiations.
if let mir::AggregateKind::Closure(def_id, substs) = *kind {
- use rustc::hir;
- use syntax::ast::DUMMY_NODE_ID;
- use syntax::ptr::P;
- use syntax_pos::DUMMY_SP;
use closure;
- closure::trans_closure_expr(closure::Dest::Ignore(bcx.ccx()),
- &hir::FnDecl {
- inputs: P::new(),
- output: hir::NoReturn(DUMMY_SP),
- variadic: false
- },
- &hir::Block {
- stmts: P::new(),
- expr: None,
- id: DUMMY_NODE_ID,
- rules: hir::DefaultBlock,
- span: DUMMY_SP
- },
- DUMMY_NODE_ID, def_id,
- bcx.monomorphize(&substs));
+ closure::trans_closure_body_via_mir(bcx.ccx(),
+ def_id,
+ bcx.monomorphize(&substs));
}
for (i, operand) in operands.iter().enumerate() {
use middle::mem_categorization::Categorization;
use rustc::ty::{self, Ty};
use rustc::infer::UpvarRegion;
-use std::collections::HashSet;
use syntax::ast;
use syntax_pos::Span;
use rustc::hir;
use rustc::hir::intravisit::{self, Visitor};
+use rustc::util::nodemap::NodeMap;
///////////////////////////////////////////////////////////////////////////
// PUBLIC ENTRY POINTS
pub fn closure_analyze_fn(&self, body: &hir::Block) {
let mut seed = SeedBorrowKind::new(self);
seed.visit_block(body);
- let closures_with_inferred_kinds = seed.closures_with_inferred_kinds;
- let mut adjust = AdjustBorrowKind::new(self, &closures_with_inferred_kinds);
+ let mut adjust = AdjustBorrowKind::new(self, seed.temp_closure_kinds);
adjust.visit_block(body);
// it's our job to process these.
pub fn closure_analyze_const(&self, body: &hir::Expr) {
let mut seed = SeedBorrowKind::new(self);
seed.visit_expr(body);
- let closures_with_inferred_kinds = seed.closures_with_inferred_kinds;
- let mut adjust = AdjustBorrowKind::new(self, &closures_with_inferred_kinds);
+ let mut adjust = AdjustBorrowKind::new(self, seed.temp_closure_kinds);
adjust.visit_expr(body);
// it's our job to process these.
struct SeedBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
- closures_with_inferred_kinds: HashSet<ast::NodeId>,
+ temp_closure_kinds: NodeMap<ty::ClosureKind>,
}
impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for SeedBorrowKind<'a, 'gcx, 'tcx> {
impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> {
fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>) -> SeedBorrowKind<'a, 'gcx, 'tcx> {
- SeedBorrowKind { fcx: fcx, closures_with_inferred_kinds: HashSet::new() }
+ SeedBorrowKind { fcx: fcx, temp_closure_kinds: NodeMap() }
}
fn check_closure(&mut self,
{
let closure_def_id = self.fcx.tcx.map.local_def_id(expr.id);
if !self.fcx.tables.borrow().closure_kinds.contains_key(&closure_def_id) {
- self.closures_with_inferred_kinds.insert(expr.id);
- self.fcx.tables.borrow_mut().closure_kinds
- .insert(closure_def_id, ty::ClosureKind::Fn);
- debug!("check_closure: adding closure_id={:?} to closures_with_inferred_kinds",
- closure_def_id);
+ self.temp_closure_kinds.insert(expr.id, ty::ClosureKind::Fn);
+ debug!("check_closure: adding closure {:?} as Fn", expr.id);
}
self.fcx.tcx.with_freevars(expr.id, |freevars| {
struct AdjustBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
- closures_with_inferred_kinds: &'a HashSet<ast::NodeId>,
+ temp_closure_kinds: NodeMap<ty::ClosureKind>,
}
impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
- closures_with_inferred_kinds: &'a HashSet<ast::NodeId>)
+ temp_closure_kinds: NodeMap<ty::ClosureKind>)
-> AdjustBorrowKind<'a, 'gcx, 'tcx> {
- AdjustBorrowKind { fcx: fcx, closures_with_inferred_kinds: closures_with_inferred_kinds }
+ AdjustBorrowKind { fcx: fcx, temp_closure_kinds: temp_closure_kinds }
}
fn analyze_closure(&mut self,
debug!("analyze_closure(id={:?}, body.id={:?})", id, body.id);
{
- let mut euv = euv::ExprUseVisitor::new(self, self.fcx);
+ let mut euv =
+ euv::ExprUseVisitor::with_options(self,
+ self.fcx,
+ mc::MemCategorizationOptions {
+ during_closure_kind_inference: true
+ });
euv.walk_fn(decl, body);
}
self.fcx.demand_eqtype(span, final_upvar_ty, upvar_ty);
}
- // Now we must process and remove any deferred resolutions,
- // since we have a concrete closure kind.
+ // If we are also inferred the closure kind here, update the
+ // main table and process any deferred resolutions.
let closure_def_id = self.fcx.tcx.map.local_def_id(id);
- if self.closures_with_inferred_kinds.contains(&id) {
+ if let Some(&kind) = self.temp_closure_kinds.get(&id) {
+ self.fcx.tables.borrow_mut().closure_kinds
+ .insert(closure_def_id, kind);
+ debug!("closure_kind({:?}) = {:?}", closure_def_id, kind);
+
let mut deferred_call_resolutions =
self.fcx.remove_deferred_call_resolutions(closure_def_id);
for deferred_call_resolution in &mut deferred_call_resolutions {
})
}
- fn adjust_upvar_borrow_kind_for_consume(&self,
+ fn adjust_upvar_borrow_kind_for_consume(&mut self,
cmt: mc::cmt<'tcx>,
mode: euv::ConsumeMode)
{
}
}
- fn adjust_upvar_borrow_kind_for_unique(&self, cmt: mc::cmt<'tcx>) {
+ fn adjust_upvar_borrow_kind_for_unique(&mut self, cmt: mc::cmt<'tcx>) {
debug!("adjust_upvar_borrow_kind_for_unique(cmt={:?})",
cmt);
}
}
- fn try_adjust_upvar_deref(&self,
+ fn try_adjust_upvar_deref(&mut self,
note: &mc::Note,
borrow_kind: ty::BorrowKind)
-> bool
/// moving from left to right as needed (but never right to left).
/// Here the argument `mutbl` is the borrow_kind that is required by
/// some particular use.
- fn adjust_upvar_borrow_kind(&self,
+ fn adjust_upvar_borrow_kind(&mut self,
upvar_id: ty::UpvarId,
upvar_capture: &mut ty::UpvarCapture,
kind: ty::BorrowKind) {
}
}
- fn adjust_closure_kind(&self,
+ fn adjust_closure_kind(&mut self,
closure_id: ast::NodeId,
new_kind: ty::ClosureKind) {
debug!("adjust_closure_kind(closure_id={}, new_kind={:?})",
closure_id, new_kind);
- if !self.closures_with_inferred_kinds.contains(&closure_id) {
- return;
- }
-
- let closure_def_id = self.fcx.tcx.map.local_def_id(closure_id);
- let closure_kinds = &mut self.fcx.tables.borrow_mut().closure_kinds;
- let existing_kind = *closure_kinds.get(&closure_def_id).unwrap();
+ if let Some(&existing_kind) = self.temp_closure_kinds.get(&closure_id) {
+ debug!("adjust_closure_kind: closure_id={}, existing_kind={:?}, new_kind={:?}",
+ closure_id, existing_kind, new_kind);
- debug!("adjust_closure_kind: closure_id={}, existing_kind={:?}, new_kind={:?}",
- closure_id, existing_kind, new_kind);
-
- match (existing_kind, new_kind) {
- (ty::ClosureKind::Fn, ty::ClosureKind::Fn) |
- (ty::ClosureKind::FnMut, ty::ClosureKind::Fn) |
- (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) |
- (ty::ClosureKind::FnOnce, _) => {
- // no change needed
- }
+ match (existing_kind, new_kind) {
+ (ty::ClosureKind::Fn, ty::ClosureKind::Fn) |
+ (ty::ClosureKind::FnMut, ty::ClosureKind::Fn) |
+ (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) |
+ (ty::ClosureKind::FnOnce, _) => {
+ // no change needed
+ }
- (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) |
- (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) |
- (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
- // new kind is stronger than the old kind
- closure_kinds.insert(closure_def_id, new_kind);
+ (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) |
+ (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) |
+ (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
+ // new kind is stronger than the old kind
+ self.temp_closure_kinds.insert(closure_id, new_kind);
+ }
}
}
}
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);
}
}
item: &hir::Item,
ast_generics: &hir::Generics)
{
+ let ty = self.tcx().node_id_to_type(item.id);
+ if self.tcx().has_error_field(ty) {
+ return;
+ }
+
let item_def_id = self.tcx().map.local_def_id(item.id);
let ty_predicates = self.tcx().lookup_predicates(item_def_id);
let variances = self.tcx().item_variances(item_def_id);
// reachable from there, to start (if this is an inherent impl,
// then just examine the self type).
let mut input_parameters: HashSet<_> =
- ctp::parameters_for_type(impl_scheme.ty, false).into_iter().collect();
+ ctp::parameters_for(&impl_scheme.ty, false).into_iter().collect();
if let Some(ref trait_ref) = impl_trait_ref {
- input_parameters.extend(ctp::parameters_for_trait_ref(trait_ref, false));
+ input_parameters.extend(ctp::parameters_for(trait_ref, false));
}
ctp::setup_constraining_predicates(impl_predicates.predicates.get_mut_slice(TypeSpace),
let impl_trait_ref = ccx.tcx.impl_trait_ref(impl_def_id);
let mut input_parameters: HashSet<_> =
- ctp::parameters_for_type(impl_scheme.ty, false).into_iter().collect();
+ ctp::parameters_for(&impl_scheme.ty, false).into_iter().collect();
if let Some(ref trait_ref) = impl_trait_ref {
- input_parameters.extend(ctp::parameters_for_trait_ref(trait_ref, false));
+ input_parameters.extend(ctp::parameters_for(trait_ref, false));
}
ctp::identify_constrained_type_params(
&impl_predicates.predicates.as_slice(), impl_trait_ref, &mut input_parameters);
ty::TypeTraitItem(ref assoc_ty) => assoc_ty.ty,
ty::ConstTraitItem(..) | ty::MethodTraitItem(..) => None
})
- .flat_map(|ty| ctp::parameters_for_type(ty, true))
+ .flat_map(|ty| ctp::parameters_for(&ty, true))
.filter_map(|p| match p {
ctp::Parameter::Type(_) => None,
ctp::Parameter::Region(r) => Some(r),
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use rustc::ty::{self, subst, Ty};
-
+use rustc::ty::{self, Ty};
+use rustc::ty::fold::{TypeFoldable, TypeVisitor};
use std::collections::HashSet;
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
}
/// If `include_projections` is false, returns the list of parameters that are
-/// constrained by the type `ty` - i.e. the value of each parameter in the list is
-/// uniquely determined by `ty` (see RFC 447). If it is true, return the list
+/// constrained by `t` - i.e. the value of each parameter in the list is
+/// uniquely determined by `t` (see RFC 447). If it is true, return the list
/// of parameters whose values are needed in order to constrain `ty` - these
/// differ, with the latter being a superset, in the presence of projections.
-pub fn parameters_for_type<'tcx>(ty: Ty<'tcx>,
- include_projections: bool) -> Vec<Parameter> {
- let mut result = vec![];
- ty.maybe_walk(|t| match t.sty {
- ty::TyProjection(..) if !include_projections => {
+pub fn parameters_for<'tcx, T>(t: &T,
+ include_nonconstraining: bool)
+ -> Vec<Parameter>
+ where T: TypeFoldable<'tcx>
+{
- false // projections are not injective.
- }
- _ => {
- result.append(&mut parameters_for_type_shallow(t));
- // non-projection type constructors are injective.
- true
- }
- });
- result
+ let mut collector = ParameterCollector {
+ parameters: vec![],
+ include_nonconstraining: include_nonconstraining
+ };
+ t.visit_with(&mut collector);
+ collector.parameters
}
-pub fn parameters_for_trait_ref<'tcx>(trait_ref: &ty::TraitRef<'tcx>,
- include_projections: bool) -> Vec<Parameter> {
- let mut region_parameters =
- parameters_for_regions_in_substs(&trait_ref.substs);
-
- let type_parameters =
- trait_ref.substs
- .types
- .iter()
- .flat_map(|ty| parameters_for_type(ty, include_projections));
-
- region_parameters.extend(type_parameters);
-
- region_parameters
+struct ParameterCollector {
+ parameters: Vec<Parameter>,
+ include_nonconstraining: bool
}
-fn parameters_for_type_shallow<'tcx>(ty: Ty<'tcx>) -> Vec<Parameter> {
- match ty.sty {
- ty::TyParam(ref d) =>
- vec![Parameter::Type(d.clone())],
- ty::TyRef(region, _) =>
- parameters_for_region(region).into_iter().collect(),
- ty::TyStruct(_, substs) |
- ty::TyEnum(_, substs) =>
- parameters_for_regions_in_substs(substs),
- ty::TyTrait(ref data) =>
- parameters_for_regions_in_substs(&data.principal.skip_binder().substs),
- ty::TyProjection(ref pi) =>
- parameters_for_regions_in_substs(&pi.trait_ref.substs),
- ty::TyBool | ty::TyChar | ty::TyInt(..) | ty::TyUint(..) |
- ty::TyFloat(..) | ty::TyBox(..) | ty::TyStr |
- ty::TyArray(..) | ty::TySlice(..) |
- ty::TyFnDef(..) | ty::TyFnPtr(_) |
- ty::TyTuple(..) | ty::TyRawPtr(..) |
- ty::TyInfer(..) | ty::TyClosure(..) | ty::TyError =>
- vec![]
- }
-}
+impl<'tcx> TypeVisitor<'tcx> for ParameterCollector {
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
+ match t.sty {
+ ty::TyProjection(..) if !self.include_nonconstraining => {
+ // projections are not injective
+ return false;
+ }
+ ty::TyParam(ref d) => {
+ self.parameters.push(Parameter::Type(d.clone()));
+ }
+ _ => {}
+ }
-fn parameters_for_regions_in_substs(substs: &subst::Substs) -> Vec<Parameter> {
- substs.regions
- .iter()
- .filter_map(|r| parameters_for_region(r))
- .collect()
-}
+ t.super_visit_with(self)
+ }
-fn parameters_for_region(region: &ty::Region) -> Option<Parameter> {
- match *region {
- ty::ReEarlyBound(data) => Some(Parameter::Region(data)),
- _ => None,
+ fn visit_region(&mut self, r: ty::Region) -> bool {
+ match r {
+ ty::ReEarlyBound(data) => {
+ self.parameters.push(Parameter::Region(data));
+ }
+ _ => {}
+ }
+ false
}
}
// Then the projection only applies if `T` is known, but it still
// does not determine `U`.
- let inputs = parameters_for_trait_ref(&projection.projection_ty.trait_ref, true);
+ let inputs = parameters_for(&projection.projection_ty.trait_ref, true);
let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(&p));
if !relies_only_on_inputs {
continue;
}
- input_parameters.extend(parameters_for_type(projection.ty, false));
+ input_parameters.extend(parameters_for(&projection.ty, false));
} else {
continue;
}
[build-dependencies]
build_helper = { path = "../build_helper" }
-gcc = "0.3"
+gcc = "0.3.27"
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);
[build-dependencies]
build_helper = { path = "../build_helper" }
-gcc = "0.3"
+gcc = "0.3.27"
[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)
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;
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;
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,
})
}
}
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;
}
}}
}
+impl<'a> PostExpansionVisitor<'a> {
+ fn check_abi(&self, abi: Abi, span: Span) {
+ match abi {
+ Abi::RustIntrinsic =>
+ gate_feature_post!(&self, intrinsics, span,
+ "intrinsics are subject to change"),
+ Abi::PlatformIntrinsic => {
+ gate_feature_post!(&self, platform_intrinsics, span,
+ "platform intrinsics are experimental and possibly buggy")
+ },
+ Abi::Vectorcall => {
+ gate_feature_post!(&self, abi_vectorcall, span,
+ "vectorcall is experimental and subject to change")
+ }
+ Abi::RustCall => {
+ gate_feature_post!(&self, unboxed_closures, span,
+ "rust-call ABI is subject to change");
+ }
+ _ => {}
+ }
+ }
+}
+
impl<'a> Visitor for PostExpansionVisitor<'a> {
fn visit_attribute(&mut self, attr: &ast::Attribute) {
if !self.context.cm.span_allows_unstable(attr.span) {
across platforms, it is recommended to \
use `#[link(name = \"foo\")]` instead")
}
- match foreign_module.abi {
- Abi::RustIntrinsic =>
- gate_feature_post!(&self, intrinsics, i.span,
- "intrinsics are subject to change"),
- Abi::PlatformIntrinsic => {
- gate_feature_post!(&self, platform_intrinsics, i.span,
- "platform intrinsics are experimental \
- and possibly buggy")
- },
- Abi::Vectorcall => {
- gate_feature_post!(&self, abi_vectorcall, i.span,
- "vectorcall is experimental and subject to change")
- }
- _ => ()
- }
+ self.check_abi(foreign_module.abi, i.span);
}
ast::ItemKind::Fn(..) => {
visit::walk_foreign_item(self, i)
}
+ fn visit_ty(&mut self, ty: &ast::Ty) {
+ match ty.node {
+ ast::TyKind::BareFn(ref bare_fn_ty) => {
+ self.check_abi(bare_fn_ty.abi, ty.span);
+ }
+ _ => {}
+ }
+ visit::walk_ty(self, ty)
+ }
+
fn visit_expr(&mut self, e: &ast::Expr) {
match e.node {
ast::ExprKind::Box(_) => {
}
match fn_kind {
- FnKind::ItemFn(_, _, _, _, abi, _) if abi == Abi::RustIntrinsic => {
- gate_feature_post!(&self, intrinsics,
- span,
- "intrinsics are subject to change")
- }
FnKind::ItemFn(_, _, _, _, abi, _) |
- FnKind::Method(_, &ast::MethodSig { abi, .. }, _) => match abi {
- Abi::RustCall => {
- gate_feature_post!(&self, unboxed_closures, span,
- "rust-call ABI is subject to change");
- },
- Abi::Vectorcall => {
- gate_feature_post!(&self, abi_vectorcall, span,
- "vectorcall is experimental and subject to change");
- },
- _ => {}
- },
+ FnKind::Method(_, &ast::MethodSig { abi, .. }, _) => {
+ self.check_abi(abi, span);
+ }
_ => {}
}
visit::walk_fn(self, fn_kind, fn_decl, block, span);
ti.span,
"associated constants are experimental")
}
- ast::TraitItemKind::Method(ref sig, _) => {
+ ast::TraitItemKind::Method(ref sig, ref block) => {
+ if block.is_none() {
+ self.check_abi(sig.abi, ti.span);
+ }
if sig.constness == ast::Constness::Const {
gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable");
}
}
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;
//! 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)
let target = env::var("TARGET").unwrap();
if target.contains("linux") {
- if target.contains("musl") && (target.contains("x86_64") || target.contains("i686")) {
+ if target.contains("musl") && !target.contains("mips") {
println!("cargo:rustc-link-lib=static=unwind");
} else if !target.contains("android") {
println!("cargo:rustc-link-lib=gcc_s");
#![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" {}
dependencies = [
"build_helper 0.1.0",
"core 0.0.0",
- "gcc 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.0.0",
]
[[package]]
name = "gcc"
-version = "0.3.26"
+version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
"build_helper 0.1.0",
"collections 0.0.0",
"core 0.0.0",
- "gcc 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.0.0",
"panic_abort 0.0.0",
"panic_unwind 0.0.0",
[features]
jemalloc = ["std/jemalloc"]
debug-jemalloc = ["std/debug-jemalloc"]
+backtrace = ["std/backtrace"]
#![feature(plugin)]
#![plugin(lint_plugin_test)]
#![forbid(test_lint)]
+//~^ NOTE lint level defined here
+//~| NOTE `forbid` lint level set here
fn lintme() { } //~ ERROR item is named 'lintme'
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-extern "rust-call" { fn foo(x: u8, ...); } //~ ERROR E0045
+extern "Rust" { fn foo(x: u8, ...); } //~ ERROR E0045
fn main() {
}
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];
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
}
+++ /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.
-
-extern "vectorcall" { //~ ERROR vectorcall is experimental and subject to change
- fn bar();
-}
-
-extern "vectorcall" fn baz() { //~ ERROR vectorcall is experimental and subject to change
-}
-
-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.
+
+// Functions
+extern "rust-intrinsic" fn f1() {} //~ ERROR intrinsics are subject to change
+extern "platform-intrinsic" fn f2() {} //~ ERROR platform intrinsics are experimental
+extern "vectorcall" fn f3() {} //~ ERROR vectorcall is experimental and subject to change
+extern "rust-call" fn f4() {} //~ ERROR rust-call ABI is subject to change
+
+// Methods in trait definition
+trait Tr {
+ extern "rust-intrinsic" fn m1(); //~ ERROR intrinsics are subject to change
+ extern "platform-intrinsic" fn m2(); //~ ERROR platform intrinsics are experimental
+ extern "vectorcall" fn m3(); //~ ERROR vectorcall is experimental and subject to change
+ extern "rust-call" fn m4(); //~ ERROR rust-call ABI is subject to change
+
+ extern "rust-intrinsic" fn dm1() {} //~ ERROR intrinsics are subject to change
+ extern "platform-intrinsic" fn dm2() {} //~ ERROR platform intrinsics are experimental
+ extern "vectorcall" fn dm3() {} //~ ERROR vectorcall is experimental and subject to change
+ extern "rust-call" fn dm4() {} //~ ERROR rust-call ABI is subject to change
+}
+
+struct S;
+
+// Methods in trait impl
+impl Tr for S {
+ extern "rust-intrinsic" fn m1() {} //~ ERROR intrinsics are subject to change
+ extern "platform-intrinsic" fn m2() {} //~ ERROR platform intrinsics are experimental
+ extern "vectorcall" fn m3() {} //~ ERROR vectorcall is experimental and subject to change
+ extern "rust-call" fn m4() {} //~ ERROR rust-call ABI is subject to change
+}
+
+// Methods in inherent impl
+impl S {
+ extern "rust-intrinsic" fn im1() {} //~ ERROR intrinsics are subject to change
+ extern "platform-intrinsic" fn im2() {} //~ ERROR platform intrinsics are experimental
+ extern "vectorcall" fn im3() {} //~ ERROR vectorcall is experimental and subject to change
+ extern "rust-call" fn im4() {} //~ ERROR rust-call ABI is subject to change
+}
+
+// Function pointer types
+type A1 = extern "rust-intrinsic" fn(); //~ ERROR intrinsics are subject to change
+type A2 = extern "platform-intrinsic" fn(); //~ ERROR platform intrinsics are experimental
+type A3 = extern "vectorcall" fn(); //~ ERROR vectorcall is experimental and subject to change
+type A4 = extern "rust-call" fn(); //~ ERROR rust-call ABI is subject to change
+
+// Foreign modules
+extern "rust-intrinsic" {} //~ ERROR intrinsics are subject to change
+extern "platform-intrinsic" {} //~ ERROR platform intrinsics are experimental
+extern "vectorcall" {} //~ ERROR vectorcall is experimental and subject to change
+extern "rust-call" {} //~ ERROR rust-call ABI is subject to change
+
+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.
-
-extern "rust-call" fn foo() { } //~ ERROR rust-call ABI is subject to change
-
-trait Foo {
- extern "rust-call" fn foo();
-}
-
-impl Foo for i32 {
- extern "rust-call" fn foo() { } //~ ERROR rust-call ABI is subject to change
-}
-
-fn main() { }
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
}
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`
};
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
}
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
};
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}`
}
}
--- /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.
+
+// This is a regression test for a problem encountered around upvar
+// inference and trait caching: in particular, we were entering a
+// temporary closure kind during inference, and then caching results
+// based on that temporary kind, which led to no error being reported
+// in this particular test.
+
+fn main() {
+ let inc = || {};
+ inc();
+
+ fn apply<F>(f: F) where F: Fn() {
+ f()
+ }
+
+ let mut farewell = "goodbye".to_owned();
+ let diary = || { //~ ERROR E0525
+ farewell.push_str("!!!");
+ println!("Then I screamed {}.", farewell);
+ };
+
+ apply(diary);
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Bar<T> {
+ inner: Foo<T> //~ ERROR type name `Foo` is undefined or not in scope
+}
+
+enum Baz<T> {
+ Foo(Foo<T>) //~ ERROR type name `Foo` is undefined or not in scope
+}
+
+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::fmt;
+
+pub trait MethodType {
+ type GetProp: ?Sized;
+}
+
+pub struct MTFn;
+
+impl<'a> MethodType for MTFn { //~ ERROR E0207
+ type GetProp = fmt::Debug + 'a;
+}
+
+fn bad(a: Box<<MTFn as MethodType>::GetProp>) -> Box<fmt::Debug+'static> {
+ a
+}
+
+fn dangling(a: &str) -> Box<fmt::Debug> {
+ bad(Box::new(a))
+}
+
+fn main() {
+ let mut s = "hello".to_string();
+ let x = dangling(&s);
+ s = String::new();
+ println!("{:?}", x);
+}
} 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`
}
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
}
// except according to those terms.
#![forbid(deprecated)]
+//~^ NOTE `forbid` lint level set here
#[allow(deprecated)] //~ ERROR allow(deprecated) overruled by outer forbid(deprecated)
fn main() {
10 ... "what" => ()
};
//~^^ ERROR only char and numeric types are allowed in range
- //~| start type: _
+ //~| start type: {integer}
//~| end type: &'static str
match 5 {
_ => { }
};
//~^^^ ERROR mismatched types
- //~| expected type `_`
+ //~| 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 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
}
let d = [0; 0.5];
//~^ ERROR mismatched types
//~| expected type `usize`
- //~| found type `_`
+ //~| found type `{float}`
//~| expected usize, found floating-point variable
//~| ERROR expected usize for repeat count, found float [E0306]
let e = [0; "foo"];
// scope (in this case, the enum).
trait TraitA<A> {
- fn outer(self) {
+ fn outer(&self) {
enum Foo<B> {
- //~^ ERROR parameter `B` is never used
Variance(A)
//~^ ERROR can't use type parameters from outer function
}
}
trait TraitB<A> {
- fn outer(self) {
+ fn outer(&self) {
struct Foo<B>(A);
//~^ ERROR can't use type parameters from outer function
- //~^^ ERROR parameter `B` is never used
}
}
trait TraitC<A> {
- fn outer(self) {
+ fn outer(&self) {
struct Foo<B> { a: A }
//~^ ERROR can't use type parameters from outer function
- //~^^ ERROR parameter `B` is never used
}
}
trait TraitD<A> {
- fn outer(self) {
+ fn outer(&self) {
fn foo<B>(a: A) { }
//~^ ERROR can't use type parameters from outer function
}
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() {
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);
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 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 test case tests whether we can handle code bases that contain a high
+// number of closures, something that needs special handling in the MingGW
+// toolchain.
+// See https://github.com/rust-lang/rust/issues/34793 for more information.
+
+// Expand something exponentially
+macro_rules! go_bacterial {
+ ($mac:ident) => ($mac!());
+ ($mac:ident 1 $($t:tt)*) => (
+ go_bacterial!($mac $($t)*);
+ go_bacterial!($mac $($t)*);
+ )
+}
+
+macro_rules! mk_closure {
+ () => ({
+ let c = |a: u32| a + 4;
+ let _ = c(2);
+ })
+}
+
+macro_rules! mk_fn {
+ () => {
+ {
+ fn function() {
+ // Make 16 closures
+ go_bacterial!(mk_closure 1 1 1 1);
+ }
+ let _ = function();
+ }
+ }
+}
+
+fn main() {
+ // Make 2^12 functions, each containing 16 closures,
+ // resulting in 2^16 closures overall.
+ go_bacterial!(mk_fn 1 1 1 1 1 1 1 1 1 1 1 1);
+}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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 ())