"rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
-[[package]]
-name = "alloc_system"
-version = "0.0.0"
-dependencies = [
- "compiler_builtins 0.0.0",
- "core 0.0.0",
- "dlmalloc 0.0.0",
- "libc 0.0.0",
-]
-
[[package]]
name = "ammonia"
version = "1.1.0"
"crates-io 0.21.0",
"crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"crypto-hash 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "curl 0.4.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "curl 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)",
+ "curl-sys 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.12 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"filetime 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)",
"shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "tar 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tar 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)",
"tempfile 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"termcolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
name = "crates-io"
version = "0.21.0"
dependencies = [
- "curl 0.4.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "curl 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "curl"
-version = "0.4.18"
+version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "curl-sys 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "curl-sys 0.4.15 (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.43 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "curl-sys"
-version = "0.4.13"
+version = "0.4.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "curl 0.4.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "curl 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)",
"git2 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"flate2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "tar 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tar 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)",
"walkdir 2.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"xz2 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
- "curl-sys 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "curl-sys 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
"libssh2-sys 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"libz-sys 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_cratesio_shim 0.0.0",
+ "smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
version = "0.0.0"
dependencies = [
"alloc 0.0.0",
- "alloc_system 0.0.0",
"build_helper 0.1.0",
"cmake 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)",
"compiler_builtins 0.0.0",
version = "0.0.0"
dependencies = [
"alloc 0.0.0",
- "alloc_system 0.0.0",
"build_helper 0.1.0",
"cmake 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)",
"compiler_builtins 0.0.0",
version = "0.0.0"
dependencies = [
"alloc 0.0.0",
- "alloc_system 0.0.0",
"build_helper 0.1.0",
"cmake 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)",
"compiler_builtins 0.0.0",
version = "0.0.0"
dependencies = [
"alloc 0.0.0",
- "alloc_system 0.0.0",
"build_helper 0.1.0",
"cmake 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)",
"compiler_builtins 0.0.0",
version = "0.0.0"
dependencies = [
"alloc 0.0.0",
- "alloc_system 0.0.0",
"build_helper 0.1.0",
"cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
"compiler_builtins 0.0.0",
"core 0.0.0",
+ "dlmalloc 0.0.0",
"libc 0.0.0",
"panic_abort 0.0.0",
"panic_unwind 0.0.0",
[[package]]
name = "tar"
-version = "0.4.16"
+version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"filetime 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9"
"checksum crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "677d453a17e8bd2b913fa38e8b9cf04bcdbb5be790aa294f2389661d72036015"
"checksum crypto-hash 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "09de9ee0fc255ace04c7fa0763c9395a945c37c8292bb554f8d48361d1dcf1b4"
-"checksum curl 0.4.18 (registry+https://github.com/rust-lang/crates.io-index)" = "a9e5285b49b44401518c947d3b808d14d99a538a6c9ffb3ec0205c11f9fc4389"
-"checksum curl-sys 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "08459503c415173da1ce6b41036a37b8bfdd86af46d45abb9964d4c61fe670ef"
+"checksum curl 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)" = "c7c9d851c825e0c033979d4516c9173bc19a78a96eb4d6ae51d4045440eafa16"
+"checksum curl-sys 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)" = "721c204978be2143fab0a84b708c49d79d1f6100b8785610f456043a90708870"
"checksum datafrog 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "16d724bf4ffe77cdceeecd461009b5f8d9e23c5d645d68bedb4586bf43e7e142"
"checksum derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ceed73957c449214f8440eec8ad7fa282b67dc9eacbb24a3085b15d60397a17a"
"checksum derive_more 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46c7f14685a20f5dd08e7f754f2ea8cc064d8f4214ae21116c106a2768ba7b9b"
"checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741"
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
"checksum synstructure 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "85bb9b7550d063ea184027c9b8c20ac167cd36d3e06b3a40bceb9d746dc1a7b7"
-"checksum tar 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)" = "e8f41ca4a5689f06998f0247fcb60da6c760f1950cc9df2a10d71575ad0b062a"
+"checksum tar 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)" = "69e16840a1e0a1f1a880b739ef1cc6a4b85496c99b8aa786ccffce6e0c15624c"
"checksum tempfile 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c4b103c6d08d323b92ff42c8ce62abcd83ca8efa7fd5bf7927efefec75f58c76"
"checksum tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9de21546595a0873061940d994bbbc5c35f024ae4fd61ec5c5b159115684f508"
"checksum term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e6b677dd1e8214ea1ef4297f85dbcbed8e8cdddb561040cc998ca2551c37561"
# see http://serverfault.com/questions/301128/how-to-download
if sys.platform == 'win32':
run(["PowerShell.exe", "/nologo", "-Command",
- "(New-Object System.Net.WebClient)"
- ".DownloadFile('{}', '{}')".format(url, path)],
+ "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;",
+ "(New-Object System.Net.WebClient).DownloadFile('{}', '{}')".format(url, path)],
verbose=verbose,
exception=exception)
else:
// Pass down configuration from the LLVM build into the build of
// librustc_llvm and librustc_codegen_llvm.
- if builder.is_rust_llvm(target) {
+ if builder.is_rust_llvm(target) && backend != "emscripten" {
cargo.env("LLVM_RUSTLLVM", "1");
}
cargo.env("LLVM_CONFIG", &llvm_config);
"src/build_helper",
"src/dlmalloc",
"src/liballoc",
- "src/liballoc_system",
"src/libbacktrace",
"src/libcompiler_builtins",
"src/libcore",
RUN sh /scripts/sccache.sh
ENV PATH=$PATH:/emsdk-portable
-ENV PATH=$PATH:/emsdk-portable/clang/e1.37.13_64bit/
-ENV PATH=$PATH:/emsdk-portable/emscripten/1.37.13/
-ENV PATH=$PATH:/emsdk-portable/node/4.1.1_64bit/bin/
-ENV EMSCRIPTEN=/emsdk-portable/emscripten/1.37.13/
-ENV BINARYEN_ROOT=/emsdk-portable/clang/e1.37.13_64bit/binaryen/
+ENV PATH=$PATH:/emsdk-portable/clang/e1.38.15_64bit/
+ENV PATH=$PATH:/emsdk-portable/emscripten/1.38.15/
+ENV PATH=$PATH:/emsdk-portable/node/8.9.1_64bit/bin/
+ENV EMSCRIPTEN=/emsdk-portable/emscripten/1.38.15/
+ENV BINARYEN_ROOT=/emsdk-portable/clang/e1.38.15_64bit/binaryen/
ENV EM_CONFIG=/emsdk-portable/.emscripten
ENV TARGETS=asmjs-unknown-emscripten
RUN sh /scripts/sccache.sh
ENV PATH=$PATH:/emsdk-portable
-ENV PATH=$PATH:/emsdk-portable/clang/e1.37.13_64bit/
-ENV PATH=$PATH:/emsdk-portable/emscripten/1.37.13/
-ENV PATH=$PATH:/node-v8.0.0-linux-x64/bin/
-ENV EMSCRIPTEN=/emsdk-portable/emscripten/1.37.13/
-ENV BINARYEN_ROOT=/emsdk-portable/clang/e1.37.13_64bit/binaryen/
+ENV PATH=$PATH:/emsdk-portable/clang/e1.38.15_64bit/
+ENV PATH=$PATH:/emsdk-portable/emscripten/1.38.15/
+ENV PATH=$PATH:/emsdk-portable/node/8.9.1_64bit/bin/
+ENV EMSCRIPTEN=/emsdk-portable/emscripten/1.38.15/
+ENV BINARYEN_ROOT=/emsdk-portable/clang/e1.38.15_64bit/binaryen/
ENV EM_CONFIG=/emsdk-portable/.emscripten
ENV TARGETS=wasm32-unknown-emscripten
cd /emsdk-portable
./emsdk update
-hide_output ./emsdk install sdk-1.37.13-64bit
-./emsdk activate sdk-1.37.13-64bit
+hide_output ./emsdk install sdk-1.38.15-64bit
+./emsdk activate sdk-1.38.15-64bit
# Compile and cache libc
source ./emsdk_env.sh
# Make emsdk usable by any user
cp /root/.emscripten /emsdk-portable
chmod a+rxw -R /emsdk-portable
-
-# node 8 is required to run wasm
-cd /
-curl -sL https://nodejs.org/dist/v8.0.0/node-v8.0.0-linux-x64.tar.xz | \
- tar -xJ
-FROM ubuntu:16.04
+FROM ubuntu:18.04
RUN apt-get update && apt-get install -y --no-install-recommends \
g++ \
Now we'll have a `Re-exports` line, and `Bar` will not link to anywhere.
+One special case: In Rust 2018 and later, if you `pub use` one of your dependencies, `rustdoc` will
+not eagerly inline it as a module unless you add `#[doc(inline)}`.
+
## `#[doc(hidden)]`
Any item annotated with `#[doc(hidden)]` will not appear in the documentation, unless
use core::fmt;
use core::future::Future;
use core::hash::{Hash, Hasher};
-use core::iter::FusedIterator;
+use core::iter::{Iterator, FromIterator, FusedIterator};
use core::marker::{Unpin, Unsize};
use core::mem;
use core::pin::Pin;
use core::ptr::{self, NonNull, Unique};
use core::task::{LocalWaker, Poll};
+use vec::Vec;
use raw_vec::RawVec;
use str::from_boxed_utf8_unchecked;
#[unstable(feature = "dispatch_from_dyn", issue = "0")]
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U>> for Box<T> {}
+#[stable(feature = "boxed_slice_from_iter", since = "1.32.0")]
+impl<A> FromIterator<A> for Box<[A]> {
+ fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self {
+ iter.into_iter().collect::<Vec<_>>().into_boxed_slice()
+ }
+}
+
#[stable(feature = "box_slice_clone", since = "1.3.0")]
impl<T: Clone> Clone for Box<[T]> {
fn clone(&self) -> Self {
let boxed: Box<str> = Box::from(s);
assert_eq!(&*boxed, s)
}
+
+#[test]
+fn boxed_slice_from_iter() {
+ let iter = 0..100;
+ let boxed: Box<[u32]> = iter.collect();
+ assert_eq!(boxed.len(), 100);
+ assert_eq!(boxed[7], 7);
+}
/// ```
/// use std::collections::BTreeMap;
///
- /// let mut map: BTreeMap<&str, i32> = ["Alice", "Bob", "Carol", "Cheryl"].iter()
- /// .map(|&s| (s, 0))
- /// .collect();
+ /// let mut map: BTreeMap<&str, i32> = ["Alice", "Bob", "Carol", "Cheryl"]
+ /// .iter()
+ /// .map(|&s| (s, 0))
+ /// .collect();
/// for (_, balance) in map.range_mut("B".."Cheryl") {
/// *balance += 100;
/// }
// Previously, layout was calculated on the expression
// `&*(ptr as *const RcBox<T>)`, but this created a misaligned
// reference (see #54908).
- let (layout, _) = Layout::new::<RcBox<()>>()
- .extend(Layout::for_value(&*ptr)).unwrap();
+ let layout = Layout::new::<RcBox<()>>()
+ .extend(Layout::for_value(&*ptr)).unwrap().0
+ .pad_to_align().unwrap();
let mem = Global.alloc(layout)
.unwrap_or_else(|_| handle_alloc_error(layout));
// Initialize the RcBox
let inner = set_data_ptr(ptr as *mut T, mem.as_ptr() as *mut u8) as *mut RcBox<T>;
+ debug_assert_eq!(Layout::for_value(&*inner), layout);
ptr::write(&mut (*inner).strong, Cell::new(1));
ptr::write(&mut (*inner).weak, Cell::new(1));
// Previously, layout was calculated on the expression
// `&*(ptr as *const ArcInner<T>)`, but this created a misaligned
// reference (see #54908).
- let (layout, _) = Layout::new::<ArcInner<()>>()
- .extend(Layout::for_value(&*ptr)).unwrap();
+ let layout = Layout::new::<ArcInner<()>>()
+ .extend(Layout::for_value(&*ptr)).unwrap().0
+ .pad_to_align().unwrap();
let mem = Global.alloc(layout)
.unwrap_or_else(|_| handle_alloc_error(layout));
// Initialize the ArcInner
let inner = set_data_ptr(ptr as *mut T, mem.as_ptr() as *mut u8) as *mut ArcInner<T>;
+ debug_assert_eq!(Layout::for_value(&*inner), layout);
ptr::write(&mut (*inner).strong, atomic::AtomicUsize::new(1));
ptr::write(&mut (*inner).weak, atomic::AtomicUsize::new(1));
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use alloc_system::System;
-use std::alloc::{Global, Alloc, Layout};
+use std::alloc::{Global, Alloc, Layout, System};
/// https://github.com/rust-lang/rust/issues/45955
#[test]
// except according to those terms.
#![feature(allocator_api)]
-#![feature(alloc_system)]
#![feature(box_syntax)]
#![feature(drain_filter)]
#![feature(exact_size_is_empty)]
#![feature(unboxed_closures)]
#![feature(repeat_generic_slice)]
-extern crate alloc_system;
extern crate core;
extern crate rand;
+++ /dev/null
-[package]
-authors = ["The Rust Project Developers"]
-name = "alloc_system"
-version = "0.0.0"
-
-[lib]
-name = "alloc_system"
-path = "lib.rs"
-test = false
-doc = false
-
-[dependencies]
-core = { path = "../libcore" }
-libc = { path = "../rustc/libc_shim" }
-compiler_builtins = { path = "../rustc/compiler_builtins_shim" }
-
-# See comments in the source for what this dependency is
-[target.'cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))'.dependencies]
-dlmalloc = { path = "../rustc/dlmalloc_shim" }
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![no_std]
-#![allow(unused_attributes)]
-#![unstable(feature = "alloc_system",
- reason = "this library is unlikely to be stabilized in its current \
- form or name",
- issue = "32838")]
-
-#![feature(allocator_api)]
-#![feature(core_intrinsics)]
-#![feature(nll)]
-#![feature(staged_api)]
-#![feature(rustc_attrs)]
-#![cfg_attr(
- all(target_arch = "wasm32", not(target_os = "emscripten")),
- feature(integer_atomics, stdsimd)
-)]
-#![cfg_attr(any(unix, target_os = "cloudabi", target_os = "redox"), feature(libc))]
-#![rustc_alloc_kind = "lib"]
-
-// The minimum alignment guaranteed by the architecture. This value is used to
-// add fast paths for low alignment values.
-#[cfg(all(any(target_arch = "x86",
- target_arch = "arm",
- target_arch = "mips",
- target_arch = "powerpc",
- target_arch = "powerpc64",
- target_arch = "asmjs",
- target_arch = "wasm32")))]
-#[allow(dead_code)]
-const MIN_ALIGN: usize = 8;
-#[cfg(all(any(target_arch = "x86_64",
- target_arch = "aarch64",
- target_arch = "mips64",
- target_arch = "s390x",
- target_arch = "sparc64")))]
-#[allow(dead_code)]
-const MIN_ALIGN: usize = 16;
-
-use core::alloc::{Alloc, GlobalAlloc, AllocErr, Layout};
-use core::ptr::NonNull;
-
-/// The default memory allocator provided by the operating system.
-///
-/// This is based on `malloc` on Unix platforms and `HeapAlloc` on Windows,
-/// plus related functions.
-///
-/// This type can be used in a `static` item
-/// with the `#[global_allocator]` attribute
-/// to force the global allocator to be the system’s one.
-/// (The default is jemalloc for executables, on some platforms.)
-///
-/// ```rust
-/// use std::alloc::System;
-///
-/// #[global_allocator]
-/// static A: System = System;
-///
-/// fn main() {
-/// let a = Box::new(4); // Allocates from the system allocator.
-/// println!("{}", a);
-/// }
-/// ```
-///
-/// It can also be used directly to allocate memory
-/// independently of the standard library’s global allocator.
-#[stable(feature = "alloc_system_type", since = "1.28.0")]
-pub struct System;
-
-#[unstable(feature = "allocator_api", issue = "32838")]
-unsafe impl Alloc for System {
- #[inline]
- unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
- NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr)
- }
-
- #[inline]
- unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
- NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr)
- }
-
- #[inline]
- unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
- GlobalAlloc::dealloc(self, ptr.as_ptr(), layout)
- }
-
- #[inline]
- unsafe fn realloc(&mut self,
- ptr: NonNull<u8>,
- layout: Layout,
- new_size: usize) -> Result<NonNull<u8>, AllocErr> {
- NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr)
- }
-}
-
-#[cfg(any(windows, unix, target_os = "cloudabi", target_os = "redox"))]
-mod realloc_fallback {
- use core::alloc::{GlobalAlloc, Layout};
- use core::cmp;
- use core::ptr;
-
- impl super::System {
- pub(crate) unsafe fn realloc_fallback(&self, ptr: *mut u8, old_layout: Layout,
- new_size: usize) -> *mut u8 {
- // Docs for GlobalAlloc::realloc require this to be valid:
- let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align());
-
- let new_ptr = GlobalAlloc::alloc(self, new_layout);
- if !new_ptr.is_null() {
- let size = cmp::min(old_layout.size(), new_size);
- ptr::copy_nonoverlapping(ptr, new_ptr, size);
- GlobalAlloc::dealloc(self, ptr, old_layout);
- }
- new_ptr
- }
- }
-}
-
-#[cfg(any(unix, target_os = "cloudabi", target_os = "redox"))]
-mod platform {
- extern crate libc;
-
- use core::ptr;
-
- use MIN_ALIGN;
- use System;
- use core::alloc::{GlobalAlloc, Layout};
-
- #[stable(feature = "alloc_system_type", since = "1.28.0")]
- unsafe impl GlobalAlloc for System {
- #[inline]
- unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
- if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
- libc::malloc(layout.size()) as *mut u8
- } else {
- #[cfg(target_os = "macos")]
- {
- if layout.align() > (1 << 31) {
- return ptr::null_mut()
- }
- }
- aligned_malloc(&layout)
- }
- }
-
- #[inline]
- unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
- if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
- libc::calloc(layout.size(), 1) as *mut u8
- } else {
- let ptr = self.alloc(layout.clone());
- if !ptr.is_null() {
- ptr::write_bytes(ptr, 0, layout.size());
- }
- ptr
- }
- }
-
- #[inline]
- unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
- libc::free(ptr as *mut libc::c_void)
- }
-
- #[inline]
- unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
- if layout.align() <= MIN_ALIGN && layout.align() <= new_size {
- libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8
- } else {
- self.realloc_fallback(ptr, layout, new_size)
- }
- }
- }
-
- #[cfg(any(target_os = "android",
- target_os = "hermit",
- target_os = "redox",
- target_os = "solaris"))]
- #[inline]
- unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
- // On android we currently target API level 9 which unfortunately
- // doesn't have the `posix_memalign` API used below. Instead we use
- // `memalign`, but this unfortunately has the property on some systems
- // where the memory returned cannot be deallocated by `free`!
- //
- // Upon closer inspection, however, this appears to work just fine with
- // Android, so for this platform we should be fine to call `memalign`
- // (which is present in API level 9). Some helpful references could
- // possibly be chromium using memalign [1], attempts at documenting that
- // memalign + free is ok [2] [3], or the current source of chromium
- // which still uses memalign on android [4].
- //
- // [1]: https://codereview.chromium.org/10796020/
- // [2]: https://code.google.com/p/android/issues/detail?id=35391
- // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579
- // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/
- // /memory/aligned_memory.cc
- libc::memalign(layout.align(), layout.size()) as *mut u8
- }
-
- #[cfg(not(any(target_os = "android",
- target_os = "hermit",
- target_os = "redox",
- target_os = "solaris")))]
- #[inline]
- unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
- let mut out = ptr::null_mut();
- let ret = libc::posix_memalign(&mut out, layout.align(), layout.size());
- if ret != 0 {
- ptr::null_mut()
- } else {
- out as *mut u8
- }
- }
-}
-
-#[cfg(windows)]
-#[allow(nonstandard_style)]
-mod platform {
- use MIN_ALIGN;
- use System;
- use core::alloc::{GlobalAlloc, Layout};
-
- type LPVOID = *mut u8;
- type HANDLE = LPVOID;
- type SIZE_T = usize;
- type DWORD = u32;
- type BOOL = i32;
-
- extern "system" {
- fn GetProcessHeap() -> HANDLE;
- fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
- fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID;
- fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
- fn GetLastError() -> DWORD;
- }
-
- #[repr(C)]
- struct Header(*mut u8);
-
- const HEAP_ZERO_MEMORY: DWORD = 0x00000008;
-
- unsafe fn get_header<'a>(ptr: *mut u8) -> &'a mut Header {
- &mut *(ptr as *mut Header).offset(-1)
- }
-
- unsafe fn align_ptr(ptr: *mut u8, align: usize) -> *mut u8 {
- let aligned = ptr.add(align - (ptr as usize & (align - 1)));
- *get_header(aligned) = Header(ptr);
- aligned
- }
-
- #[inline]
- unsafe fn allocate_with_flags(layout: Layout, flags: DWORD) -> *mut u8 {
- let ptr = if layout.align() <= MIN_ALIGN {
- HeapAlloc(GetProcessHeap(), flags, layout.size())
- } else {
- let size = layout.size() + layout.align();
- let ptr = HeapAlloc(GetProcessHeap(), flags, size);
- if ptr.is_null() {
- ptr
- } else {
- align_ptr(ptr, layout.align())
- }
- };
- ptr as *mut u8
- }
-
- #[stable(feature = "alloc_system_type", since = "1.28.0")]
- unsafe impl GlobalAlloc for System {
- #[inline]
- unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
- allocate_with_flags(layout, 0)
- }
-
- #[inline]
- unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
- allocate_with_flags(layout, HEAP_ZERO_MEMORY)
- }
-
- #[inline]
- unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
- if layout.align() <= MIN_ALIGN {
- let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID);
- debug_assert!(err != 0, "Failed to free heap memory: {}",
- GetLastError());
- } else {
- let header = get_header(ptr);
- let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID);
- debug_assert!(err != 0, "Failed to free heap memory: {}",
- GetLastError());
- }
- }
-
- #[inline]
- unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
- if layout.align() <= MIN_ALIGN {
- HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, new_size) as *mut u8
- } else {
- self.realloc_fallback(ptr, layout, new_size)
- }
- }
- }
-}
-
-// This is an implementation of a global allocator on the wasm32 platform when
-// emscripten is not in use. In that situation there's no actual runtime for us
-// to lean on for allocation, so instead we provide our own!
-//
-// The wasm32 instruction set has two instructions for getting the current
-// amount of memory and growing the amount of memory. These instructions are the
-// foundation on which we're able to build an allocator, so we do so! Note that
-// the instructions are also pretty "global" and this is the "global" allocator
-// after all!
-//
-// The current allocator here is the `dlmalloc` crate which we've got included
-// in the rust-lang/rust repository as a submodule. The crate is a port of
-// dlmalloc.c from C to Rust and is basically just so we can have "pure Rust"
-// for now which is currently technically required (can't link with C yet).
-//
-// The crate itself provides a global allocator which on wasm has no
-// synchronization as there are no threads!
-#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
-mod platform {
- extern crate dlmalloc;
-
- use core::alloc::{GlobalAlloc, Layout};
- use System;
-
- static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::DLMALLOC_INIT;
-
- #[stable(feature = "alloc_system_type", since = "1.28.0")]
- unsafe impl GlobalAlloc for System {
- #[inline]
- unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
- let _lock = lock::lock();
- DLMALLOC.malloc(layout.size(), layout.align())
- }
-
- #[inline]
- unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
- let _lock = lock::lock();
- DLMALLOC.calloc(layout.size(), layout.align())
- }
-
- #[inline]
- unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
- let _lock = lock::lock();
- DLMALLOC.free(ptr, layout.size(), layout.align())
- }
-
- #[inline]
- unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
- let _lock = lock::lock();
- DLMALLOC.realloc(ptr, layout.size(), layout.align(), new_size)
- }
- }
-
- #[cfg(target_feature = "atomics")]
- mod lock {
- use core::arch::wasm32;
- use core::sync::atomic::{AtomicI32, Ordering::SeqCst};
-
- static LOCKED: AtomicI32 = AtomicI32::new(0);
-
- pub struct DropLock;
-
- pub fn lock() -> DropLock {
- loop {
- if LOCKED.swap(1, SeqCst) == 0 {
- return DropLock
- }
- unsafe {
- let r = wasm32::atomic::wait_i32(
- &LOCKED as *const AtomicI32 as *mut i32,
- 1, // expected value
- -1, // timeout
- );
- debug_assert!(r == 0 || r == 1);
- }
- }
- }
-
- impl Drop for DropLock {
- fn drop(&mut self) {
- let r = LOCKED.swap(0, SeqCst);
- debug_assert_eq!(r, 1);
- unsafe {
- wasm32::atomic::wake(
- &LOCKED as *const AtomicI32 as *mut i32,
- 1, // only one thread
- );
- }
- }
- }
- }
-
- #[cfg(not(target_feature = "atomics"))]
- mod lock {
- #[inline]
- pub fn lock() {} // no atomics, no threads, that's easy!
- }
-}
len_rounded_up.wrapping_sub(len)
}
+ /// Creates a layout by rounding the size of this layout up to a multiple
+ /// of the layout's alignment.
+ ///
+ /// Returns `Err` if the padded size would overflow.
+ ///
+ /// This is equivalent to adding the result of `padding_needed_for`
+ /// to the layout's current size.
+ #[unstable(feature = "alloc_layout_extra", issue = "55724")]
+ #[inline]
+ pub fn pad_to_align(&self) -> Result<Layout, LayoutErr> {
+ let pad = self.padding_needed_for(self.align());
+ let new_size = self.size().checked_add(pad)
+ .ok_or(LayoutErr { private: () })?;
+
+ Layout::from_size_align(new_size, self.align())
+ }
+
/// Creates a layout describing the record for `n` instances of
/// `self`, with a suitable amount of padding between each to
/// ensure that each instance is given its requested size and
ptr
}
- /// Shink or grow a block of memory to the given `new_size`.
+ /// Shrink or grow a block of memory to the given `new_size`.
/// The block is described by the given `ptr` pointer and `layout`.
///
/// If this returns a non-null pointer, then ownership of the memory block
// realloc. alloc_excess, realloc_excess
/// Returns a pointer suitable for holding data described by
- /// a new layout with `layout`’s alginment and a size given
+ /// a new layout with `layout`’s alignment and a size given
/// by `new_size`. To
/// accomplish this, this may extend or shrink the allocation
/// referenced by `ptr` to fit the new layout.
/// ```
#[inline]
#[stable(feature = "cell_as_ptr", since = "1.12.0")]
- pub fn as_ptr(&self) -> *mut T {
+ pub const fn as_ptr(&self) -> *mut T {
self.value.get()
}
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn get(&self) -> *mut T {
+ pub const fn get(&self) -> *mut T {
&self.value as *const T as *mut T
}
}
/// ```
#[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
#[inline]
- pub fn is_ascii(&self) -> bool {
+ pub const fn is_ascii(&self) -> bool {
*self as u32 <= 0x7F
}
/// assert_eq!(vec![1, 3], filtered);
/// ```
#[unstable(feature = "convert_id", issue = "53500")]
-#[rustc_const_unstable(feature = "const_convert_id")]
#[inline]
pub const fn identity<T>(x: T) -> T { x }
use pin::Pin;
use task::{Poll, LocalWaker};
-/// A future represents an asychronous computation.
+/// A future represents an asynchronous computation.
///
/// A future is a value that may not have finished computing yet. This kind of
/// "asynchronous value" makes it possible for a thread to continue doing useful
/// y < 0 or y >= N, where N is the width of T in bits.
pub fn unchecked_shr<T>(x: T, y: T) -> T;
+ /// Performs rotate left.
+ /// The stabilized versions of this intrinsic are available on the integer
+ /// primitives via the `rotate_left` method. For example,
+ /// [`std::u32::rotate_left`](../../std/primitive.u32.html#method.rotate_left)
+ #[cfg(not(stage0))]
+ pub fn rotate_left<T>(x: T, y: T) -> T;
+
+ /// Performs rotate right.
+ /// The stabilized versions of this intrinsic are available on the integer
+ /// primitives via the `rotate_right` method. For example,
+ /// [`std::u32::rotate_right`](../../std/primitive.u32.html#method.rotate_right)
+ #[cfg(not(stage0))]
+ pub fn rotate_right<T>(x: T, y: T) -> T;
+
/// Returns (a + b) mod 2<sup>N</sup>, where N is the width of T in bits.
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `wrapping_add` method. For example,
/// assert_eq!(None, nope.next());
/// ```
#[stable(feature = "iter_empty", since = "1.2.0")]
-pub fn empty<T>() -> Empty<T> {
+pub const fn empty<T>() -> Empty<T> {
Empty(marker::PhantomData)
}
#![feature(const_fn)]
#![feature(const_int_ops)]
#![feature(const_fn_union)]
-#![feature(const_manually_drop_new)]
#![feature(custom_attribute)]
#![feature(doc_cfg)]
#![feature(doc_spotlight)]
#![feature(const_transmute)]
#![feature(reverse_bits)]
#![feature(non_exhaustive)]
+#![feature(structural_match)]
#[prelude_import]
#[allow(unused)]
mod tuple;
mod unit;
-// Pull in the the `coresimd` crate directly into libcore. This is where all the
+// Pull in the `coresimd` crate directly into libcore. This is where all the
// architecture-specific (and vendor-specific) intrinsics are defined. AKA
// things like SIMD and such. Note that the actual source for all this lies in a
// different repository, rust-lang-nursery/stdsimd. That's why the setup here is
/// assert_eq!(v, b"s = \"abc 123\"");
/// ```
///
-/// Note: This macro can be used in `no_std` setups as well
-/// In a `no_std` setup you are responsible for the
-/// implementation details of the components.
+/// Note: This macro can be used in `no_std` setups as well.
+/// In a `no_std` setup you are responsible for the implementation details of the components.
///
/// ```no_run
/// # extern crate core;
///
/// If the determination that the code is unreachable proves incorrect, the
/// program immediately terminates with a [`panic!`]. The function [`unreachable_unchecked`],
-/// which belongs to the [`std::hint`] module, informs the compilier to
+/// which belongs to the [`std::hint`] module, informs the compiler to
/// optimize the code out of the release version entirely.
///
/// [`panic!`]: ../std/macro.panic.html
///
/// [drop check]: ../../nomicon/dropck.html
#[lang = "phantom_data"]
+#[structural_match]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct PhantomData<T:?Sized>;
///
/// ## Size of Enums
///
-/// Enums that carry no data other than the descriminant have the same size as C enums
+/// Enums that carry no data other than the discriminant have the same size as C enums
/// on the platform they are compiled for.
///
/// ## Size of Unions
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn transmute_copy<T, U>(src: &T) -> U {
- ptr::read(src as *const T as *const U)
+ ptr::read_unaligned(src as *const T as *const U)
}
/// Opaque type representing the discriminant of an enum.
/// ManuallyDrop::new(Box::new(()));
/// ```
#[stable(feature = "manually_drop", since = "1.20.0")]
- #[rustc_const_unstable(feature = "const_manually_drop_new")]
#[inline]
pub const fn new(value: T) -> ManuallyDrop<T> {
ManuallyDrop { value }
/// ```
#[stable(feature = "manually_drop", since = "1.20.0")]
#[inline]
- pub fn into_inner(slot: ManuallyDrop<T>) -> T {
+ pub const fn into_inner(slot: ManuallyDrop<T>) -> T {
slot.value
}
///
/// # Unsafety
///
- /// It is up to the caller to guarantee that the the `MaybeUninit` really is in an initialized
+ /// It is up to the caller to guarantee that the `MaybeUninit` really is in an initialized
/// state, otherwise this will immediately cause undefined behavior.
#[unstable(feature = "maybe_uninit", issue = "53491")]
pub unsafe fn into_inner(self) -> T {
///
/// # Unsafety
///
- /// It is up to the caller to guarantee that the the `MaybeUninit` really is in an initialized
+ /// It is up to the caller to guarantee that the `MaybeUninit` really is in an initialized
/// state, otherwise this will immediately cause undefined behavior.
#[unstable(feature = "maybe_uninit", issue = "53491")]
pub unsafe fn get_ref(&self) -> &T {
///
/// # Unsafety
///
- /// It is up to the caller to guarantee that the the `MaybeUninit` really is in an initialized
+ /// It is up to the caller to guarantee that the `MaybeUninit` really is in an initialized
/// state, otherwise this will immediately cause undefined behavior.
#[unstable(feature = "maybe_uninit", issue = "53491")]
pub unsafe fn get_mut(&mut self) -> &mut T {
// therefore this always underestimates (or is exact), but not much.
(((nbits + exp as i64) * 1292913986) >> 32) as i16
}
-
", $Feature, "assert_eq!(", stringify!($SelfT), "::min_value(), 0);", $EndFeature, "
```"),
#[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_promotable]
#[inline]
pub const fn min_value() -> Self { 0 }
}
stringify!($MaxV), ");", $EndFeature, "
```"),
#[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_promotable]
#[inline]
pub const fn max_value() -> Self { !0 }
}
#[rustc_const_unstable(feature = "const_int_rotate")]
#[inline]
pub const fn rotate_left(self, n: u32) -> Self {
- (self << (n % $BITS)) | (self >> (($BITS - (n % $BITS)) % $BITS))
+ #[cfg(not(stage0))] {
+ unsafe { intrinsics::rotate_left(self, n as $SelfT) }
+ }
+ #[cfg(stage0)] {
+ (self << (n % $BITS)) | (self >> (($BITS - (n % $BITS)) % $BITS))
+ }
}
}
#[rustc_const_unstable(feature = "const_int_rotate")]
#[inline]
pub const fn rotate_right(self, n: u32) -> Self {
- (self >> (n % $BITS)) | (self << (($BITS - (n % $BITS)) % $BITS))
+ #[cfg(not(stage0))] {
+ unsafe { intrinsics::rotate_right(self, n as $SelfT) }
+ }
+ #[cfg(stage0)] {
+ (self >> (n % $BITS)) | (self << (($BITS - (n % $BITS)) % $BITS))
+ }
}
}
```"),
#[inline]
#[unstable(feature = "wrapping_int_impl", issue = "32463")]
- pub fn count_ones(self) -> u32 {
+ pub const fn count_ones(self) -> u32 {
self.0.count_ones()
}
}
```"),
#[inline]
#[unstable(feature = "wrapping_int_impl", issue = "32463")]
- pub fn count_zeros(self) -> u32 {
+ pub const fn count_zeros(self) -> u32 {
self.0.count_zeros()
}
}
```"),
#[inline]
#[unstable(feature = "wrapping_int_impl", issue = "32463")]
- pub fn trailing_zeros(self) -> u32 {
+ pub const fn trailing_zeros(self) -> u32 {
self.0.trailing_zeros()
}
}
/// ```
#[inline]
#[unstable(feature = "wrapping_int_impl", issue = "32463")]
- pub fn rotate_left(self, n: u32) -> Self {
+ pub const fn rotate_left(self, n: u32) -> Self {
Wrapping(self.0.rotate_left(n))
}
/// ```
#[inline]
#[unstable(feature = "wrapping_int_impl", issue = "32463")]
- pub fn rotate_right(self, n: u32) -> Self {
+ pub const fn rotate_right(self, n: u32) -> Self {
Wrapping(self.0.rotate_right(n))
}
/// ```
#[inline]
#[unstable(feature = "wrapping_int_impl", issue = "32463")]
- pub fn swap_bytes(self) -> Self {
+ pub const fn swap_bytes(self) -> Self {
Wrapping(self.0.swap_bytes())
}
/// ```
#[unstable(feature = "reverse_bits", issue = "48763")]
#[inline]
- pub fn reverse_bits(self) -> Self {
+ pub const fn reverse_bits(self) -> Self {
Wrapping(self.0.reverse_bits())
}
```"),
#[inline]
#[unstable(feature = "wrapping_int_impl", issue = "32463")]
- pub fn from_be(x: Self) -> Self {
+ pub const fn from_be(x: Self) -> Self {
Wrapping(<$t>::from_be(x.0))
}
}
```"),
#[inline]
#[unstable(feature = "wrapping_int_impl", issue = "32463")]
- pub fn from_le(x: Self) -> Self {
+ pub const fn from_le(x: Self) -> Self {
Wrapping(<$t>::from_le(x.0))
}
}
```"),
#[inline]
#[unstable(feature = "wrapping_int_impl", issue = "32463")]
- pub fn to_be(self) -> Self {
+ pub const fn to_be(self) -> Self {
Wrapping(self.0.to_be())
}
}
```"),
#[inline]
#[unstable(feature = "wrapping_int_impl", issue = "32463")]
- pub fn to_le(self) -> Self {
+ pub const fn to_le(self) -> Self {
Wrapping(self.0.to_le())
}
}
```"),
#[inline]
#[unstable(feature = "wrapping_int_impl", issue = "32463")]
- pub fn leading_zeros(self) -> u32 {
+ pub const fn leading_zeros(self) -> u32 {
self.0.leading_zeros()
}
}
```"),
#[inline]
#[unstable(feature = "wrapping_int_impl", issue = "32463")]
- pub fn is_positive(self) -> bool {
+ pub const fn is_positive(self) -> bool {
self.0.is_positive()
}
}
```"),
#[inline]
#[unstable(feature = "wrapping_int_impl", issue = "32463")]
- pub fn is_negative(self) -> bool {
+ pub const fn is_negative(self) -> bool {
self.0.is_negative()
}
}
```"),
#[inline]
#[unstable(feature = "wrapping_int_impl", issue = "32463")]
- pub fn leading_zeros(self) -> u32 {
+ pub const fn leading_zeros(self) -> u32 {
self.0.leading_zeros()
}
}
/// ```
#[stable(feature = "inclusive_range_methods", since = "1.27.0")]
#[inline]
- pub fn start(&self) -> &Idx {
+ pub const fn start(&self) -> &Idx {
&self.start
}
/// ```
#[stable(feature = "inclusive_range_methods", since = "1.27.0")]
#[inline]
- pub fn end(&self) -> &Idx {
+ pub const fn end(&self) -> &Idx {
&self.end
}
//! It is sometimes useful to have objects that are guaranteed to not move,
//! in the sense that their placement in memory does not change, and can thus be relied upon.
//!
-//! A prime example of such a scenario would be building self-referencial structs,
+//! A prime example of such a scenario would be building self-referential structs,
//! since moving an object with pointers to itself will invalidate them,
//! which could cause undefined behavior.
//!
//! use std::marker::Pinned;
//! use std::ptr::NonNull;
//!
-//! // This is a self referencial struct since the slice field points to the data field.
+//! // This is a self-referential struct since the slice field points to the data field.
//! // We cannot inform the compiler about that with a normal reference,
//! // since this pattern cannot be described with the usual borrowing rules.
//! // Instead we use a raw pointer, though one which is known to not be null,
///
/// Additionally, if `T` is not [`Copy`], using the pointed-to value after
/// calling `drop_in_place` can cause undefined behavior. Note that `*to_drop =
-/// foo` counts as a use because it will cause the the value to be dropped
+/// foo` counts as a use because it will cause the value to be dropped
/// again. [`write`] can be used to overwrite data without causing it to be
/// dropped.
///
#[inline]
unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) {
// The approach here is to utilize simd to swap x & y efficiently. Testing reveals
- // that swapping either 32 bytes or 64 bytes at a time is most efficient for intel
+ // that swapping either 32 bytes or 64 bytes at a time is most efficient for Intel
// Haswell E processors. LLVM is more able to optimize if we give a struct a
// #[repr(simd)], even if we don't actually use this struct directly.
//
/// # Null-unchecked version
///
/// If you are sure the pointer can never be null and are looking for some kind of
- /// `as_ref_unchecked` that returns the `&T` instead of `Option<&T>, know that you can
+ /// `as_ref_unchecked` that returns the `&T` instead of `Option<&T>`, know that you can
/// dereference the pointer directly.
///
/// ```
/// # Null-unchecked version
///
/// If you are sure the pointer can never be null and are looking for some kind of
- /// `as_ref_unchecked` that returns the `&T` instead of `Option<&T>, know that you can
+ /// `as_ref_unchecked` that returns the `&T` instead of `Option<&T>`, know that you can
/// dereference the pointer directly.
///
/// ```
/// Acquires the underlying `*mut` pointer.
#[stable(feature = "nonnull", since = "1.25.0")]
#[inline]
- pub fn as_ptr(self) -> *mut T {
+ pub const fn as_ptr(self) -> *mut T {
self.pointer.0 as *mut T
}
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- #[rustc_const_unstable(feature = "const_slice_as_ptr")]
pub const fn as_ptr(&self) -> *const T {
self as *const [T] as *const T
}
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- #[rustc_const_unstable(feature = "const_str_as_ptr")]
pub const fn as_ptr(&self) -> *const u8 {
self as *const str as *const u8
}
///
/// [`subsec_nanos`]: #method.subsec_nanos
#[stable(feature = "duration", since = "1.3.0")]
- #[rustc_const_unstable(feature="duration_getters")]
#[inline]
pub const fn as_secs(&self) -> u64 { self.secs }
/// assert_eq!(duration.subsec_millis(), 432);
/// ```
#[stable(feature = "duration_extras", since = "1.27.0")]
- #[rustc_const_unstable(feature="duration_getters")]
#[inline]
pub const fn subsec_millis(&self) -> u32 { self.nanos / NANOS_PER_MILLI }
/// assert_eq!(duration.subsec_micros(), 234_567);
/// ```
#[stable(feature = "duration_extras", since = "1.27.0")]
- #[rustc_const_unstable(feature="duration_getters")]
#[inline]
pub const fn subsec_micros(&self) -> u32 { self.nanos / NANOS_PER_MICRO }
/// assert_eq!(duration.subsec_nanos(), 10_000_000);
/// ```
#[stable(feature = "duration", since = "1.3.0")]
- #[rustc_const_unstable(feature="duration_getters")]
#[inline]
pub const fn subsec_nanos(&self) -> u32 { self.nanos }
/// ```
#[unstable(feature = "duration_as_u128", issue = "50202")]
#[inline]
- pub fn as_millis(&self) -> u128 {
+ pub const fn as_millis(&self) -> u128 {
self.secs as u128 * MILLIS_PER_SEC as u128 + (self.nanos / NANOS_PER_MILLI) as u128
}
/// ```
#[unstable(feature = "duration_as_u128", issue = "50202")]
#[inline]
- pub fn as_micros(&self) -> u128 {
+ pub const fn as_micros(&self) -> u128 {
self.secs as u128 * MICROS_PER_SEC as u128 + (self.nanos / NANOS_PER_MICRO) as u128
}
/// ```
#[unstable(feature = "duration_as_u128", issue = "50202")]
#[inline]
- pub fn as_nanos(&self) -> u128 {
+ pub const fn as_nanos(&self) -> u128 {
self.secs as u128 * NANOS_PER_SEC as u128 + self.nanos as u128
}
/// ```
#[unstable(feature = "duration_float", issue = "54361")]
#[inline]
- pub fn as_float_secs(&self) -> f64 {
+ pub const fn as_float_secs(&self) -> f64 {
(self.secs as f64) + (self.nanos as f64) / (NANOS_PER_SEC as f64)
}
pub mod personalities {
#[no_mangle]
#[cfg(not(any(
- target_arch = "wasm32",
+ all(
+ target_arch = "wasm32",
+ not(target_os = "emscripten"),
+ ),
all(
target_os = "windows",
target_env = "gnu",
register_diagnostics! {
-// E0006 // merged with E0005
+// E0006, // merged with E0005
// E0101, // replaced with E0282
// E0102, // replaced with E0282
// E0134,
E0657, // `impl Trait` can only capture lifetimes bound at the fn level
E0687, // in-band lifetimes cannot be used in `fn`/`Fn` syntax
E0688, // in-band lifetimes cannot be mixed with explicit lifetime binders
-
E0697, // closures cannot be static
-
E0707, // multiple elided lifetimes used in arguments of `async fn`
E0708, // `async` non-`move` closures with arguments are not currently supported
E0709, // multiple different lifetimes used in arguments of `async fn`
let ohs = P(self.lower_expr(ohs));
hir::ExprKind::Unary(op, ohs)
}
- ExprKind::Lit(ref l) => hir::ExprKind::Lit(P((**l).clone())),
+ ExprKind::Lit(ref l) => hir::ExprKind::Lit(P((*l).clone())),
ExprKind::Cast(ref expr, ref ty) => {
let expr = P(self.lower_expr(expr));
hir::ExprKind::Cast(expr, self.lower_ty(ty, ImplTraitContext::disallowed()))
}
/// The AST represents all type param bounds as types.
-/// typeck::collect::compute_bounds matches these against
-/// the "special" built-in traits (see middle::lang_items) and
-/// detects Copy, Send and Sync.
+/// `typeck::collect::compute_bounds` matches these against
+/// the "special" built-in traits (see `middle::lang_items`) and
+/// detects `Copy`, `Send` and `Sync`.
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub enum GenericBound {
Trait(PolyTraitRef, TraitBoundModifier),
self.msg_span_from_early_bound_and_free_regions(region)
}
ty::ReStatic => ("the static lifetime".to_owned(), None),
+ ty::ReEmpty => ("an empty lifetime".to_owned(), None),
_ => bug!("{:?}", region),
}
}
let mut types = vec![concrete_ty];
let bound_region = |r| self.sub_regions(infer::CallReturn(span), least_region, r);
while let Some(ty) = types.pop() {
- let mut components = self.tcx.outlives_components(ty);
+ let mut components = smallvec![];
+ self.tcx.push_outlives_components(ty, &mut components);
while let Some(component) = components.pop() {
match component {
Component::Region(r) => {
// except according to those terms.
//! Code that handles "type-outlives" constraints like `T: 'a`. This
-//! is based on the `outlives_components` function defined on the tcx,
+//! is based on the `push_outlives_components` function defined on the tcx,
//! but it adds a bit of heuristics on top, in particular to deal with
//! associated types and projections.
//!
assert!(!ty.has_escaping_bound_vars());
- let components = self.tcx.outlives_components(ty);
- self.components_must_outlive(origin, components, region);
+ let mut components = smallvec![];
+ self.tcx.push_outlives_components(ty, &mut components);
+ self.components_must_outlive(origin, &components, region);
}
fn components_must_outlive(
&mut self,
origin: infer::SubregionOrigin<'tcx>,
- components: Vec<Component<'tcx>>,
+ components: &[Component<'tcx>],
region: ty::Region<'tcx>,
) {
- for component in components {
+ for component in components.iter() {
let origin = origin.clone();
match component {
Component::Region(region1) => {
.push_sub_region_constraint(origin, region, region1);
}
Component::Param(param_ty) => {
- self.param_ty_must_outlive(origin, region, param_ty);
+ self.param_ty_must_outlive(origin, region, *param_ty);
}
Component::Projection(projection_ty) => {
- self.projection_must_outlive(origin, region, projection_ty);
+ self.projection_must_outlive(origin, region, *projection_ty);
}
Component::EscapingProjection(subcomponents) => {
- self.components_must_outlive(origin, subcomponents, region);
+ self.components_must_outlive(origin, &subcomponents, region);
}
Component::UnresolvedInferenceVariable(v) => {
// ignore this, we presume it will yield an error
.map(|subty| self.type_bound(subty))
.collect::<Vec<_>>();
- let mut regions = ty.regions();
+ let mut regions = smallvec![];
+ ty.push_regions(&mut regions);
regions.retain(|r| !r.is_late_bound()); // ignore late-bound regions
bounds.push(VerifyBound::AllBounds(
regions
"detects labels that are never used"
}
-declare_lint! {
- pub DUPLICATE_ASSOCIATED_TYPE_BINDINGS,
- Warn,
- "warns about duplicate associated type bindings in generics"
-}
-
declare_lint! {
pub DUPLICATE_MACRO_EXPORTS,
Deny,
ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
UNSTABLE_NAME_COLLISIONS,
IRREFUTABLE_LET_PATTERNS,
- DUPLICATE_ASSOCIATED_TYPE_BINDINGS,
DUPLICATE_MACRO_EXPORTS,
INTRA_DOC_LINK_RESOLUTION_FAILURE,
MISSING_DOC_CODE_EXAMPLES,
})
}
-#[macro_export]
-macro_rules! static_assert {
- ($name:ident: $test:expr) => {
- // Use the bool to access an array such that if the bool is false, the access
- // is out-of-bounds.
- #[allow(dead_code)]
- static $name: () = [()][!$test as usize];
- }
-}
-
#[macro_export]
macro_rules! __impl_stable_hash_field {
($field:ident, $ctx:expr, $hasher:expr) => ($field.hash_stable($ctx, $hasher));
use hir::def_id::CrateNum;
-use session;
use session::config;
use ty::TyCtxt;
use middle::cstore::{self, DepKind};
// quite yet, so do so here.
activate_injected_dep(*sess.injected_panic_runtime.get(), &mut ret,
&|cnum| tcx.is_panic_runtime(cnum));
- activate_injected_allocator(sess, &mut ret);
// When dylib B links to dylib A, then when using B we must also link to A.
// It could be the case, however, that the rlib for A is present (hence we
// that here and activate them.
activate_injected_dep(*sess.injected_panic_runtime.get(), &mut ret,
&|cnum| tcx.is_panic_runtime(cnum));
- activate_injected_allocator(sess, &mut ret);
Some(ret)
}
}
}
-fn activate_injected_allocator(sess: &session::Session,
- list: &mut DependencyList) {
- let cnum = match sess.injected_allocator.get() {
- Some(cnum) => cnum,
- None => return,
- };
- let idx = cnum.as_usize() - 1;
- if list[idx] == Linkage::NotLinked {
- list[idx] = Linkage::Static;
- }
-}
-
// After the linkage for a crate has been determined we need to verify that
// there's only going to be one allocator in the output.
fn verify_ok<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, list: &[Linkage]) {
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+//! The virtual memory representation of the MIR interpreter
+
+use super::{Pointer, EvalResult, AllocId};
+
+use ty::layout::{Size, Align};
+use syntax::ast::Mutability;
+use std::iter;
+use mir;
+use std::ops::{Deref, DerefMut};
+use rustc_data_structures::sorted_map::SortedMap;
+
+#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
+pub struct Allocation<Tag=(),Extra=()> {
+ /// The actual bytes of the allocation.
+ /// Note that the bytes of a pointer represent the offset of the pointer
+ pub bytes: Vec<u8>,
+ /// Maps from byte addresses to extra data for each pointer.
+ /// Only the first byte of a pointer is inserted into the map; i.e.,
+ /// every entry in this map applies to `pointer_size` consecutive bytes starting
+ /// at the given offset.
+ pub relocations: Relocations<Tag>,
+ /// Denotes undefined memory. Reading from undefined memory is forbidden in miri
+ pub undef_mask: UndefMask,
+ /// The alignment of the allocation to detect unaligned reads.
+ pub align: Align,
+ /// Whether the allocation is mutable.
+ /// Also used by codegen to determine if a static should be put into mutable memory,
+ /// which happens for `static mut` and `static` with interior mutability.
+ pub mutability: Mutability,
+ /// Extra state for the machine.
+ pub extra: Extra,
+}
+
+pub trait AllocationExtra<Tag>: ::std::fmt::Debug + Default + Clone {
+ /// Hook for performing extra checks on a memory read access.
+ ///
+ /// Takes read-only access to the allocation so we can keep all the memory read
+ /// operations take `&self`. Use a `RefCell` in `AllocExtra` if you
+ /// need to mutate.
+ #[inline]
+ fn memory_read(
+ _alloc: &Allocation<Tag, Self>,
+ _ptr: Pointer<Tag>,
+ _size: Size,
+ ) -> EvalResult<'tcx> {
+ Ok(())
+ }
+
+ /// Hook for performing extra checks on a memory write access.
+ #[inline]
+ fn memory_written(
+ _alloc: &mut Allocation<Tag, Self>,
+ _ptr: Pointer<Tag>,
+ _size: Size,
+ ) -> EvalResult<'tcx> {
+ Ok(())
+ }
+}
+
+impl AllocationExtra<()> for () {}
+
+impl<Tag, Extra: Default> Allocation<Tag, Extra> {
+ /// Creates a read-only allocation initialized by the given bytes
+ pub fn from_bytes(slice: &[u8], align: Align) -> Self {
+ let mut undef_mask = UndefMask::new(Size::ZERO);
+ undef_mask.grow(Size::from_bytes(slice.len() as u64), true);
+ Self {
+ bytes: slice.to_owned(),
+ relocations: Relocations::new(),
+ undef_mask,
+ align,
+ mutability: Mutability::Immutable,
+ extra: Extra::default(),
+ }
+ }
+
+ pub fn from_byte_aligned_bytes(slice: &[u8]) -> Self {
+ Allocation::from_bytes(slice, Align::from_bytes(1, 1).unwrap())
+ }
+
+ pub fn undef(size: Size, align: Align) -> Self {
+ assert_eq!(size.bytes() as usize as u64, size.bytes());
+ Allocation {
+ bytes: vec![0; size.bytes() as usize],
+ relocations: Relocations::new(),
+ undef_mask: UndefMask::new(size),
+ align,
+ mutability: Mutability::Mutable,
+ extra: Extra::default(),
+ }
+ }
+}
+
+impl<'tcx> ::serialize::UseSpecializedDecodable for &'tcx Allocation {}
+
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
+pub struct Relocations<Tag=(), Id=AllocId>(SortedMap<Size, (Tag, Id)>);
+
+impl<Tag, Id> Relocations<Tag, Id> {
+ pub fn new() -> Self {
+ Relocations(SortedMap::new())
+ }
+
+ // The caller must guarantee that the given relocations are already sorted
+ // by address and contain no duplicates.
+ pub fn from_presorted(r: Vec<(Size, (Tag, Id))>) -> Self {
+ Relocations(SortedMap::from_presorted_elements(r))
+ }
+}
+
+impl<Tag> Deref for Relocations<Tag> {
+ type Target = SortedMap<Size, (Tag, AllocId)>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+impl<Tag> DerefMut for Relocations<Tag> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.0
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Undefined byte tracking
+////////////////////////////////////////////////////////////////////////////////
+
+type Block = u64;
+const BLOCK_SIZE: u64 = 64;
+
+#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
+pub struct UndefMask {
+ blocks: Vec<Block>,
+ len: Size,
+}
+
+impl_stable_hash_for!(struct mir::interpret::UndefMask{blocks, len});
+
+impl UndefMask {
+ pub fn new(size: Size) -> Self {
+ let mut m = UndefMask {
+ blocks: vec![],
+ len: Size::ZERO,
+ };
+ m.grow(size, false);
+ m
+ }
+
+ /// Check whether the range `start..end` (end-exclusive) is entirely defined.
+ ///
+ /// Returns `Ok(())` if it's defined. Otherwise returns the index of the byte
+ /// at which the first undefined access begins.
+ #[inline]
+ pub fn is_range_defined(&self, start: Size, end: Size) -> Result<(), Size> {
+ if end > self.len {
+ return Err(self.len);
+ }
+
+ let idx = (start.bytes()..end.bytes())
+ .map(|i| Size::from_bytes(i))
+ .find(|&i| !self.get(i));
+
+ match idx {
+ Some(idx) => Err(idx),
+ None => Ok(())
+ }
+ }
+
+ pub fn set_range(&mut self, start: Size, end: Size, new_state: bool) {
+ let len = self.len;
+ if end > len {
+ self.grow(end - len, new_state);
+ }
+ self.set_range_inbounds(start, end, new_state);
+ }
+
+ pub fn set_range_inbounds(&mut self, start: Size, end: Size, new_state: bool) {
+ for i in start.bytes()..end.bytes() {
+ self.set(Size::from_bytes(i), new_state);
+ }
+ }
+
+ #[inline]
+ pub fn get(&self, i: Size) -> bool {
+ let (block, bit) = bit_index(i);
+ (self.blocks[block] & 1 << bit) != 0
+ }
+
+ #[inline]
+ pub fn set(&mut self, i: Size, new_state: bool) {
+ let (block, bit) = bit_index(i);
+ if new_state {
+ self.blocks[block] |= 1 << bit;
+ } else {
+ self.blocks[block] &= !(1 << bit);
+ }
+ }
+
+ pub fn grow(&mut self, amount: Size, new_state: bool) {
+ let unused_trailing_bits = self.blocks.len() as u64 * BLOCK_SIZE - self.len.bytes();
+ if amount.bytes() > unused_trailing_bits {
+ let additional_blocks = amount.bytes() / BLOCK_SIZE + 1;
+ assert_eq!(additional_blocks as usize as u64, additional_blocks);
+ self.blocks.extend(
+ iter::repeat(0).take(additional_blocks as usize),
+ );
+ }
+ let start = self.len;
+ self.len += amount;
+ self.set_range_inbounds(start, start + amount, new_state);
+ }
+}
+
+#[inline]
+fn bit_index(bits: Size) -> (usize, usize) {
+ let bits = bits.bytes();
+ let a = bits / BLOCK_SIZE;
+ let b = bits % BLOCK_SIZE;
+ assert_eq!(a as usize as u64, a);
+ assert_eq!(b as usize as u64, b);
+ (a as usize, b as usize)
+}
mod error;
mod value;
+mod allocation;
+mod pointer;
pub use self::error::{
EvalError, EvalResult, EvalErrorKind, AssertMessage, ConstEvalErr, struct_error,
FrameInfo, ConstEvalResult, ErrorHandled,
};
-pub use self::value::{Scalar, ConstValue};
+pub use self::value::{Scalar, ConstValue, ScalarMaybeUndef};
+
+pub use self::allocation::{
+ Allocation, AllocationExtra,
+ Relocations, UndefMask,
+};
+
+pub use self::pointer::{Pointer, PointerArithmetic};
use std::fmt;
use mir;
use hir::def_id::DefId;
use ty::{self, TyCtxt, Instance};
-use ty::layout::{self, Align, HasDataLayout, Size};
+use ty::layout::{self, Size};
use middle::region;
-use std::iter;
use std::io;
-use std::ops::{Deref, DerefMut};
use std::hash::Hash;
-use syntax::ast::Mutability;
use rustc_serialize::{Encoder, Decodable, Encodable};
-use rustc_data_structures::sorted_map::SortedMap;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::{Lock as Mutex, HashMapExt};
use rustc_data_structures::tiny_list::TinyList;
pub promoted: Option<mir::Promoted>,
}
-////////////////////////////////////////////////////////////////////////////////
-// Pointer arithmetic
-////////////////////////////////////////////////////////////////////////////////
-
-pub trait PointerArithmetic: layout::HasDataLayout {
- // These are not supposed to be overridden.
-
- #[inline(always)]
- fn pointer_size(&self) -> Size {
- self.data_layout().pointer_size
- }
-
- //// Trunace the given value to the pointer size; also return whether there was an overflow
- #[inline]
- fn truncate_to_ptr(&self, val: u128) -> (u64, bool) {
- let max_ptr_plus_1 = 1u128 << self.pointer_size().bits();
- ((val % max_ptr_plus_1) as u64, val >= max_ptr_plus_1)
- }
-
- #[inline]
- fn offset<'tcx>(&self, val: u64, i: u64) -> EvalResult<'tcx, u64> {
- let (res, over) = self.overflowing_offset(val, i);
- if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
- }
-
- #[inline]
- fn overflowing_offset(&self, val: u64, i: u64) -> (u64, bool) {
- let (res, over1) = val.overflowing_add(i);
- let (res, over2) = self.truncate_to_ptr(u128::from(res));
- (res, over1 || over2)
- }
-
- #[inline]
- fn signed_offset<'tcx>(&self, val: u64, i: i64) -> EvalResult<'tcx, u64> {
- let (res, over) = self.overflowing_signed_offset(val, i128::from(i));
- if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
- }
-
- // Overflow checking only works properly on the range from -u64 to +u64.
- #[inline]
- fn overflowing_signed_offset(&self, val: u64, i: i128) -> (u64, bool) {
- // FIXME: is it possible to over/underflow here?
- if i < 0 {
- // trickery to ensure that i64::min_value() works fine
- // this formula only works for true negative values, it panics for zero!
- let n = u64::max_value() - (i as u64) + 1;
- val.overflowing_sub(n)
- } else {
- self.overflowing_offset(val, i as u64)
- }
- }
-}
-
-impl<T: layout::HasDataLayout> PointerArithmetic for T {}
-
-
-/// Pointer is generic over the type that represents a reference to Allocations,
-/// thus making it possible for the most convenient representation to be used in
-/// each context.
-///
-/// Defaults to the index based and loosely coupled AllocId.
-///
-/// Pointer is also generic over the `Tag` associated with each pointer,
-/// which is used to do provenance tracking during execution.
-#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
-pub struct Pointer<Tag=(),Id=AllocId> {
- pub alloc_id: Id,
- pub offset: Size,
- pub tag: Tag,
-}
-
-/// Produces a `Pointer` which points to the beginning of the Allocation
-impl From<AllocId> for Pointer {
- #[inline(always)]
- fn from(alloc_id: AllocId) -> Self {
- Pointer::new(alloc_id, Size::ZERO)
- }
-}
-
-impl<'tcx> Pointer<()> {
- #[inline(always)]
- pub fn new(alloc_id: AllocId, offset: Size) -> Self {
- Pointer { alloc_id, offset, tag: () }
- }
-
- #[inline(always)]
- pub fn with_default_tag<Tag>(self) -> Pointer<Tag>
- where Tag: Default
- {
- Pointer::new_with_tag(self.alloc_id, self.offset, Default::default())
- }
-}
-
-impl<'tcx, Tag> Pointer<Tag> {
- #[inline(always)]
- pub fn new_with_tag(alloc_id: AllocId, offset: Size, tag: Tag) -> Self {
- Pointer { alloc_id, offset, tag }
- }
-
- #[inline]
- pub fn offset(self, i: Size, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> {
- Ok(Pointer::new_with_tag(
- self.alloc_id,
- Size::from_bytes(cx.data_layout().offset(self.offset.bytes(), i.bytes())?),
- self.tag
- ))
- }
-
- #[inline]
- pub fn overflowing_offset(self, i: Size, cx: &impl HasDataLayout) -> (Self, bool) {
- let (res, over) = cx.data_layout().overflowing_offset(self.offset.bytes(), i.bytes());
- (Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over)
- }
-
- #[inline(always)]
- pub fn wrapping_offset(self, i: Size, cx: &impl HasDataLayout) -> Self {
- self.overflowing_offset(i, cx).0
- }
-
- #[inline]
- pub fn signed_offset(self, i: i64, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> {
- Ok(Pointer::new_with_tag(
- self.alloc_id,
- Size::from_bytes(cx.data_layout().signed_offset(self.offset.bytes(), i)?),
- self.tag,
- ))
- }
-
- #[inline]
- pub fn overflowing_signed_offset(self, i: i128, cx: &impl HasDataLayout) -> (Self, bool) {
- let (res, over) = cx.data_layout().overflowing_signed_offset(self.offset.bytes(), i);
- (Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over)
- }
-
- #[inline(always)]
- pub fn wrapping_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> Self {
- self.overflowing_signed_offset(i128::from(i), cx).0
- }
-
- #[inline(always)]
- pub fn erase_tag(self) -> Pointer {
- Pointer { alloc_id: self.alloc_id, offset: self.offset, tag: () }
- }
-}
-
-
#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd, Debug)]
pub struct AllocId(pub u64);
}
}
-#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
-pub struct Allocation<Tag=(),Extra=()> {
- /// The actual bytes of the allocation.
- /// Note that the bytes of a pointer represent the offset of the pointer
- pub bytes: Vec<u8>,
- /// Maps from byte addresses to extra data for each pointer.
- /// Only the first byte of a pointer is inserted into the map; i.e.,
- /// every entry in this map applies to `pointer_size` consecutive bytes starting
- /// at the given offset.
- pub relocations: Relocations<Tag>,
- /// Denotes undefined memory. Reading from undefined memory is forbidden in miri
- pub undef_mask: UndefMask,
- /// The alignment of the allocation to detect unaligned reads.
- pub align: Align,
- /// Whether the allocation is mutable.
- /// Also used by codegen to determine if a static should be put into mutable memory,
- /// which happens for `static mut` and `static` with interior mutability.
- pub mutability: Mutability,
- /// Extra state for the machine.
- pub extra: Extra,
-}
-
-impl<Tag, Extra: Default> Allocation<Tag, Extra> {
- /// Creates a read-only allocation initialized by the given bytes
- pub fn from_bytes(slice: &[u8], align: Align) -> Self {
- let mut undef_mask = UndefMask::new(Size::ZERO);
- undef_mask.grow(Size::from_bytes(slice.len() as u64), true);
- Self {
- bytes: slice.to_owned(),
- relocations: Relocations::new(),
- undef_mask,
- align,
- mutability: Mutability::Immutable,
- extra: Extra::default(),
- }
- }
-
- pub fn from_byte_aligned_bytes(slice: &[u8]) -> Self {
- Allocation::from_bytes(slice, Align::from_bytes(1, 1).unwrap())
- }
-
- pub fn undef(size: Size, align: Align) -> Self {
- assert_eq!(size.bytes() as usize as u64, size.bytes());
- Allocation {
- bytes: vec![0; size.bytes() as usize],
- relocations: Relocations::new(),
- undef_mask: UndefMask::new(size),
- align,
- mutability: Mutability::Mutable,
- extra: Extra::default(),
- }
- }
-}
-
-impl<'tcx> ::serialize::UseSpecializedDecodable for &'tcx Allocation {}
-
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
-pub struct Relocations<Tag=(), Id=AllocId>(SortedMap<Size, (Tag, Id)>);
-
-impl<Tag, Id> Relocations<Tag, Id> {
- pub fn new() -> Self {
- Relocations(SortedMap::new())
- }
-
- // The caller must guarantee that the given relocations are already sorted
- // by address and contain no duplicates.
- pub fn from_presorted(r: Vec<(Size, (Tag, Id))>) -> Self {
- Relocations(SortedMap::from_presorted_elements(r))
- }
-}
-
-impl<Tag> Deref for Relocations<Tag> {
- type Target = SortedMap<Size, (Tag, AllocId)>;
-
- fn deref(&self) -> &Self::Target {
- &self.0
- }
-}
-
-impl<Tag> DerefMut for Relocations<Tag> {
- fn deref_mut(&mut self) -> &mut Self::Target {
- &mut self.0
- }
-}
-
////////////////////////////////////////////////////////////////////////////////
// Methods to access integers in the target endianness
////////////////////////////////////////////////////////////////////////////////
// truncate (shift left to drop out leftover values, shift right to fill with zeroes)
(value << shift) >> shift
}
-
-////////////////////////////////////////////////////////////////////////////////
-// Undefined byte tracking
-////////////////////////////////////////////////////////////////////////////////
-
-type Block = u64;
-const BLOCK_SIZE: u64 = 64;
-
-#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
-pub struct UndefMask {
- blocks: Vec<Block>,
- len: Size,
-}
-
-impl_stable_hash_for!(struct mir::interpret::UndefMask{blocks, len});
-
-impl UndefMask {
- pub fn new(size: Size) -> Self {
- let mut m = UndefMask {
- blocks: vec![],
- len: Size::ZERO,
- };
- m.grow(size, false);
- m
- }
-
- /// Check whether the range `start..end` (end-exclusive) is entirely defined.
- ///
- /// Returns `Ok(())` if it's defined. Otherwise returns the index of the byte
- /// at which the first undefined access begins.
- #[inline]
- pub fn is_range_defined(&self, start: Size, end: Size) -> Result<(), Size> {
- if end > self.len {
- return Err(self.len);
- }
-
- let idx = (start.bytes()..end.bytes())
- .map(|i| Size::from_bytes(i))
- .find(|&i| !self.get(i));
-
- match idx {
- Some(idx) => Err(idx),
- None => Ok(())
- }
- }
-
- pub fn set_range(&mut self, start: Size, end: Size, new_state: bool) {
- let len = self.len;
- if end > len {
- self.grow(end - len, new_state);
- }
- self.set_range_inbounds(start, end, new_state);
- }
-
- pub fn set_range_inbounds(&mut self, start: Size, end: Size, new_state: bool) {
- for i in start.bytes()..end.bytes() {
- self.set(Size::from_bytes(i), new_state);
- }
- }
-
- #[inline]
- pub fn get(&self, i: Size) -> bool {
- let (block, bit) = bit_index(i);
- (self.blocks[block] & 1 << bit) != 0
- }
-
- #[inline]
- pub fn set(&mut self, i: Size, new_state: bool) {
- let (block, bit) = bit_index(i);
- if new_state {
- self.blocks[block] |= 1 << bit;
- } else {
- self.blocks[block] &= !(1 << bit);
- }
- }
-
- pub fn grow(&mut self, amount: Size, new_state: bool) {
- let unused_trailing_bits = self.blocks.len() as u64 * BLOCK_SIZE - self.len.bytes();
- if amount.bytes() > unused_trailing_bits {
- let additional_blocks = amount.bytes() / BLOCK_SIZE + 1;
- assert_eq!(additional_blocks as usize as u64, additional_blocks);
- self.blocks.extend(
- iter::repeat(0).take(additional_blocks as usize),
- );
- }
- let start = self.len;
- self.len += amount;
- self.set_range_inbounds(start, start + amount, new_state);
- }
-}
-
-#[inline]
-fn bit_index(bits: Size) -> (usize, usize) {
- let bits = bits.bytes();
- let a = bits / BLOCK_SIZE;
- let b = bits % BLOCK_SIZE;
- assert_eq!(a as usize as u64, a);
- assert_eq!(b as usize as u64, b);
- (a as usize, b as usize)
-}
--- /dev/null
+use mir;
+use ty::layout::{self, HasDataLayout, Size};
+
+use super::{
+ AllocId, EvalResult,
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Pointer arithmetic
+////////////////////////////////////////////////////////////////////////////////
+
+pub trait PointerArithmetic: layout::HasDataLayout {
+ // These are not supposed to be overridden.
+
+ #[inline(always)]
+ fn pointer_size(&self) -> Size {
+ self.data_layout().pointer_size
+ }
+
+ //// Trunace the given value to the pointer size; also return whether there was an overflow
+ #[inline]
+ fn truncate_to_ptr(&self, val: u128) -> (u64, bool) {
+ let max_ptr_plus_1 = 1u128 << self.pointer_size().bits();
+ ((val % max_ptr_plus_1) as u64, val >= max_ptr_plus_1)
+ }
+
+ #[inline]
+ fn offset<'tcx>(&self, val: u64, i: u64) -> EvalResult<'tcx, u64> {
+ let (res, over) = self.overflowing_offset(val, i);
+ if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
+ }
+
+ #[inline]
+ fn overflowing_offset(&self, val: u64, i: u64) -> (u64, bool) {
+ let (res, over1) = val.overflowing_add(i);
+ let (res, over2) = self.truncate_to_ptr(u128::from(res));
+ (res, over1 || over2)
+ }
+
+ #[inline]
+ fn signed_offset<'tcx>(&self, val: u64, i: i64) -> EvalResult<'tcx, u64> {
+ let (res, over) = self.overflowing_signed_offset(val, i128::from(i));
+ if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
+ }
+
+ // Overflow checking only works properly on the range from -u64 to +u64.
+ #[inline]
+ fn overflowing_signed_offset(&self, val: u64, i: i128) -> (u64, bool) {
+ // FIXME: is it possible to over/underflow here?
+ if i < 0 {
+ // trickery to ensure that i64::min_value() works fine
+ // this formula only works for true negative values, it panics for zero!
+ let n = u64::max_value() - (i as u64) + 1;
+ val.overflowing_sub(n)
+ } else {
+ self.overflowing_offset(val, i as u64)
+ }
+ }
+}
+
+impl<T: layout::HasDataLayout> PointerArithmetic for T {}
+
+
+/// Pointer is generic over the type that represents a reference to Allocations,
+/// thus making it possible for the most convenient representation to be used in
+/// each context.
+///
+/// Defaults to the index based and loosely coupled AllocId.
+///
+/// Pointer is also generic over the `Tag` associated with each pointer,
+/// which is used to do provenance tracking during execution.
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
+pub struct Pointer<Tag=(),Id=AllocId> {
+ pub alloc_id: Id,
+ pub offset: Size,
+ pub tag: Tag,
+}
+
+/// Produces a `Pointer` which points to the beginning of the Allocation
+impl From<AllocId> for Pointer {
+ #[inline(always)]
+ fn from(alloc_id: AllocId) -> Self {
+ Pointer::new(alloc_id, Size::ZERO)
+ }
+}
+
+impl<'tcx> Pointer<()> {
+ #[inline(always)]
+ pub fn new(alloc_id: AllocId, offset: Size) -> Self {
+ Pointer { alloc_id, offset, tag: () }
+ }
+
+ #[inline(always)]
+ pub fn with_default_tag<Tag>(self) -> Pointer<Tag>
+ where Tag: Default
+ {
+ Pointer::new_with_tag(self.alloc_id, self.offset, Default::default())
+ }
+}
+
+impl<'tcx, Tag> Pointer<Tag> {
+ #[inline(always)]
+ pub fn new_with_tag(alloc_id: AllocId, offset: Size, tag: Tag) -> Self {
+ Pointer { alloc_id, offset, tag }
+ }
+
+ #[inline]
+ pub fn offset(self, i: Size, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> {
+ Ok(Pointer::new_with_tag(
+ self.alloc_id,
+ Size::from_bytes(cx.data_layout().offset(self.offset.bytes(), i.bytes())?),
+ self.tag
+ ))
+ }
+
+ #[inline]
+ pub fn overflowing_offset(self, i: Size, cx: &impl HasDataLayout) -> (Self, bool) {
+ let (res, over) = cx.data_layout().overflowing_offset(self.offset.bytes(), i.bytes());
+ (Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over)
+ }
+
+ #[inline(always)]
+ pub fn wrapping_offset(self, i: Size, cx: &impl HasDataLayout) -> Self {
+ self.overflowing_offset(i, cx).0
+ }
+
+ #[inline]
+ pub fn signed_offset(self, i: i64, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> {
+ Ok(Pointer::new_with_tag(
+ self.alloc_id,
+ Size::from_bytes(cx.data_layout().signed_offset(self.offset.bytes(), i)?),
+ self.tag,
+ ))
+ }
+
+ #[inline]
+ pub fn overflowing_signed_offset(self, i: i128, cx: &impl HasDataLayout) -> (Self, bool) {
+ let (res, over) = cx.data_layout().overflowing_signed_offset(self.offset.bytes(), i);
+ (Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over)
+ }
+
+ #[inline(always)]
+ pub fn wrapping_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> Self {
+ self.overflowing_signed_offset(i128::from(i), cx).0
+ }
+
+ #[inline(always)]
+ pub fn erase_tag(self) -> Pointer {
+ Pointer { alloc_id: self.alloc_id, offset: self.offset, tag: () }
+ }
+}
Scalar::Ptr(ptr)
}
}
+
+#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
+pub enum ScalarMaybeUndef<Tag=(), Id=AllocId> {
+ Scalar(Scalar<Tag, Id>),
+ Undef,
+}
+
+impl<Tag> From<Scalar<Tag>> for ScalarMaybeUndef<Tag> {
+ #[inline(always)]
+ fn from(s: Scalar<Tag>) -> Self {
+ ScalarMaybeUndef::Scalar(s)
+ }
+}
+
+impl<Tag> fmt::Display for ScalarMaybeUndef<Tag> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ ScalarMaybeUndef::Undef => write!(f, "uninitialized bytes"),
+ ScalarMaybeUndef::Scalar(s) => write!(f, "{}", s),
+ }
+ }
+}
+
+impl<'tcx> ScalarMaybeUndef<()> {
+ #[inline]
+ pub fn with_default_tag<Tag>(self) -> ScalarMaybeUndef<Tag>
+ where Tag: Default
+ {
+ match self {
+ ScalarMaybeUndef::Scalar(s) => ScalarMaybeUndef::Scalar(s.with_default_tag()),
+ ScalarMaybeUndef::Undef => ScalarMaybeUndef::Undef,
+ }
+ }
+}
+
+impl<'tcx, Tag> ScalarMaybeUndef<Tag> {
+ #[inline]
+ pub fn erase_tag(self) -> ScalarMaybeUndef
+ {
+ match self {
+ ScalarMaybeUndef::Scalar(s) => ScalarMaybeUndef::Scalar(s.erase_tag()),
+ ScalarMaybeUndef::Undef => ScalarMaybeUndef::Undef,
+ }
+ }
+
+ #[inline]
+ pub fn not_undef(self) -> EvalResult<'static, Scalar<Tag>> {
+ match self {
+ ScalarMaybeUndef::Scalar(scalar) => Ok(scalar),
+ ScalarMaybeUndef::Undef => err!(ReadUndefBytes(Size::from_bytes(0))),
+ }
+ }
+
+ #[inline(always)]
+ pub fn to_ptr(self) -> EvalResult<'tcx, Pointer<Tag>> {
+ self.not_undef()?.to_ptr()
+ }
+
+ #[inline(always)]
+ pub fn to_bits(self, target_size: Size) -> EvalResult<'tcx, u128> {
+ self.not_undef()?.to_bits(target_size)
+ }
+
+ #[inline(always)]
+ pub fn to_bool(self) -> EvalResult<'tcx, bool> {
+ self.not_undef()?.to_bool()
+ }
+
+ #[inline(always)]
+ pub fn to_char(self) -> EvalResult<'tcx, char> {
+ self.not_undef()?.to_char()
+ }
+
+ #[inline(always)]
+ pub fn to_f32(self) -> EvalResult<'tcx, f32> {
+ self.not_undef()?.to_f32()
+ }
+
+ #[inline(always)]
+ pub fn to_f64(self) -> EvalResult<'tcx, f64> {
+ self.not_undef()?.to_f64()
+ }
+
+ #[inline(always)]
+ pub fn to_u8(self) -> EvalResult<'tcx, u8> {
+ self.not_undef()?.to_u8()
+ }
+
+ #[inline(always)]
+ pub fn to_u32(self) -> EvalResult<'tcx, u32> {
+ self.not_undef()?.to_u32()
+ }
+
+ #[inline(always)]
+ pub fn to_u64(self) -> EvalResult<'tcx, u64> {
+ self.not_undef()?.to_u64()
+ }
+
+ #[inline(always)]
+ pub fn to_usize(self, cx: &impl HasDataLayout) -> EvalResult<'tcx, u64> {
+ self.not_undef()?.to_usize(cx)
+ }
+
+ #[inline(always)]
+ pub fn to_i8(self) -> EvalResult<'tcx, i8> {
+ self.not_undef()?.to_i8()
+ }
+
+ #[inline(always)]
+ pub fn to_i32(self) -> EvalResult<'tcx, i32> {
+ self.not_undef()?.to_i32()
+ }
+
+ #[inline(always)]
+ pub fn to_i64(self) -> EvalResult<'tcx, i64> {
+ self.not_undef()?.to_i64()
+ }
+
+ #[inline(always)]
+ pub fn to_isize(self, cx: &impl HasDataLayout) -> EvalResult<'tcx, i64> {
+ self.not_undef()?.to_isize(cx)
+ }
+}
+
+impl_stable_hash_for!(enum ::mir::interpret::ScalarMaybeUndef {
+ Scalar(v),
+ Undef
+});
use mir::visit::MirVisitable;
use rustc_apfloat::ieee::{Double, Single};
use rustc_apfloat::Float;
+use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::graph::dominators::{dominators, Dominators};
use rustc_data_structures::graph::{self, GraphPredecessors, GraphSuccessors};
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
})
}
+ /// Returns an iterator over all user-declared mutable locals.
+ #[inline]
+ pub fn mut_vars_iter<'a>(&'a self) -> impl Iterator<Item = Local> + 'a {
+ (self.arg_count + 1..self.local_decls.len()).filter_map(move |index| {
+ let local = Local::new(index);
+ let decl = &self.local_decls[local];
+ if decl.is_user_variable.is_some() && decl.mutability == Mutability::Mut {
+ Some(local)
+ } else {
+ None
+ }
+ })
+ }
+
/// Returns an iterator over all user-declared mutable arguments and locals.
#[inline]
pub fn mut_vars_and_args_iter<'a>(&'a self) -> impl Iterator<Item = Local> + 'a {
pub kind: StatementKind<'tcx>,
}
+// `Statement` is used a lot. Make sure it doesn't unintentionally get bigger.
+#[cfg(target_arch = "x86_64")]
+static_assert!(MEM_SIZE_OF_STATEMENT: mem::size_of::<Statement<'_>>() == 56);
+
impl<'tcx> Statement<'tcx> {
/// Changes a statement to a nop. This is both faster than deleting instructions and avoids
/// invalidating statement indices in `Location`s.
pub fn make_nop(&mut self) {
- // `Statement` contributes significantly to peak memory usage. Make
- // sure it doesn't get bigger.
- static_assert!(STATEMENT_IS_AT_MOST_56_BYTES: mem::size_of::<Statement<'_>>() <= 56);
-
self.kind = StatementKind::Nop
}
}
}
+ /// Returns `true` if `other` is earlier in the control flow graph than `self`.
+ pub fn is_predecessor_of<'tcx>(&self, other: Location, mir: &Mir<'tcx>) -> bool {
+ // If we are in the same block as the other location and are an earlier statement
+ // then we are a predecessor of `other`.
+ if self.block == other.block && self.statement_index < other.statement_index {
+ return true;
+ }
+
+ // If we're in another block, then we want to check that block is a predecessor of `other`.
+ let mut queue: Vec<BasicBlock> = mir.predecessors_for(other.block).clone();
+ let mut visited = FxHashSet::default();
+
+ while let Some(block) = queue.pop() {
+ // If we haven't visited this block before, then make sure we visit it's predecessors.
+ if visited.insert(block) {
+ queue.append(&mut mir.predecessors_for(block).clone());
+ } else {
+ continue;
+ }
+
+ // If we found the block that `self` is in, then we are a predecessor of `other` (since
+ // we found that block by looking at the predecessors of `other`).
+ if self.block == block {
+ return true;
+ }
+ }
+
+ false
+ }
+
pub fn dominates(&self, other: Location, dominators: &Dominators<BasicBlock>) -> bool {
if self.block == other.block {
self.statement_index <= other.statement_index
elem: &PlaceElem<'tcx>)
-> PlaceTy<'tcx>
{
- self.projection_ty_core(tcx, elem, |_, _, ty| ty)
+ self.projection_ty_core(tcx, elem, |_, _, ty| -> Result<Ty<'tcx>, ()> { Ok(ty) })
+ .unwrap()
}
/// `place_ty.projection_ty_core(tcx, elem, |...| { ... })`
/// `Ty` or downcast variant corresponding to that projection.
/// The `handle_field` callback must map a `Field` to its `Ty`,
/// (which should be trivial when `T` = `Ty`).
- pub fn projection_ty_core<V, T>(self,
- tcx: TyCtxt<'a, 'gcx, 'tcx>,
- elem: &ProjectionElem<'tcx, V, T>,
- mut handle_field: impl FnMut(&Self, &Field, &T) -> Ty<'tcx>)
- -> PlaceTy<'tcx>
+ pub fn projection_ty_core<V, T, E>(
+ self,
+ tcx: TyCtxt<'a, 'gcx, 'tcx>,
+ elem: &ProjectionElem<'tcx, V, T>,
+ mut handle_field: impl FnMut(&Self, &Field, &T) -> Result<Ty<'tcx>, E>)
+ -> Result<PlaceTy<'tcx>, E>
where
V: ::std::fmt::Debug, T: ::std::fmt::Debug
{
bug!("cannot downcast non-ADT type: `{:?}`", self)
}
},
- ProjectionElem::Field(ref f, ref fty) => PlaceTy::Ty { ty: handle_field(&self, f, fty) }
+ ProjectionElem::Field(ref f, ref fty) =>
+ PlaceTy::Ty { ty: handle_field(&self, f, fty)? },
};
debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
- answer
+ Ok(answer)
}
}
error_format,
&format!(
"optimization level needs to be \
- between 0-3 (instead was `{}`)",
+ between 0-3, s or z (instead was `{}`)",
arg
),
);
/// The metadata::creader module may inject an allocator/panic_runtime
/// dependency if it didn't already find one, and this tracks what was
/// injected.
- pub injected_allocator: Once<Option<CrateNum>>,
pub allocator_kind: Once<Option<AllocatorKind>>,
pub injected_panic_runtime: Once<Option<CrateNum>>,
self.opts.debugging_opts.teach && self.diagnostic().must_teach(code)
}
+ pub fn rust_2015(&self) -> bool {
+ self.opts.edition == Edition::Edition2015
+ }
+
/// Are we allowed to use features from the Rust 2018 edition?
pub fn rust_2018(&self) -> bool {
self.opts.edition >= Edition::Edition2018
type_length_limit: Once::new(),
const_eval_stack_frame_limit: 100,
next_node_id: OneThread::new(Cell::new(NodeId::new(1))),
- injected_allocator: Once::new(),
allocator_kind: Once::new(),
injected_panic_runtime: Once::new(),
imported_macro_spans: OneThread::new(RefCell::new(FxHashMap::default())),
pub use self::specialize::{OverlapError, specialization_graph, translate_substs};
pub use self::specialize::find_associated_item;
pub use self::engine::{TraitEngine, TraitEngineExt};
-pub use self::util::elaborate_predicates;
-pub use self::util::supertraits;
-pub use self::util::Supertraits;
-pub use self::util::supertrait_def_ids;
-pub use self::util::SupertraitDefIds;
+pub use self::util::{elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs};
+pub use self::util::{supertraits, supertrait_def_ids, Supertraits, SupertraitDefIds};
pub use self::util::transitive_bounds;
#[allow(dead_code)]
let recursion_limit = *selcx.tcx().sess.recursion_limit.get();
if obligation.recursion_depth >= recursion_limit {
debug!("project: overflow!");
- selcx.infcx().report_overflow_error(&obligation, true);
+ return Err(ProjectionTyError::TraitSelectionError(SelectionError::Overflow));
}
let obligation_trait_ref = &obligation.predicate.trait_ref(selcx.tcx());
if !substs.is_noop() {
types_without_default_bounds.extend(substs.types());
w.push('<');
- w.push_str(&substs.iter().map(|k| k.to_string()).collect::<Vec<_>>().join(", "));
+ w.push_str(&substs.iter()
+ .map(|k| k.to_string())
+ .filter(|k| &k[..] != "'_")
+ .collect::<Vec<_>>().join(", "));
w.push('>');
}
pub fn items(
&self,
tcx: TyCtxt<'a, 'gcx, 'tcx>,
- ) -> impl Iterator<Item = ty::AssociatedItem> + 'a {
+ ) -> ty::AssociatedItemsIterator<'a, 'gcx, 'tcx> {
tcx.associated_items(self.def_id())
}
}
let visited = &mut self.visited;
+ let mut components = smallvec![];
+ tcx.push_outlives_components(ty_max, &mut components);
self.stack.extend(
- tcx.outlives_components(ty_max)
+ components
.into_iter()
.filter_map(|component| match component {
Component::Region(r) => if r.is_late_bound() {
}
}
-impl<'tcx,I:Iterator<Item = ty::Predicate<'tcx>>> Iterator for FilterToTraits<I> {
+impl<'tcx, I: Iterator<Item = ty::Predicate<'tcx>>> Iterator for FilterToTraits<I> {
type Item = ty::PolyTraitRef<'tcx>;
fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {
use session::config::{BorrowckMode, OutputFilenames};
use session::config::CrateType;
use middle;
-use hir::{TraitCandidate, HirId, ItemLocalId, Node};
+use hir::{TraitCandidate, HirId, ItemKind, ItemLocalId, Node};
use hir::def::{Def, Export};
use hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE};
use hir::map as hir_map;
impl<'tcx> CommonTypes<'tcx> {
fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> {
- // Ensure our type representation does not grow
- #[cfg(target_pointer_width = "64")]
- static_assert!(ASSERT_TY_KIND: ::std::mem::size_of::<ty::TyKind<'_>>() <= 24);
- #[cfg(target_pointer_width = "64")]
- static_assert!(ASSERT_TYS: ::std::mem::size_of::<ty::TyS<'_>>() <= 32);
-
let mk = |sty| CtxtInterners::intern_ty(interners, interners, sty);
let mk_region = |r| {
if let Some(r) = interners.region.borrow().get(&r) {
&self,
scope_def_id: DefId,
) -> Option<Ty<'tcx>> {
+ // HACK: `type_of_def_id()` will fail on these (#55796), so return None
+ let node_id = self.hir.as_local_node_id(scope_def_id).unwrap();
+ match self.hir.get(node_id) {
+ Node::Item(item) => {
+ match item.node {
+ ItemKind::Fn(..) => { /* type_of_def_id() will work */ }
+ _ => {
+ return None;
+ }
+ }
+ }
+ _ => { /* type_of_def_id() will work or panic */ }
+ }
+
let ret_ty = self.type_of(scope_def_id);
match ret_ty.sty {
ty::FnDef(_, _) => {
}
}
- /// Returns true if an item with this visibility is accessible from the given block.
+ /// Returns `true` if an item with this visibility is accessible from the given block.
pub fn is_accessible_from<T: DefIdTree>(self, module: DefId, tree: T) -> bool {
let restriction = match self {
// Public items are visible everywhere.
tree.is_descendant_of(module, restriction)
}
- /// Returns true if this visibility is at least as accessible as the given visibility
+ /// Returns `true` if this visibility is at least as accessible as the given visibility
pub fn is_at_least<T: DefIdTree>(self, vis: Visibility, tree: T) -> bool {
let vis_restriction = match vis {
Visibility::Public => return self == Visibility::Public,
self.is_accessible_from(vis_restriction, tree)
}
- // Returns true if this item is visible anywhere in the local crate.
+ // Returns `true` if this item is visible anywhere in the local crate.
pub fn is_visible_locally(self) -> bool {
match self {
Visibility::Public => true,
// FIXME: Rename this to the actual property since it's used for generators too
const HAS_TY_CLOSURE = 1 << 9;
- // true if there are "names" of types and regions and so forth
+ // `true` if there are "names" of types and regions and so forth
// that are local to a particular fn
const HAS_FREE_LOCAL_NAMES = 1 << 10;
outer_exclusive_binder: ty::DebruijnIndex,
}
+// `TyS` is used a lot. Make sure it doesn't unintentionally get bigger.
+#[cfg(target_arch = "x86_64")]
+static_assert!(MEM_SIZE_OF_TY_S: ::std::mem::size_of::<TyS<'_>>() == 32);
+
impl<'tcx> Ord for TyS<'tcx> {
fn cmp(&self, other: &TyS<'tcx>) -> Ordering {
self.sty.cmp(&other.sty)
pub fn is_primitive_ty(&self) -> bool {
match self.sty {
TyKind::Bool |
- TyKind::Char |
- TyKind::Int(_) |
- TyKind::Uint(_) |
- TyKind::Float(_) |
- TyKind::Infer(InferTy::IntVar(_)) |
- TyKind::Infer(InferTy::FloatVar(_)) |
- TyKind::Infer(InferTy::FreshIntTy(_)) |
- TyKind::Infer(InferTy::FreshFloatTy(_)) => true,
+ TyKind::Char |
+ TyKind::Int(_) |
+ TyKind::Uint(_) |
+ TyKind::Float(_) |
+ TyKind::Infer(InferTy::IntVar(_)) |
+ TyKind::Infer(InferTy::FloatVar(_)) |
+ TyKind::Infer(InferTy::FreshIntTy(_)) |
+ TyKind::Infer(InferTy::FreshFloatTy(_)) => true,
TyKind::Ref(_, x, _) => x.is_primitive_ty(),
_ => false,
}
_ => bug!("expected lifetime parameter, but found another generic parameter")
}
} else {
- tcx.generics_of(self.parent.expect("parent_count>0 but no parent?"))
+ tcx.generics_of(self.parent.expect("parent_count > 0 but no parent?"))
.region_param(param, tcx)
}
}
_ => bug!("expected type parameter, but found another generic parameter")
}
} else {
- tcx.generics_of(self.parent.expect("parent_count>0 but no parent?"))
+ tcx.generics_of(self.parent.expect("parent_count > 0 but no parent?"))
.type_param(param, tcx)
}
}
self.instantiate_into(tcx, &mut instantiated, substs);
instantiated
}
+
pub fn instantiate_own(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, substs: &Substs<'tcx>)
-> InstantiatedPredicates<'tcx> {
InstantiatedPredicates {
#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub enum Predicate<'tcx> {
- /// Corresponds to `where Foo : Bar<A,B,C>`. `Foo` here would be
+ /// Corresponds to `where Foo: Bar<A,B,C>`. `Foo` here would be
/// the `Self` type of the trait reference and `A`, `B`, and `C`
/// would be the type parameters.
Trait(PolyTraitPredicate<'tcx>),
- /// where `'a : 'b`
+ /// where `'a: 'b`
RegionOutlives(PolyRegionOutlivesPredicate<'tcx>),
- /// where `T : 'a`
+ /// where `T: 'a`
TypeOutlives(PolyTypeOutlivesPredicate<'tcx>),
/// where `<T as TraitRef>::Name == X`, approximately.
/// trait must be object-safe
ObjectSafe(DefId),
- /// No direct syntax. May be thought of as `where T : FnFoo<...>`
+ /// No direct syntax. May be thought of as `where T: FnFoo<...>`
/// for some substitutions `...` and `T` being a closure type.
/// Satisfied (or refuted) once we know the closure's kind.
ClosureKind(DefId, ClosureSubsts<'tcx>, ClosureKind),
//
// Let's start with an easy case. Consider two traits:
//
- // trait Foo<'a> : Bar<'a,'a> { }
+ // trait Foo<'a>: Bar<'a,'a> { }
// trait Bar<'b,'c> { }
//
- // Now, if we have a trait reference `for<'x> T : Foo<'x>`, then
- // we can deduce that `for<'x> T : Bar<'x,'x>`. Basically, if we
+ // Now, if we have a trait reference `for<'x> T: Foo<'x>`, then
+ // we can deduce that `for<'x> T: Bar<'x,'x>`. Basically, if we
// knew that `Foo<'x>` (for any 'x) then we also know that
// `Bar<'x,'x>` (for any 'x). This more-or-less falls out from
// normal substitution.
//
// Another example to be careful of is this:
//
- // trait Foo1<'a> : for<'b> Bar1<'a,'b> { }
+ // trait Foo1<'a>: for<'b> Bar1<'a,'b> { }
// trait Bar1<'b,'c> { }
//
- // Here, if we have `for<'x> T : Foo1<'x>`, then what do we know?
- // The answer is that we know `for<'x,'b> T : Bar1<'x,'b>`. The
+ // Here, if we have `for<'x> T: Foo1<'x>`, then what do we know?
+ // The answer is that we know `for<'x,'b> T: Bar1<'x,'b>`. The
// reason is similar to the previous example: any impl of
- // `T:Foo1<'x>` must show that `for<'b> T : Bar1<'x, 'b>`. So
+ // `T:Foo1<'x>` must show that `for<'b> T: Bar1<'x, 'b>`. So
// basically we would want to collapse the bound lifetimes from
// the input (`trait_ref`) and the supertraits.
//
// To achieve this in practice is fairly straightforward. Let's
// consider the more complicated scenario:
//
- // - We start out with `for<'x> T : Foo1<'x>`. In this case, `'x`
- // has a De Bruijn index of 1. We want to produce `for<'x,'b> T : Bar1<'x,'b>`,
+ // - We start out with `for<'x> T: Foo1<'x>`. In this case, `'x`
+ // has a De Bruijn index of 1. We want to produce `for<'x,'b> T: Bar1<'x,'b>`,
// where both `'x` and `'b` would have a DB index of 1.
// The substitution from the input trait-ref is therefore going to be
// `'a => 'x` (where `'x` has a DB index of 1).
pub struct TraitPredicate<'tcx> {
pub trait_ref: TraitRef<'tcx>
}
+
pub type PolyTraitPredicate<'tcx> = ty::Binder<TraitPredicate<'tcx>>;
impl<'tcx> TraitPredicate<'tcx> {
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
-pub struct OutlivesPredicate<A,B>(pub A, pub B); // `A : B`
+pub struct OutlivesPredicate<A,B>(pub A, pub B); // `A: B`
pub type PolyOutlivesPredicate<A,B> = ty::Binder<OutlivesPredicate<A,B>>;
pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate<ty::Region<'tcx>,
ty::Region<'tcx>>;
/// This kind of predicate has no *direct* correspondent in the
/// syntax, but it roughly corresponds to the syntactic forms:
///
-/// 1. `T : TraitRef<..., Item=Type>`
+/// 1. `T: TraitRef<..., Item=Type>`
/// 2. `<T as TraitRef<...>>::Item == Type` (NYI)
///
/// In particular, form #1 is "desugared" to the combination of a
-/// normal trait predicate (`T : TraitRef<...>`) and one of these
+/// normal trait predicate (`T: TraitRef<...>`) and one of these
/// predicates. Form #2 is a broader form in that it also permits
/// equality between arbitrary types. Processing an instance of
/// Form #2 eventually yields one of these `ProjectionPredicate`
pub type PolyProjectionPredicate<'tcx> = Binder<ProjectionPredicate<'tcx>>;
impl<'tcx> PolyProjectionPredicate<'tcx> {
- /// Returns the def-id of the associated item being projected.
+ /// Returns the `DefId` of the associated item being projected.
pub fn item_def_id(&self) -> DefId {
self.skip_binder().projection_ty.item_def_id
}
pub fn to_poly_trait_ref(&self, tcx: TyCtxt<'_, '_, '_>) -> PolyTraitRef<'tcx> {
- // Note: unlike with TraitRef::to_poly_trait_ref(),
- // self.0.trait_ref is permitted to have escaping regions.
+ // Note: unlike with `TraitRef::to_poly_trait_ref()`,
+ // `self.0.trait_ref` is permitted to have escaping regions.
// This is because here `self` has a `Binder` and so does our
// return value, so we are preserving the number of binding
// levels.
self.map_bound(|predicate| predicate.ty)
}
- /// The DefId of the TraitItem for the associated type.
+ /// The `DefId` of the `TraitItem` for the associated type.
///
- /// Note that this is not the DefId of the TraitRef containing this
- /// associated type, which is in tcx.associated_item(projection_def_id()).container.
+ /// Note that this is not the `DefId` of the `TraitRef` containing this
+ /// associated type, which is in `tcx.associated_item(projection_def_id()).container`.
pub fn projection_def_id(&self) -> DefId {
- // ok to skip binder since trait def-id does not care about regions
+ // okay to skip binder since trait def-id does not care about regions
self.skip_binder().projection_ty.item_def_id
}
}
UniverseIndex::from_u32(self.private.checked_add(1).unwrap())
}
- /// True if `self` can name a name from `other` -- in other words,
+ /// Returns `true` if `self` can name a name from `other` -- in other words,
/// if the set of names in `self` is a superset of those in
/// `other` (`self >= other`).
pub fn can_name(self, other: UniverseIndex) -> bool {
self.private >= other.private
}
- /// True if `self` cannot name some names from `other` -- in other
+ /// Returns `true` if `self` cannot name some names from `other` -- in other
/// words, if the set of names in `self` is a strict subset of
/// those in `other` (`self < other`).
pub fn cannot_name(self, other: UniverseIndex) -> bool {
/// are revealed. This is suitable for monomorphized, post-typeck
/// environments like codegen or doing optimizations.
///
- /// NB. If you want to have predicates in scope, use `ParamEnv::new`,
+ /// N.B. If you want to have predicates in scope, use `ParamEnv::new`,
/// or invoke `param_env.with_reveal_all()`.
pub fn reveal_all() -> Self {
Self::new(List::empty(), Reveal::All)
self.int.unwrap_or(attr::SignedInt(ast::IntTy::Isize))
}
- /// Returns true if this `#[repr()]` should inhabit "smart enum
+ /// Returns `true` if this `#[repr()]` should inhabit "smart enum
/// layout" optimizations, such as representing `Foo<&T>` as a
/// single pointer.
pub fn inhibit_enum_layout_opt(&self) -> bool {
self.c() || self.int.is_some()
}
- /// Returns true if this `#[repr()]` should inhibit struct field reordering
+ /// Returns `true` if this `#[repr()]` should inhibit struct field reordering
/// optimizations, such as with repr(C) or repr(packed(1)).
pub fn inhibit_struct_field_reordering_opt(&self) -> bool {
!(self.flags & ReprFlags::IS_UNOPTIMISABLE).is_empty() || (self.pack == 1)
self.flags.intersects(AdtFlags::IS_FUNDAMENTAL)
}
- /// Returns true if this is PhantomData<T>.
+ /// Returns `true` if this is PhantomData<T>.
#[inline]
pub fn is_phantom_data(&self) -> bool {
self.flags.intersects(AdtFlags::IS_PHANTOM_DATA)
self.flags.intersects(AdtFlags::IS_RC)
}
- /// Returns true if this is Box<T>.
+ /// Returns `true` if this is Box<T>.
#[inline]
pub fn is_box(&self) -> bool {
self.flags.intersects(AdtFlags::IS_BOX)
}
}
- /// True if this a type that impls this closure kind
+ /// Returns `true` if this a type that impls this closure kind
/// must also implement `other`.
pub fn extends(self, other: ty::ClosureKind) -> bool {
match (self, other) {
///
/// Note: prefer `ty.walk()` where possible.
pub fn maybe_walk<F>(&'tcx self, mut f: F)
- where F : FnMut(Ty<'tcx>) -> bool
+ where F: FnMut(Ty<'tcx>) -> bool
{
let mut walker = self.walk();
while let Some(ty) = walker.next() {
pub fn associated_items(
self,
def_id: DefId,
- ) -> impl Iterator<Item = AssociatedItem> + 'a {
- let def_ids = self.associated_item_def_ids(def_id);
- Box::new((0..def_ids.len()).map(move |i| self.associated_item(def_ids[i])))
- as Box<dyn Iterator<Item = AssociatedItem> + 'a>
+ ) -> AssociatedItemsIterator<'a, 'gcx, 'tcx> {
+ // Ideally, we would use `-> impl Iterator` here, but it falls
+ // afoul of the conservative "capture [restrictions]" we put
+ // in place, so we use a hand-written iterator.
+ //
+ // [restrictions]: https://github.com/rust-lang/rust/issues/34511#issuecomment-373423999
+ AssociatedItemsIterator {
+ tcx: self,
+ def_ids: self.associated_item_def_ids(def_id),
+ next_index: 0,
+ }
}
- /// Returns true if the impls are the same polarity and the trait either
+ /// Returns `true` if the impls are the same polarity and the trait either
/// has no items or is annotated #[marker] and prevents item overrides.
pub fn impls_are_allowed_to_overlap(self, def_id1: DefId, def_id2: DefId) -> bool {
if self.features().overlapping_marker_traits {
attr::contains_name(&self.get_attrs(did), attr)
}
- /// Returns true if this is an `auto trait`.
+ /// Returns `true` if this is an `auto trait`.
pub fn trait_is_auto(self, trait_def_id: DefId) -> bool {
self.trait_def(trait_def_id).has_auto_impl
}
}
}
+pub struct AssociatedItemsIterator<'a, 'gcx: 'tcx, 'tcx: 'a> {
+ tcx: TyCtxt<'a, 'gcx, 'tcx>,
+ def_ids: Lrc<Vec<DefId>>,
+ next_index: usize,
+}
+
+impl Iterator for AssociatedItemsIterator<'_, '_, '_> {
+ type Item = AssociatedItem;
+
+ fn next(&mut self) -> Option<AssociatedItem> {
+ let def_id = self.def_ids.get(self.next_index)?;
+ self.next_index += 1;
+ Some(self.tcx.associated_item(*def_id))
+ }
+}
+
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
pub fn with_freevars<T, F>(self, fid: NodeId, f: F) -> T where
F: FnOnce(&[hir::Freevar]) -> T,
// refers to rules defined in RFC 1214 (`OutlivesFooBar`), so see that
// RFC for reference.
+use smallvec::SmallVec;
use ty::{self, Ty, TyCtxt, TypeFoldable};
#[derive(Debug)]
}
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
- /// Returns all the things that must outlive `'a` for the condition
+ /// Push onto `out` all the things that must outlive `'a` for the condition
/// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**.
- pub fn outlives_components(&self, ty0: Ty<'tcx>)
- -> Vec<Component<'tcx>> {
- let mut components = vec![];
- self.compute_components(ty0, &mut components);
- debug!("components({:?}) = {:?}", ty0, components);
- components
+ pub fn push_outlives_components(&self, ty0: Ty<'tcx>,
+ out: &mut SmallVec<[Component<'tcx>; 4]>) {
+ self.compute_components(ty0, out);
+ debug!("components({:?}) = {:?}", ty0, out);
}
- fn compute_components(&self, ty: Ty<'tcx>, out: &mut Vec<Component<'tcx>>) {
+ fn compute_components(&self, ty: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) {
// Descend through the types, looking for the various "base"
// components and collecting them into `out`. This is not written
// with `collect()` because of the need to sometimes skip subtrees
// list is maintained explicitly, because bound regions
// themselves can be readily identified.
- push_region_constraints(out, ty.regions());
+ push_region_constraints(ty, out);
for subty in ty.walk_shallow() {
self.compute_components(subty, out);
}
}
fn capture_components(&self, ty: Ty<'tcx>) -> Vec<Component<'tcx>> {
- let mut temp = vec![];
- push_region_constraints(&mut temp, ty.regions());
+ let mut temp = smallvec![];
+ push_region_constraints(ty, &mut temp);
for subty in ty.walk_shallow() {
self.compute_components(subty, &mut temp);
}
- temp
+ temp.into_iter().collect()
}
}
-fn push_region_constraints<'tcx>(out: &mut Vec<Component<'tcx>>, regions: Vec<ty::Region<'tcx>>) {
+fn push_region_constraints<'tcx>(ty: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) {
+ let mut regions = smallvec![];
+ ty.push_regions(&mut regions);
out.extend(regions.iter().filter(|&r| !r.is_late_bound()).map(|r| Component::Region(r)));
}
.map(|&(cnum, ..)| cnum)
.max()
.unwrap_or(0) + 1;
- let mut map = IndexVec::new();
- map.resize(map_size as usize, None);
+ let mut map = IndexVec::from_elem_n(None, map_size as usize);
for &(prev_cnum, ref crate_name, crate_disambiguator) in prev_cnums {
let key = (crate_name.clone(), crate_disambiguator);
use util::captures::Captures;
use mir::interpret::{Scalar, Pointer};
+use smallvec::SmallVec;
use std::iter;
use std::cmp::Ordering;
use rustc_target::spec::abi;
Error,
}
+// `TyKind` is used a lot. Make sure it doesn't unintentionally get bigger.
+#[cfg(target_arch = "x86_64")]
+static_assert!(MEM_SIZE_OF_TY_KIND: ::std::mem::size_of::<TyKind<'_>>() == 24);
+
/// A closure can be modeled as a struct that looks like:
///
/// struct Closure<'l0...'li, T0...Tj, CK, CS, U0...Uk> {
/// A complete reference to a trait. These take numerous guises in syntax,
/// but perhaps the most recognizable form is in a where clause:
///
-/// T : Foo<U>
+/// T: Foo<U>
///
/// This would be represented by a trait-reference where the def-id is the
/// def-id for the trait `Foo` and the substs define `T` as parameter 0,
/// that case the `Self` parameter is absent from the substitutions.
///
/// Note that a `TraitRef` introduces a level of region binding, to
-/// account for higher-ranked trait bounds like `T : for<'a> Foo<&'a
-/// U>` or higher-ranked object types.
+/// account for higher-ranked trait bounds like `T: for<'a> Foo<&'a U>`
+/// or higher-ranked object types.
#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub struct TraitRef<'tcx> {
pub def_id: DefId,
self.substs.type_at(0)
}
- pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {
+ pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> + 'a {
// Select only the "input types" from a trait-reference. For
// now this is all the types that appear in the
// trait-reference, but it should eventually exclude
/// The parameters of the associated item.
pub substs: &'tcx Substs<'tcx>,
- /// The DefId of the TraitItem for the associated type N.
+ /// The `DefId` of the `TraitItem` for the associated type `N`.
///
- /// Note that this is not the DefId of the TraitRef containing this
- /// associated type, which is in tcx.associated_item(item_def_id).container.
+ /// Note that this is not the `DefId` of the `TraitRef` containing this
+ /// associated type, which is in `tcx.associated_item(item_def_id).container`.
pub item_def_id: DefId,
}
impl<'a, 'tcx> ProjectionTy<'tcx> {
- /// Construct a ProjectionTy by searching the trait from trait_ref for the
- /// associated item named item_name.
+ /// Construct a `ProjectionTy` by searching the trait from `trait_ref` for the
+ /// associated item named `item_name`.
pub fn from_ref_and_name(
tcx: TyCtxt<'_, '_, '_>, trait_ref: ty::TraitRef<'tcx>, item_name: Ident
) -> ProjectionTy<'tcx> {
}
}
- /// Returns the regions directly referenced from this type (but
- /// not types reachable from this type via `walk_tys`). This
- /// ignores late-bound regions binders.
- pub fn regions(&self) -> Vec<ty::Region<'tcx>> {
+ /// Push onto `out` the regions directly referenced from this type (but not
+ /// types reachable from this type via `walk_tys`). This ignores late-bound
+ /// regions binders.
+ pub fn push_regions(&self, out: &mut SmallVec<[ty::Region<'tcx>; 4]>) {
match self.sty {
Ref(region, _, _) => {
- vec![region]
+ out.push(region);
}
Dynamic(ref obj, region) => {
- let mut v = vec![region];
- v.extend(obj.principal().skip_binder().substs.regions());
- v
+ out.push(region);
+ out.extend(obj.principal().skip_binder().substs.regions());
}
Adt(_, substs) | Opaque(_, substs) => {
- substs.regions().collect()
+ out.extend(substs.regions())
}
Closure(_, ClosureSubsts { ref substs }) |
Generator(_, GeneratorSubsts { ref substs }, _) => {
- substs.regions().collect()
+ out.extend(substs.regions())
}
Projection(ref data) | UnnormalizedProjection(ref data) => {
- data.substs.regions().collect()
+ out.extend(data.substs.regions())
}
FnDef(..) |
FnPtr(_) |
Param(_) |
Bound(..) |
Infer(_) |
- Error => {
- vec![]
- }
+ Error => {}
}
}
use std::mem;
use std::num::NonZeroUsize;
-/// An entity in the Rust typesystem, which can be one of
+/// An entity in the Rust type system, which can be one of
/// several kinds (only types and lifetimes for now).
/// To reduce memory usage, a `Kind` is a interned pointer,
/// with the lowest 2 bits being reserved for a tag to
pub type Substs<'tcx> = List<Kind<'tcx>>;
impl<'a, 'gcx, 'tcx> Substs<'tcx> {
- /// Creates a Substs that maps each generic parameter to itself.
+ /// Creates a `Substs` that maps each generic parameter to itself.
pub fn identity_for_item(tcx: TyCtxt<'a, 'gcx, 'tcx>, def_id: DefId)
-> &'tcx Substs<'tcx> {
Substs::for_item(tcx, def_id, |param, _| {
})
}
- /// Creates a Substs for generic parameter definitions,
+ /// Creates a `Substs` for generic parameter definitions,
/// by calling closures to obtain each kind.
- /// The closures get to observe the Substs as they're
+ /// The closures get to observe the `Substs` as they're
/// being built, which can be used to correctly
/// substitute defaults of generic parameters.
pub fn for_item<F>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
}
#[inline]
- pub fn types(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {
+ pub fn types(&'a self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> + 'a {
self.iter().filter_map(|k| {
if let UnpackedKind::Type(ty) = k.unpack() {
Some(ty)
}
#[inline]
- pub fn regions(&'a self) -> impl DoubleEndedIterator<Item=ty::Region<'tcx>> + 'a {
+ pub fn regions(&'a self) -> impl DoubleEndedIterator<Item = ty::Region<'tcx>> + 'a {
self.iter().filter_map(|k| {
if let UnpackedKind::Lifetime(lt) = k.unpack() {
Some(lt)
// `foo`. Or use `foo.subst_spanned(tcx, substs, Some(span))` when
// there is more information available (for better errors).
-pub trait Subst<'tcx> : Sized {
+pub trait Subst<'tcx>: Sized {
fn subst<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
substs: &[Kind<'tcx>]) -> Self {
self.subst_spanned(tcx, substs, None)
[dependencies]
bitflags = "1.0"
rustc_cratesio_shim = { path = "../librustc_cratesio_shim" }
+smallvec = { version = "0.6.5", features = ["union"] }
use {Category, ExpInt, IEK_INF, IEK_NAN, IEK_ZERO};
use {Float, FloatConvert, ParseError, Round, Status, StatusAnd};
+use smallvec::{SmallVec, smallvec};
use std::cmp::{self, Ordering};
use std::convert::TryFrom;
use std::fmt::{self, Write};
// to hold the full significand, and an extra limb required by
// tcMultiplyPart.
let max_limbs = limbs_for_bits(1 + 196 * significand_digits / 59);
- let mut dec_sig = Vec::with_capacity(max_limbs);
+ let mut dec_sig: SmallVec<[Limb; 1]> = SmallVec::with_capacity(max_limbs);
// Convert to binary efficiently - we do almost all multiplication
// in a Limb. When this would overflow do we do a single
const FIRST_EIGHT_POWERS: [Limb; 8] = [1, 5, 25, 125, 625, 3125, 15625, 78125];
- let mut p5_scratch = vec![];
- let mut p5 = vec![FIRST_EIGHT_POWERS[4]];
+ let mut p5_scratch = smallvec![];
+ let mut p5: SmallVec<[Limb; 1]> = smallvec![FIRST_EIGHT_POWERS[4]];
- let mut r_scratch = vec![];
- let mut r = vec![FIRST_EIGHT_POWERS[power & 7]];
+ let mut r_scratch = smallvec![];
+ let mut r: SmallVec<[Limb; 1]> = smallvec![FIRST_EIGHT_POWERS[power & 7]];
power >>= 3;
while power > 0 {
let calc_precision = (LIMB_BITS << attempt) - 1;
attempt += 1;
- let calc_normal_from_limbs = |sig: &mut Vec<Limb>,
+ let calc_normal_from_limbs = |sig: &mut SmallVec<[Limb; 1]>,
limbs: &[Limb]|
-> StatusAnd<ExpInt> {
sig.resize(limbs_for_bits(calc_precision), 0);
#[macro_use]
extern crate bitflags;
+extern crate smallvec;
use std::cmp::Ordering;
use std::fmt;
[dependencies]
alloc = { path = "../liballoc" }
-alloc_system = { path = "../liballoc_system" }
core = { path = "../libcore" }
compiler_builtins = { path = "../rustc/compiler_builtins_shim" }
// except according to those terms.
#![sanitizer_runtime]
-#![feature(alloc_system)]
#![feature(nll)]
#![feature(sanitizer_runtime)]
#![feature(staged_api)]
#![unstable(feature = "sanitizer_runtime_lib",
reason = "internal implementation detail of sanitizers",
issue = "0")]
-
-extern crate alloc_system;
-
-use alloc_system::System;
-
-#[global_allocator]
-static ALLOC: System = System;
use type_of::{LayoutLlvmExt, PointerKind};
use value::Value;
-use rustc_target::abi::{LayoutOf, Size, TyLayout, Abi as LayoutAbi};
+use rustc_target::abi::{HasDataLayout, LayoutOf, Size, TyLayout, Abi as LayoutAbi};
use rustc::ty::{self, Ty};
use rustc::ty::layout;
// ...and then memcpy it to the intended destination.
base::call_memcpy(bx,
bx.pointercast(dst.llval, Type::i8p(cx)),
+ self.layout.align,
bx.pointercast(llscratch, Type::i8p(cx)),
+ scratch_align,
C_usize(cx, self.layout.size.bytes()),
- self.layout.align.min(scratch_align),
MemFlags::empty());
bx.lifetime_end(llscratch, scratch_size);
cx: &CodegenCx<'ll, 'tcx>,
abi: Abi);
fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
+ fn ptr_to_llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
fn llvm_cconv(&self) -> llvm::CallConv;
fn apply_attrs_llfn(&self, llfn: &'ll Value);
fn apply_attrs_callsite(&self, bx: &Builder<'a, 'll, 'tcx>, callsite: &'ll Value);
}
}
+ fn ptr_to_llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type {
+ unsafe {
+ llvm::LLVMPointerType(self.llvm_type(cx),
+ cx.data_layout().instruction_address_space as c_uint)
+ }
+ }
+
fn llvm_cconv(&self) -> llvm::CallConv {
match self.conv {
Conv::C => llvm::CCallConv,
if self.src_archive().is_none() {
return Vec::new()
}
+
let archive = self.src_archive.as_ref().unwrap().as_ref().unwrap();
- let ret = archive.iter()
- .filter_map(|child| child.ok())
- .filter(is_relevant_child)
- .filter_map(|child| child.name())
- .filter(|name| !self.removals.iter().any(|x| x == name))
- .map(|name| name.to_string())
- .collect();
- return ret;
+
+ archive.iter()
+ .filter_map(|child| child.ok())
+ .filter(is_relevant_child)
+ .filter_map(|child| child.name())
+ .filter(|name| !self.removals.iter().any(|x| x == name))
+ .map(|name| name.to_owned())
+ .collect()
}
fn src_archive(&mut self) -> Option<&ArchiveRO> {
let name = file.file_name().unwrap().to_str().unwrap();
self.additions.push(Addition::File {
path: file.to_path_buf(),
- name_in_archive: name.to_string(),
+ name_in_archive: name.to_owned(),
});
}
/// Combine the provided files, rlibs, and native libraries into a single
/// `Archive`.
pub fn build(&mut self) {
- let kind = match self.llvm_archive_kind() {
- Ok(kind) => kind,
- Err(kind) => {
- self.config.sess.fatal(&format!("Don't know how to build archive of type: {}",
- kind));
- }
- };
+ let kind = self.llvm_archive_kind().unwrap_or_else(|kind|
+ self.config.sess.fatal(&format!("Don't know how to build archive of type: {}", kind)));
if let Err(e) = self.build_with_llvm(kind) {
self.config.sess.fatal(&format!("failed to build archive: {}", e));
let ret = if r.into_result().is_err() {
let err = llvm::LLVMRustGetLastError();
let msg = if err.is_null() {
- "failed to write archive".to_string()
+ "failed to write archive".into()
} else {
String::from_utf8_lossy(CStr::from_ptr(err).to_bytes())
- .into_owned()
};
Err(io::Error::new(io::ErrorKind::Other, msg))
} else {
for member in members {
llvm::LLVMRustArchiveMemberFree(member);
}
- return ret
+ ret
}
}
}
// This is the "magic number" expected at the beginning of a LLVM bytecode
// object in an rlib.
-pub const RLIB_BYTECODE_OBJECT_MAGIC: &'static [u8] = b"RUST_OBJECT";
+pub const RLIB_BYTECODE_OBJECT_MAGIC: &[u8] = b"RUST_OBJECT";
// The version number this compiler will write to bytecode objects in rlibs
pub const RLIB_BYTECODE_OBJECT_VERSION: u8 = 2;
}
impl<'a> DecodedBytecode<'a> {
- pub fn new(data: &'a [u8]) -> Result<DecodedBytecode<'a>, String> {
+ pub fn new(data: &'a [u8]) -> Result<DecodedBytecode<'a>, &'static str> {
if !data.starts_with(RLIB_BYTECODE_OBJECT_MAGIC) {
- return Err("magic bytecode prefix not found".to_string())
+ return Err("magic bytecode prefix not found")
}
let data = &data[RLIB_BYTECODE_OBJECT_MAGIC.len()..];
if !data.starts_with(&[RLIB_BYTECODE_OBJECT_VERSION, 0, 0, 0]) {
- return Err("wrong version prefix found in bytecode".to_string())
+ return Err("wrong version prefix found in bytecode")
}
let data = &data[4..];
if data.len() < 4 {
- return Err("bytecode corrupted".to_string())
+ return Err("bytecode corrupted")
}
let identifier_len = unsafe {
u32::from_le(ptr::read_unaligned(data.as_ptr() as *const u32)) as usize
};
let data = &data[4..];
if data.len() < identifier_len {
- return Err("bytecode corrupted".to_string())
+ return Err("bytecode corrupted")
}
let identifier = match str::from_utf8(&data[..identifier_len]) {
Ok(s) => s,
- Err(_) => return Err("bytecode corrupted".to_string())
+ Err(_) => return Err("bytecode corrupted")
};
let data = &data[identifier_len..];
if data.len() < 8 {
- return Err("bytecode corrupted".to_string())
+ return Err("bytecode corrupted")
}
let bytecode_len = unsafe {
u64::from_le(ptr::read_unaligned(data.as_ptr() as *const u64)) as usize
};
let data = &data[8..];
if data.len() < bytecode_len {
- return Err("bytecode corrupted".to_string())
+ return Err("bytecode corrupted")
}
let encoded_bytecode = &data[..bytecode_len];
use syntax::attr;
pub use rustc_codegen_utils::link::{find_crate_name, filename_for_input, default_output_for_target,
- invalid_output_for_target, out_filename, check_file_is_writeable,
- filename_for_metadata};
+ invalid_output_for_target, filename_for_metadata,
+ out_filename, check_file_is_writeable};
// The third parameter is for env vars, used on windows to set up the
// path for MSVC to find its DLLs, and gcc to find its bundled
}
pub fn remove(sess: &Session, path: &Path) {
- match fs::remove_file(path) {
- Ok(..) => {}
- Err(e) => {
- sess.err(&format!("failed to remove {}: {}",
- path.display(),
- e));
- }
+ if let Err(e) = fs::remove_file(path) {
+ sess.err(&format!("failed to remove {}: {}",
+ path.display(),
+ e));
}
}
// Remove the temporary object file and metadata if we aren't saving temps
if !sess.opts.cg.save_temps {
- if sess.opts.output_types.should_codegen() &&
- !preserve_objects_for_their_debuginfo(sess)
- {
+ if sess.opts.output_types.should_codegen() && !preserve_objects_for_their_debuginfo(sess) {
for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) {
remove(sess, obj);
}
// the objects as they're losslessly contained inside the archives.
let output_linked = sess.crate_types.borrow()
.iter()
- .any(|x| *x != config::CrateType::Rlib && *x != config::CrateType::Staticlib);
+ .any(|&x| x != config::CrateType::Rlib && x != config::CrateType::Staticlib);
if !output_linked {
return false
}
// crates providing these functions don't participate in LTO (e.g.
// no_builtins or compiler builtins crates).
!sess.target.target.options.no_builtins &&
- (info.is_no_builtins.contains(&cnum) || info.compiler_builtins == Some(cnum))
+ (info.compiler_builtins == Some(cnum) || info.is_no_builtins.contains(&cnum))
}
fn link_binary_output(sess: &Session,
// final destination, with a `fs::rename` call. In order for the rename to
// always succeed, the temporary file needs to be on the same filesystem,
// which is why we create it inside the output directory specifically.
- let metadata_tmpdir = match TempFileBuilder::new()
+ let metadata_tmpdir = TempFileBuilder::new()
.prefix("rmeta")
.tempdir_in(out_filename.parent().unwrap())
- {
- Ok(tmpdir) => tmpdir,
- Err(err) => sess.fatal(&format!("couldn't create a temp dir: {}", err)),
- };
+ .unwrap_or_else(|err| sess.fatal(&format!("couldn't create a temp dir: {}", err)));
let metadata = emit_metadata(sess, codegen_results, &metadata_tmpdir);
if let Err(e) = fs::rename(metadata, &out_filename) {
sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));
out_filenames.push(out_filename);
}
- let tmpdir = match TempFileBuilder::new().prefix("rustc").tempdir() {
- Ok(tmpdir) => tmpdir,
- Err(err) => sess.fatal(&format!("couldn't create a temp dir: {}", err)),
- };
+ let tmpdir = TempFileBuilder::new().prefix("rustc").tempdir().unwrap_or_else(|err|
+ sess.fatal(&format!("couldn't create a temp dir: {}", err)));
if outputs.outputs.should_codegen() {
let out_filename = out_filename(sess, crate_type, outputs, crate_name);
sess.target_filesearch(PathKind::Native).for_each_lib_search_path(|path, _| {
search.push(path.to_path_buf());
});
- return search;
+
+ search
}
fn archive_config<'a>(sess: &'a Session,
.unwrap_or_else(|_| {
let mut x = "Non-UTF-8 output: ".to_string();
x.extend(s.iter()
- .flat_map(|&b| ascii::escape_default(b))
- .map(|b| char::from_u32(b as u32).unwrap()));
+ .flat_map(|&b| ascii::escape_default(b))
+ .map(char::from));
x
})
}
sess.opts.debuginfo != DebugInfo::None &&
!preserve_objects_for_their_debuginfo(sess)
{
- match Command::new("dsymutil").arg(out_filename).output() {
- Ok(..) => {}
- Err(e) => sess.fatal(&format!("failed to run dsymutil: {}", e)),
+ if let Err(e) = Command::new("dsymutil").arg(out_filename).output() {
+ sess.fatal(&format!("failed to run dsymutil: {}", e))
}
}
// ensure the line is interpreted as one whole argument.
for c in self.arg.chars() {
match c {
- '\\' |
- ' ' => write!(f, "\\{}", c)?,
+ '\\' | ' ' => write!(f, "\\{}", c)?,
c => write!(f, "{}", c)?,
}
}
for f in archive.src_files() {
if f.ends_with(RLIB_BYTECODE_EXTENSION) || f == METADATA_FILENAME {
archive.remove_file(&f);
- continue
}
}
Lto::Fat => {
assert!(cached_modules.is_empty());
let opt_jobs = fat_lto(cgcx,
- &diag_handler,
- modules,
- upstream_modules,
- &symbol_white_list,
- timeline);
+ &diag_handler,
+ modules,
+ upstream_modules,
+ &symbol_white_list,
+ timeline);
opt_jobs.map(|opt_jobs| (opt_jobs, vec![]))
}
Lto::Thin |
let data = bc_decoded.data();
linker.add(&data).map_err(|()| {
let msg = format!("failed to load bc of {:?}", name);
- write::llvm_err(&diag_handler, msg)
+ write::llvm_err(&diag_handler, &msg)
})
})?;
timeline.record(&format!("link {:?}", name));
unsafe {
let ptr = symbol_white_list.as_ptr();
llvm::LLVMRustRunRestrictionPass(llmod,
- ptr as *const *const libc::c_char,
- symbol_white_list.len() as libc::size_t);
+ ptr as *const *const libc::c_char,
+ symbol_white_list.len() as libc::size_t);
cgcx.save_temp_bitcode(&module, "lto.after-restriction");
}
symbol_white_list.as_ptr(),
symbol_white_list.len() as u32,
).ok_or_else(|| {
- write::llvm_err(&diag_handler, "failed to prepare thin LTO context".to_string())
+ write::llvm_err(&diag_handler, "failed to prepare thin LTO context")
})?;
info!("thin LTO data created");
};
with_llvm_pmb(llmod, config, opt_level, false, &mut |b| {
if thin {
- if !llvm::LLVMRustPassManagerBuilderPopulateThinLTOPassManager(b, pm) {
- panic!("this version of LLVM does not support ThinLTO");
- }
+ llvm::LLVMRustPassManagerBuilderPopulateThinLTOPassManager(b, pm);
} else {
llvm::LLVMPassManagerBuilderPopulateLTOPassManager(b, pm,
/* Internalize = */ False,
llvm::LLVMRustAddPass(pm, pass.unwrap());
}
- time_ext(cgcx.time_passes, None, "LTO passes", ||
- llvm::LLVMRunPassManager(pm, llmod));
+ time_ext(cgcx.time_passes, None, "LTO passes", || llvm::LLVMRunPassManager(pm, llmod));
llvm::LLVMDisposePassManager(pm);
}
{
let diag_handler = cgcx.create_diag_handler();
let tm = (cgcx.tm_factory)().map_err(|e| {
- write::llvm_err(&diag_handler, e)
+ write::llvm_err(&diag_handler, &e)
})?;
// Right now the implementation we've got only works over serialized
self.data().len(),
self.shared.module_names[self.idx].as_ptr(),
).ok_or_else(|| {
- let msg = "failed to parse bitcode for thin LTO module".to_string();
+ let msg = "failed to parse bitcode for thin LTO module";
write::llvm_err(&diag_handler, msg)
})? as *const _;
let module = ModuleCodegen {
let mut cu2 = ptr::null_mut();
llvm::LLVMRustThinLTOGetDICompileUnit(llmod, &mut cu1, &mut cu2);
if !cu2.is_null() {
- let msg = "multiple source DICompileUnits found".to_string();
+ let msg = "multiple source DICompileUnits found";
return Err(write::llvm_err(&diag_handler, msg))
}
// You can find some more comments about these functions in the LLVM
// bindings we've got (currently `PassWrapper.cpp`)
if !llvm::LLVMRustPrepareThinLTORename(self.shared.data.0, llmod) {
- let msg = "failed to prepare thin LTO module".to_string();
+ let msg = "failed to prepare thin LTO module";
return Err(write::llvm_err(&diag_handler, msg))
}
cgcx.save_temp_bitcode(&module, "thin-lto-after-rename");
timeline.record("rename");
if !llvm::LLVMRustPrepareThinLTOResolveWeak(self.shared.data.0, llmod) {
- let msg = "failed to prepare thin LTO module".to_string();
+ let msg = "failed to prepare thin LTO module";
return Err(write::llvm_err(&diag_handler, msg))
}
cgcx.save_temp_bitcode(&module, "thin-lto-after-resolve");
timeline.record("resolve");
if !llvm::LLVMRustPrepareThinLTOInternalize(self.shared.data.0, llmod) {
- let msg = "failed to prepare thin LTO module".to_string();
+ let msg = "failed to prepare thin LTO module";
return Err(write::llvm_err(&diag_handler, msg))
}
cgcx.save_temp_bitcode(&module, "thin-lto-after-internalize");
timeline.record("internalize");
if !llvm::LLVMRustPrepareThinLTOImport(self.shared.data.0, llmod) {
- let msg = "failed to prepare thin LTO module".to_string();
+ let msg = "failed to prepare thin LTO module";
return Err(write::llvm_err(&diag_handler, msg))
}
cgcx.save_temp_bitcode(&module, "thin-lto-after-import");
}
fn module_name_to_str(c_str: &CStr) -> &str {
- match c_str.to_str() {
- Ok(s) => s,
- Err(e) => {
- bug!("Encountered non-utf8 LLVM module name `{}`: {}",
- c_str.to_string_lossy(),
- e)
- }
- }
+ c_str.to_str().unwrap_or_else(|e|
+ bug!("Encountered non-utf8 LLVM module name `{}`: {}", c_str.to_string_lossy(), e))
}
// Use DT_RUNPATH instead of DT_RPATH if available
if config.linker_is_gnu {
- flags.push("-Wl,--enable-new-dtags".to_string());
+ flags.push("-Wl,--enable-new-dtags".to_owned());
}
flags
ret.push(format!("-Wl,-rpath,{}", &(*rpath)));
}
}
- return ret;
+
+ ret
}
fn get_rpaths(config: &mut RPathConfig, libs: &[PathBuf]) -> Vec<String> {
// Remove duplicates
let rpaths = minimize_rpaths(&rpaths);
- return rpaths;
+
+ rpaths
}
fn get_rpaths_relative_to_output(config: &mut RPathConfig,
let relative = path_relative_from(&lib, &output).unwrap_or_else(||
panic!("couldn't create relative path from {:?} to {:?}", output, lib));
// FIXME (#9639): This needs to handle non-utf8 paths
- format!("{}/{}", prefix,
- relative.to_str().expect("non-utf8 component in path"))
+ format!("{}/{}", prefix, relative.to_str().expect("non-utf8 component in path"))
}
// This routine is adapted from the *old* Path's `path_relative_from`
let path = (config.get_install_prefix_lib_path)();
let path = env::current_dir().unwrap().join(&path);
// FIXME (#9639): This needs to handle non-utf8 paths
- path.to_str().expect("non-utf8 component in rpath").to_string()
+ path.to_str().expect("non-utf8 component in rpath").to_owned()
}
fn minimize_rpaths(rpaths: &[String]) -> Vec<String> {
/// https://github.com/llvm-mirror/llvm/commit/0f32e1365, although support still
/// needs to be added, tracked at https://bugs.llvm.org/show_bug.cgi?id=37168
pub fn rewrite_imports(path: &Path, import_map: &FxHashMap<String, String>) {
- if import_map.len() == 0 {
+ if import_map.is_empty() {
return
}
type Item = (u8, &'a [u8]);
fn next(&mut self) -> Option<(u8, &'a [u8])> {
- if self.0.data.len() == 0 {
+ if self.0.data.is_empty() {
return None
}
use std::thread;
use libc::{c_uint, c_void, c_char, size_t};
-pub const RELOC_MODEL_ARGS : [(&'static str, llvm::RelocMode); 7] = [
+pub const RELOC_MODEL_ARGS : [(&str, llvm::RelocMode); 7] = [
("pic", llvm::RelocMode::PIC),
("static", llvm::RelocMode::Static),
("default", llvm::RelocMode::Default),
("large", llvm::CodeModel::Large),
];
-pub const TLS_MODEL_ARGS : [(&'static str, llvm::ThreadLocalMode); 4] = [
+pub const TLS_MODEL_ARGS : [(&str, llvm::ThreadLocalMode); 4] = [
("global-dynamic", llvm::ThreadLocalMode::GeneralDynamic),
("local-dynamic", llvm::ThreadLocalMode::LocalDynamic),
("initial-exec", llvm::ThreadLocalMode::InitialExec),
const PRE_THIN_LTO_BC_EXT: &str = "pre-thin-lto.bc";
-pub fn llvm_err(handler: &errors::Handler, msg: String) -> FatalError {
+pub fn llvm_err(handler: &errors::Handler, msg: &str) -> FatalError {
match llvm::last_error() {
Some(err) => handler.fatal(&format!("{}: {}", msg, err)),
None => handler.fatal(&msg),
file_type: llvm::FileType) -> Result<(), FatalError> {
unsafe {
let output_c = path2cstr(output);
- let result = llvm::LLVMRustWriteOutputFile(
- target, pm, m, output_c.as_ptr(), file_type);
+ let result = llvm::LLVMRustWriteOutputFile(target, pm, m, output_c.as_ptr(), file_type);
if result.into_result().is_err() {
let msg = format!("could not write output to {}", output.display());
- Err(llvm_err(handler, msg))
+ Err(llvm_err(handler, &msg))
} else {
Ok(())
}
find_features: bool,
) -> &'static mut llvm::TargetMachine {
target_machine_factory(sess, find_features)().unwrap_or_else(|err| {
- llvm_err(sess.diagnostic(), err).raise()
+ llvm_err(sess.diagnostic(), &err).raise()
})
}
unsafe extern "C" fn report_inline_asm<'a, 'b>(cgcx: &'a CodegenContext,
msg: &'b str,
cookie: c_uint) {
- cgcx.diag_emitter.inline_asm_error(cookie as u32, msg.to_string());
+ cgcx.diag_emitter.inline_asm_error(cookie as u32, msg.to_owned());
}
unsafe extern "C" fn inline_asm_handler(diag: &SMDiagnostic,
for pass in &config.passes {
if !addpass(pass) {
- diag_handler.warn(&format!("unknown pass `{}`, ignoring",
- pass));
+ diag_handler.warn(&format!("unknown pass `{}`, ignoring", pass));
}
if pass == "name-anon-globals" {
have_name_anon_globals_pass = true;
for pass in &cgcx.plugin_passes {
if !addpass(pass) {
diag_handler.err(&format!("a plugin asked for LLVM pass \
- `{}` but LLVM does not \
- recognize it", pass));
+ `{}` but LLVM does not \
+ recognize it", pass));
}
if pass == "name-anon-globals" {
have_name_anon_globals_pass = true;
// As described above, this will probably cause an error in LLVM
if config.no_prepopulate_passes {
diag_handler.err("The current compilation is going to use thin LTO buffers \
- without running LLVM's NameAnonGlobals pass. \
- This will likely cause errors in LLVM. Consider adding \
- -C passes=name-anon-globals to the compiler command line.");
+ without running LLVM's NameAnonGlobals pass. \
+ This will likely cause errors in LLVM. Consider adding \
+ -C passes=name-anon-globals to the compiler command line.");
} else {
bug!("We are using thin LTO buffers without running the NameAnonGlobals pass. \
- This will likely cause errors in LLVM and should never happen.");
+ This will likely cause errors in LLVM and should never happen.");
}
}
}
// escape the closure itself, and the manager should only be
// used once.
unsafe fn with_codegen<'ll, F, R>(tm: &'ll llvm::TargetMachine,
- llmod: &'ll llvm::Module,
- no_builtins: bool,
- f: F) -> R
+ llmod: &'ll llvm::Module,
+ no_builtins: bool,
+ f: F) -> R
where F: FnOnce(&'ll mut PassManager<'ll>) -> R,
{
let cpm = llvm::LLVMCreatePassManager();
};
with_codegen(tm, llmod, config.no_builtins, |cpm| {
write_output_file(diag_handler, tm, cpm, llmod, &path,
- llvm::FileType::AssemblyFile)
+ llvm::FileType::AssemblyFile)
})?;
timeline.record("asm");
}
if write_obj {
with_codegen(tm, llmod, config.no_builtins, |cpm| {
write_output_file(diag_handler, tm, cpm, llmod, &obj_out,
- llvm::FileType::ObjectFile)
+ llvm::FileType::ObjectFile)
})?;
timeline.record("obj");
} else if asm_to_obj {
}
pub fn start_async_codegen(tcx: TyCtxt,
- time_graph: Option<TimeGraph>,
- metadata: EncodedMetadata,
- coordinator_receive: Receiver<Box<dyn Any + Send>>,
- total_cgus: usize)
- -> OngoingCodegen {
+ time_graph: Option<TimeGraph>,
+ metadata: EncodedMetadata,
+ coordinator_receive: Receiver<Box<dyn Any + Send>>,
+ total_cgus: usize)
+ -> OngoingCodegen {
let sess = tcx.sess;
let crate_name = tcx.crate_name(LOCAL_CRATE);
let crate_hash = tcx.crate_hash(LOCAL_CRATE);
}
if let Some((id, product)) =
- copy_cgu_workproducts_to_incr_comp_cache_dir(sess, &module.name, &files) {
+ copy_cgu_workproducts_to_incr_comp_cache_dir(sess, &module.name, &files)
+ {
work_products.insert(id, product);
}
}
module.name,
source_file,
obj_out.display());
- match link_or_copy(&source_file, &obj_out) {
- Ok(_) => { }
- Err(err) => {
- let diag_handler = cgcx.create_diag_handler();
- diag_handler.err(&format!("unable to copy {} to {}: {}",
- source_file.display(),
- obj_out.display(),
- err));
- }
+ if let Err(err) = link_or_copy(&source_file, &obj_out) {
+ let diag_handler = cgcx.create_diag_handler();
+ diag_handler.err(&format!("unable to copy {} to {}: {}",
+ source_file.display(),
+ obj_out.display(),
+ err));
}
}
let (name, mut cmd) = get_linker(sess, &linker, flavor);
cmd.args(&sess.target.target.options.asm_args);
- Some(Arc::new(AssemblerCommand {
- name,
- cmd,
- }))
+
+ Some(Arc::new(AssemblerCommand { name, cmd }))
} else {
None
};
handler.struct_err(&format!("linking with `{}` failed: {}",
pname.display(),
prog.status))
- .note(&format!("{:?}", &cmd))
- .note(str::from_utf8(¬e[..]).unwrap())
- .emit();
+ .note(&format!("{:?}", &cmd))
+ .note(str::from_utf8(¬e[..]).unwrap())
+ .emit();
handler.abort_if_errors();
}
},
}
pub(crate) fn submit_pre_codegened_module_to_llvm(&self,
- tcx: TyCtxt,
- module: ModuleCodegen) {
+ tcx: TyCtxt,
+ module: ModuleCodegen) {
self.wait_for_signal_to_codegen_item();
self.check_for_errors(tcx.sess);
use attributes;
use builder::{Builder, MemFlags};
use callee;
-use common::{C_bool, C_bytes_in_context, C_i32, C_usize};
+use common::{C_bool, C_bytes_in_context, C_usize};
use rustc_mir::monomorphize::item::DefPathBasedNames;
use common::{C_struct_in_context, C_array, val_ty};
use consts;
use std::any::Any;
use std::cmp;
use std::ffi::CString;
-use std::i32;
use std::ops::{Deref, DerefMut};
use std::sync::mpsc;
use std::time::{Instant, Duration};
}
if src_f.layout.ty == dst_f.layout.ty {
- memcpy_ty(bx, dst_f.llval, src_f.llval, src_f.layout,
- src_f.align.min(dst_f.align), MemFlags::empty());
+ memcpy_ty(bx, dst_f.llval, dst_f.align, src_f.llval, src_f.align,
+ src_f.layout, MemFlags::empty());
} else {
coerce_unsized_into(bx, src_f, dst_f);
}
pub fn call_memcpy(
bx: &Builder<'_, 'll, '_>,
dst: &'ll Value,
+ dst_align: Align,
src: &'ll Value,
+ src_align: Align,
n_bytes: &'ll Value,
- align: Align,
flags: MemFlags,
) {
if flags.contains(MemFlags::NONTEMPORAL) {
// HACK(nox): This is inefficient but there is no nontemporal memcpy.
- let val = bx.load(src, align);
+ let val = bx.load(src, src_align);
let ptr = bx.pointercast(dst, val_ty(val).ptr_to());
- bx.store_with_flags(val, ptr, align, flags);
+ bx.store_with_flags(val, ptr, dst_align, flags);
return;
}
let cx = bx.cx;
- let ptr_width = &cx.sess().target.target.target_pointer_width;
- let key = format!("llvm.memcpy.p0i8.p0i8.i{}", ptr_width);
- let memcpy = cx.get_intrinsic(&key);
let src_ptr = bx.pointercast(src, Type::i8p(cx));
let dst_ptr = bx.pointercast(dst, Type::i8p(cx));
let size = bx.intcast(n_bytes, cx.isize_ty, false);
- let align = C_i32(cx, align.abi() as i32);
- let volatile = C_bool(cx, flags.contains(MemFlags::VOLATILE));
- bx.call(memcpy, &[dst_ptr, src_ptr, size, align, volatile], None);
+ let volatile = flags.contains(MemFlags::VOLATILE);
+ bx.memcpy(dst_ptr, dst_align.abi(), src_ptr, src_align.abi(), size, volatile);
}
pub fn memcpy_ty(
bx: &Builder<'_, 'll, 'tcx>,
dst: &'ll Value,
+ dst_align: Align,
src: &'ll Value,
+ src_align: Align,
layout: TyLayout<'tcx>,
- align: Align,
flags: MemFlags,
) {
let size = layout.size.bytes();
return;
}
- call_memcpy(bx, dst, src, C_usize(bx.cx, size), align, flags);
+ call_memcpy(bx, dst, dst_align, src, src_align, C_usize(bx.cx, size), flags);
}
pub fn call_memset(
}
}
+ pub fn memcpy(&self, dst: &'ll Value, dst_align: u64,
+ src: &'ll Value, src_align: u64,
+ size: &'ll Value, is_volatile: bool) -> &'ll Value {
+ unsafe {
+ llvm::LLVMRustBuildMemCpy(self.llbuilder, dst, dst_align as c_uint,
+ src, src_align as c_uint, size, is_volatile)
+ }
+ }
+
+ pub fn memmove(&self, dst: &'ll Value, dst_align: u64,
+ src: &'ll Value, src_align: u64,
+ size: &'ll Value, is_volatile: bool) -> &'ll Value {
+ unsafe {
+ llvm::LLVMRustBuildMemMove(self.llbuilder, dst, dst_align as c_uint,
+ src, src_align as c_uint, size, is_volatile)
+ }
+ }
+
pub fn minnum(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
self.count_insn("minnum");
unsafe {
// FIXME: add a non-fast math version once
// https://bugs.llvm.org/show_bug.cgi?id=36732
// is fixed.
- let instr = llvm::LLVMRustBuildVectorReduceFAdd(self.llbuilder, acc, src)
- .expect("LLVMRustBuildVectorReduceFAdd is not available in LLVM version < 5.0");
+ let instr = llvm::LLVMRustBuildVectorReduceFAdd(self.llbuilder, acc, src);
llvm::LLVMRustSetHasUnsafeAlgebra(instr);
instr
}
// FIXME: add a non-fast math version once
// https://bugs.llvm.org/show_bug.cgi?id=36732
// is fixed.
- let instr = llvm::LLVMRustBuildVectorReduceFMul(self.llbuilder, acc, src)
- .expect("LLVMRustBuildVectorReduceFMul is not available in LLVM version < 5.0");
+ let instr = llvm::LLVMRustBuildVectorReduceFMul(self.llbuilder, acc, src);
llvm::LLVMRustSetHasUnsafeAlgebra(instr);
instr
}
}
pub fn vector_reduce_add(&self, src: &'ll Value) -> &'ll Value {
self.count_insn("vector.reduce.add");
- unsafe {
- let instr = llvm::LLVMRustBuildVectorReduceAdd(self.llbuilder, src);
- instr.expect("LLVMRustBuildVectorReduceAdd is not available in LLVM version < 5.0")
- }
+ unsafe { llvm::LLVMRustBuildVectorReduceAdd(self.llbuilder, src) }
}
pub fn vector_reduce_mul(&self, src: &'ll Value) -> &'ll Value {
self.count_insn("vector.reduce.mul");
- unsafe {
- let instr = llvm::LLVMRustBuildVectorReduceMul(self.llbuilder, src);
- instr.expect("LLVMRustBuildVectorReduceMul is not available in LLVM version < 5.0")
- }
+ unsafe { llvm::LLVMRustBuildVectorReduceMul(self.llbuilder, src) }
}
pub fn vector_reduce_and(&self, src: &'ll Value) -> &'ll Value {
self.count_insn("vector.reduce.and");
- unsafe {
- let instr = llvm::LLVMRustBuildVectorReduceAnd(self.llbuilder, src);
- instr.expect("LLVMRustBuildVectorReduceAnd is not available in LLVM version < 5.0")
- }
+ unsafe { llvm::LLVMRustBuildVectorReduceAnd(self.llbuilder, src) }
}
pub fn vector_reduce_or(&self, src: &'ll Value) -> &'ll Value {
self.count_insn("vector.reduce.or");
- unsafe {
- let instr = llvm::LLVMRustBuildVectorReduceOr(self.llbuilder, src);
- instr.expect("LLVMRustBuildVectorReduceOr is not available in LLVM version < 5.0")
- }
+ unsafe { llvm::LLVMRustBuildVectorReduceOr(self.llbuilder, src) }
}
pub fn vector_reduce_xor(&self, src: &'ll Value) -> &'ll Value {
self.count_insn("vector.reduce.xor");
- unsafe {
- let instr = llvm::LLVMRustBuildVectorReduceXor(self.llbuilder, src);
- instr.expect("LLVMRustBuildVectorReduceXor is not available in LLVM version < 5.0")
- }
+ unsafe { llvm::LLVMRustBuildVectorReduceXor(self.llbuilder, src) }
}
pub fn vector_reduce_fmin(&self, src: &'ll Value) -> &'ll Value {
self.count_insn("vector.reduce.fmin");
- unsafe {
- let instr = llvm::LLVMRustBuildVectorReduceFMin(self.llbuilder, src, /*NoNaNs:*/ false);
- instr.expect("LLVMRustBuildVectorReduceFMin is not available in LLVM version < 5.0")
- }
+ unsafe { llvm::LLVMRustBuildVectorReduceFMin(self.llbuilder, src, /*NoNaNs:*/ false) }
}
pub fn vector_reduce_fmax(&self, src: &'ll Value) -> &'ll Value {
self.count_insn("vector.reduce.fmax");
- unsafe {
- let instr = llvm::LLVMRustBuildVectorReduceFMax(self.llbuilder, src, /*NoNaNs:*/ false);
- instr.expect("LLVMRustBuildVectorReduceFMax is not available in LLVM version < 5.0")
- }
+ unsafe { llvm::LLVMRustBuildVectorReduceFMax(self.llbuilder, src, /*NoNaNs:*/ false) }
}
pub fn vector_reduce_fmin_fast(&self, src: &'ll Value) -> &'ll Value {
self.count_insn("vector.reduce.fmin_fast");
unsafe {
- let instr = llvm::LLVMRustBuildVectorReduceFMin(self.llbuilder, src, /*NoNaNs:*/ true)
- .expect("LLVMRustBuildVectorReduceFMin is not available in LLVM version < 5.0");
+ let instr = llvm::LLVMRustBuildVectorReduceFMin(self.llbuilder, src, /*NoNaNs:*/ true);
llvm::LLVMRustSetHasUnsafeAlgebra(instr);
instr
}
pub fn vector_reduce_fmax_fast(&self, src: &'ll Value) -> &'ll Value {
self.count_insn("vector.reduce.fmax_fast");
unsafe {
- let instr = llvm::LLVMRustBuildVectorReduceFMax(self.llbuilder, src, /*NoNaNs:*/ true)
- .expect("LLVMRustBuildVectorReduceFMax is not available in LLVM version < 5.0");
+ let instr = llvm::LLVMRustBuildVectorReduceFMax(self.llbuilder, src, /*NoNaNs:*/ true);
llvm::LLVMRustSetHasUnsafeAlgebra(instr);
instr
}
}
pub fn vector_reduce_min(&self, src: &'ll Value, is_signed: bool) -> &'ll Value {
self.count_insn("vector.reduce.min");
- unsafe {
- let instr = llvm::LLVMRustBuildVectorReduceMin(self.llbuilder, src, is_signed);
- instr.expect("LLVMRustBuildVectorReduceMin is not available in LLVM version < 5.0")
- }
+ unsafe { llvm::LLVMRustBuildVectorReduceMin(self.llbuilder, src, is_signed) }
}
pub fn vector_reduce_max(&self, src: &'ll Value, is_signed: bool) -> &'ll Value {
self.count_insn("vector.reduce.max");
- unsafe {
- let instr = llvm::LLVMRustBuildVectorReduceMax(self.llbuilder, src, is_signed);
- instr.expect("LLVMRustBuildVectorReduceMax is not available in LLVM version < 5.0")
- }
+ unsafe { llvm::LLVMRustBuildVectorReduceMax(self.llbuilder, src, is_signed) }
}
pub fn extract_value(&self, agg_val: &'ll Value, idx: u64) -> &'ll Value {
let t_v4f64 = Type::vector(t_f64, 4);
let t_v8f64 = Type::vector(t_f64, 8);
- ifn!("llvm.memcpy.p0i8.p0i8.i16", fn(i8p, i8p, t_i16, t_i32, i1) -> void);
- ifn!("llvm.memcpy.p0i8.p0i8.i32", fn(i8p, i8p, t_i32, t_i32, i1) -> void);
- ifn!("llvm.memcpy.p0i8.p0i8.i64", fn(i8p, i8p, t_i64, t_i32, i1) -> void);
- ifn!("llvm.memmove.p0i8.p0i8.i16", fn(i8p, i8p, t_i16, t_i32, i1) -> void);
- ifn!("llvm.memmove.p0i8.p0i8.i32", fn(i8p, i8p, t_i32, t_i32, i1) -> void);
- ifn!("llvm.memmove.p0i8.p0i8.i64", fn(i8p, i8p, t_i64, t_i32, i1) -> void);
ifn!("llvm.memset.p0i8.i16", fn(i8p, t_i8, t_i16, t_i32, i1) -> void);
ifn!("llvm.memset.p0i8.i32", fn(i8p, t_i8, t_i32, t_i32, i1) -> void);
ifn!("llvm.memset.p0i8.i64", fn(i8p, t_i8, t_i64, t_i32, i1) -> void);
ifn!("llvm.bitreverse.i64", fn(t_i64) -> t_i64);
ifn!("llvm.bitreverse.i128", fn(t_i128) -> t_i128);
+ ifn!("llvm.fshl.i8", fn(t_i8, t_i8, t_i8) -> t_i8);
+ ifn!("llvm.fshl.i16", fn(t_i16, t_i16, t_i16) -> t_i16);
+ ifn!("llvm.fshl.i32", fn(t_i32, t_i32, t_i32) -> t_i32);
+ ifn!("llvm.fshl.i64", fn(t_i64, t_i64, t_i64) -> t_i64);
+ ifn!("llvm.fshl.i128", fn(t_i128, t_i128, t_i128) -> t_i128);
+
+ ifn!("llvm.fshr.i8", fn(t_i8, t_i8, t_i8) -> t_i8);
+ ifn!("llvm.fshr.i16", fn(t_i16, t_i16, t_i16) -> t_i16);
+ ifn!("llvm.fshr.i32", fn(t_i32, t_i32, t_i32) -> t_i32);
+ ifn!("llvm.fshr.i64", fn(t_i64, t_i64, t_i64) -> t_i64);
+ ifn!("llvm.fshr.i128", fn(t_i128, t_i128, t_i128) -> t_i128);
+
ifn!("llvm.sadd.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1});
ifn!("llvm.sadd.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1});
ifn!("llvm.sadd.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1});
use llvm;
use llvm::debuginfo::{DIType, DIFile, DIScope, DIDescriptor,
DICompositeType, DILexicalBlock, DIFlags};
+use llvm_util;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc::hir::CodegenFnAttrFlags;
fn use_enum_fallback(cx: &CodegenCx) -> bool {
// On MSVC we have to use the fallback mode, because LLVM doesn't
// lower variant parts to PDB.
- return cx.sess().target.target.options.is_like_msvc || unsafe {
- llvm::LLVMRustVersionMajor() < 7
- };
+ return cx.sess().target.target.options.is_like_msvc
+ || llvm_util::get_major_version() < 7;
}
// Describes the members of an enum value: An enum is described as a union of
niche_start,
ref variants,
dataful_variant,
- ..
+ ref niche,
} => {
if fallback {
let variant = self.layout.for_variant(cx, dataful_variant);
let niche_value = if i == dataful_variant {
None
} else {
- let niche = (i as u128)
+ let value = (i as u128)
.wrapping_sub(*niche_variants.start() as u128)
.wrapping_add(niche_start);
- assert_eq!(niche as u64 as u128, niche);
- Some(niche as u64)
+ let value = value & ((1u128 << niche.value.size(cx).bits()) - 1);
+ Some(value as u64)
};
MemberDescription {
use attributes;
use intrinsics::{self, Intrinsic};
use llvm::{self, TypeKind};
+use llvm_util;
use abi::{Abi, FnType, LlvmType, PassMode};
use mir::place::PlaceRef;
use mir::operand::{OperandRef, OperandValue};
use type_::Type;
use type_of::LayoutLlvmExt;
use rustc::ty::{self, Ty};
-use rustc::ty::layout::{HasDataLayout, LayoutOf};
+use rustc::ty::layout::LayoutOf;
use rustc::hir;
use syntax::ast;
use syntax::symbol::Symbol;
"ctlz" | "ctlz_nonzero" | "cttz" | "cttz_nonzero" | "ctpop" | "bswap" |
"bitreverse" | "add_with_overflow" | "sub_with_overflow" |
"mul_with_overflow" | "overflowing_add" | "overflowing_sub" | "overflowing_mul" |
- "unchecked_div" | "unchecked_rem" | "unchecked_shl" | "unchecked_shr" | "exact_div" => {
+ "unchecked_div" | "unchecked_rem" | "unchecked_shl" | "unchecked_shr" | "exact_div" |
+ "rotate_left" | "rotate_right" => {
let ty = arg_tys[0];
match int_type_width_signed(ty, cx) {
Some((width, signed)) =>
} else {
bx.lshr(args[0].immediate(), args[1].immediate())
},
+ "rotate_left" | "rotate_right" => {
+ let is_left = name == "rotate_left";
+ let val = args[0].immediate();
+ let raw_shift = args[1].immediate();
+ if llvm_util::get_major_version() >= 7 {
+ // rotate = funnel shift with first two args the same
+ let llvm_name = &format!("llvm.fsh{}.i{}",
+ if is_left { 'l' } else { 'r' }, width);
+ let llfn = cx.get_intrinsic(llvm_name);
+ bx.call(llfn, &[val, val, raw_shift], None)
+ } else {
+ // rotate_left: (X << (S % BW)) | (X >> ((BW - S) % BW))
+ // rotate_right: (X << ((BW - S) % BW)) | (X >> (S % BW))
+ let width = C_uint(Type::ix(cx, width), width);
+ let shift = bx.urem(raw_shift, width);
+ let inv_shift = bx.urem(bx.sub(width, raw_shift), width);
+ let shift1 = bx.shl(val, if is_left { shift } else { inv_shift });
+ let shift2 = bx.lshr(val, if !is_left { shift } else { inv_shift });
+ bx.or(shift1, shift2)
+ }
+ },
_ => bug!(),
},
None => {
let cx = bx.cx;
let (size, align) = cx.size_and_align_of(ty);
let size = C_usize(cx, size.bytes());
- let align = C_i32(cx, align.abi() as i32);
-
- let operation = if allow_overlap {
- "memmove"
- } else {
- "memcpy"
- };
-
- let name = format!("llvm.{}.p0i8.p0i8.i{}", operation,
- cx.data_layout().pointer_size.bits());
-
+ let align = align.abi();
let dst_ptr = bx.pointercast(dst, Type::i8p(cx));
let src_ptr = bx.pointercast(src, Type::i8p(cx));
- let llfn = cx.get_intrinsic(&name);
-
- bx.call(llfn,
- &[dst_ptr,
- src_ptr,
- bx.mul(size, count),
- align,
- C_bool(cx, volatile)],
- None)
+ if allow_overlap {
+ bx.memmove(dst_ptr, align, src_ptr, align, bx.mul(size, count), volatile)
+ } else {
+ bx.memcpy(dst_ptr, align, src_ptr, align, bx.mul(size, count), volatile)
+ }
}
fn memset_intrinsic(
Bundle: Option<&OperandBundleDef<'a>>,
Name: *const c_char)
-> &'a Value;
+ pub fn LLVMRustBuildMemCpy(B: &Builder<'a>,
+ Dst: &'a Value,
+ DstAlign: c_uint,
+ Src: &'a Value,
+ SrcAlign: c_uint,
+ Size: &'a Value,
+ IsVolatile: bool)
+ -> &'a Value;
+ pub fn LLVMRustBuildMemMove(B: &Builder<'a>,
+ Dst: &'a Value,
+ DstAlign: c_uint,
+ Src: &'a Value,
+ SrcAlign: c_uint,
+ Size: &'a Value,
+ IsVolatile: bool)
+ -> &'a Value;
pub fn LLVMBuildSelect(B: &Builder<'a>,
If: &'a Value,
Then: &'a Value,
pub fn LLVMRustBuildVectorReduceFAdd(B: &Builder<'a>,
Acc: &'a Value,
Src: &'a Value)
- -> Option<&'a Value>;
+ -> &'a Value;
pub fn LLVMRustBuildVectorReduceFMul(B: &Builder<'a>,
Acc: &'a Value,
Src: &'a Value)
- -> Option<&'a Value>;
+ -> &'a Value;
pub fn LLVMRustBuildVectorReduceAdd(B: &Builder<'a>,
Src: &'a Value)
- -> Option<&'a Value>;
+ -> &'a Value;
pub fn LLVMRustBuildVectorReduceMul(B: &Builder<'a>,
Src: &'a Value)
- -> Option<&'a Value>;
+ -> &'a Value;
pub fn LLVMRustBuildVectorReduceAnd(B: &Builder<'a>,
Src: &'a Value)
- -> Option<&'a Value>;
+ -> &'a Value;
pub fn LLVMRustBuildVectorReduceOr(B: &Builder<'a>,
Src: &'a Value)
- -> Option<&'a Value>;
+ -> &'a Value;
pub fn LLVMRustBuildVectorReduceXor(B: &Builder<'a>,
Src: &'a Value)
- -> Option<&'a Value>;
+ -> &'a Value;
pub fn LLVMRustBuildVectorReduceMin(B: &Builder<'a>,
Src: &'a Value,
IsSigned: bool)
- -> Option<&'a Value>;
+ -> &'a Value;
pub fn LLVMRustBuildVectorReduceMax(B: &Builder<'a>,
Src: &'a Value,
IsSigned: bool)
- -> Option<&'a Value>;
+ -> &'a Value;
pub fn LLVMRustBuildVectorReduceFMin(B: &Builder<'a>,
Src: &'a Value,
IsNaN: bool)
- -> Option<&'a Value>;
+ -> &'a Value;
pub fn LLVMRustBuildVectorReduceFMax(B: &Builder<'a>,
Src: &'a Value,
IsNaN: bool)
- -> Option<&'a Value>;
+ -> &'a Value;
pub fn LLVMRustBuildMinNum(
B: &Builder<'a>,
RunInliner: Bool);
pub fn LLVMRustPassManagerBuilderPopulateThinLTOPassManager(
PMB: &PassManagerBuilder,
- PM: &PassManager) -> bool;
+ PM: &PassManager);
// Stuff that's in rustllvm/ because it's not upstream yet.
"hexagon" => HEXAGON_WHITELIST,
"mips" | "mips64" => MIPS_WHITELIST,
"powerpc" | "powerpc64" => POWERPC_WHITELIST,
- "wasm32" => WASM_WHITELIST,
+ // wasm32 on emscripten does not support these target features
+ "wasm32" if !sess.target.target.options.is_like_emscripten => WASM_WHITELIST,
_ => &[],
}
}
}
}
+pub fn get_major_version() -> u32 {
+ unsafe { llvm::LLVMRustVersionMajor() }
+}
+
pub fn print_passes() {
// Can be called without initializing LLVM
unsafe { llvm::LLVMRustPrintPasses(); }
// Load the data pointer from the object.
debug!("get_fn({:?}, {:?})", llvtable, self);
- let llvtable = bx.pointercast(llvtable, fn_ty.llvm_type(bx.cx).ptr_to().ptr_to());
+ let llvtable = bx.pointercast(llvtable, fn_ty.ptr_to_llvm_type(bx.cx).ptr_to());
let ptr_align = bx.tcx().data_layout.pointer_align;
let ptr = bx.load(bx.inbounds_gep(llvtable, &[C_usize(bx.cx, self.0)]), ptr_align);
bx.nonnull_metadata(ptr);
// have scary latent bugs around.
let scratch = PlaceRef::alloca(bx, arg.layout, "arg");
- base::memcpy_ty(bx, scratch.llval, llval, op.layout, align, MemFlags::empty());
+ base::memcpy_ty(bx, scratch.llval, scratch.align, llval, align,
+ op.layout, MemFlags::empty());
(scratch.llval, scratch.align, true)
} else {
(llval, align, true)
use libc::c_uint;
use llvm::{self, BasicBlock};
use llvm::debuginfo::DIScope;
+use llvm_util;
use rustc::ty::{self, Ty, TypeFoldable, UpvarSubsts};
use rustc::ty::layout::{LayoutOf, TyLayout};
use rustc::mir::{self, Mir};
// doesn't actually strip the offset when splitting the closure
// environment into its components so it ends up out of bounds.
// (cuviper) It seems to be fine without the alloca on LLVM 6 and later.
- let env_alloca = !env_ref && unsafe { llvm::LLVMRustVersionMajor() < 6 };
+ let env_alloca = !env_ref && llvm_util::get_major_version() < 6;
let env_ptr = if env_alloca {
let scratch = PlaceRef::alloca(bx,
bx.cx.layout_of(tcx.mk_mut_ptr(arg.layout.ty)),
}
match self {
OperandValue::Ref(r, None, source_align) => {
- base::memcpy_ty(bx, dest.llval, r, dest.layout,
- source_align.min(dest.align), flags)
+ base::memcpy_ty(bx, dest.llval, dest.align, r, source_align,
+ dest.layout, flags)
}
OperandValue::Ref(_, Some(_), _) => {
bug!("cannot directly store unsized values");
// Allocate an appropriate region on the stack, and copy the value into it
let (llsize, _) = glue::size_and_align_of_dst(&bx, unsized_ty, Some(llextra));
let lldst = bx.array_alloca(Type::i8(bx.cx), llsize, "unsized_tmp", max_align);
- base::call_memcpy(&bx, lldst, llptr, llsize, min_align, flags);
+ base::call_memcpy(&bx, lldst, max_align, llptr, min_align, llsize, flags);
// Store the allocated region and the extra to the indirect place.
let indirect_operand = OperandValue::Pair(lldst, llextra);
}
pub fn ptr_to(&self) -> &Type {
+ assert_ne!(self.kind(), TypeKind::Function,
+ "don't call ptr_to on function types, use ptr_to_llvm_type on FnType instead");
unsafe {
llvm::LLVMPointerType(self, 0)
}
ty::ParamEnv::reveal_all(),
&sig,
);
- FnType::new(cx, sig, &[]).llvm_type(cx).ptr_to()
+ FnType::new(cx, sig, &[]).ptr_to_llvm_type(cx)
}
_ => self.scalar_llvm_type_at(cx, scalar, Size::ZERO)
};
}
impl<'a> Linker for GccLinker<'a> {
- fn link_dylib(&mut self, lib: &str) { self.hint_dynamic(); self.cmd.arg(format!("-l{}",lib)); }
+ fn link_dylib(&mut self, lib: &str) { self.hint_dynamic(); self.cmd.arg(format!("-l{}", lib)); }
fn link_staticlib(&mut self, lib: &str) {
- self.hint_static(); self.cmd.arg(format!("-l{}",lib));
+ self.hint_static(); self.cmd.arg(format!("-l{}", lib));
}
fn link_rlib(&mut self, lib: &Path) { self.hint_static(); self.cmd.arg(lib); }
fn include_path(&mut self, path: &Path) { self.cmd.arg("-L").arg(path); }
fn link_rust_dylib(&mut self, lib: &str, _path: &Path) {
self.hint_dynamic();
- self.cmd.arg(format!("-l{}",lib));
+ self.cmd.arg(format!("-l{}", lib));
}
fn link_framework(&mut self, framework: &str) {
self.hint_static();
let target = &self.sess.target.target;
if !target.options.is_like_osx {
- self.linker_arg("--whole-archive").cmd.arg(format!("-l{}",lib));
+ self.linker_arg("--whole-archive").cmd.arg(format!("-l{}", lib));
self.linker_arg("--no-whole-archive");
} else {
// -force_load is the macOS equivalent of --whole-archive, but it
}
fn debuginfo(&mut self) {
- match self.sess.opts.debuginfo {
- DebugInfo::None => {
- // If we are building without debuginfo enabled and we were called with
- // `-Zstrip-debuginfo-if-disabled=yes`, tell the linker to strip any debuginfo
- // found when linking to get rid of symbols from libstd.
- match self.sess.opts.debugging_opts.strip_debuginfo_if_disabled {
- Some(true) => { self.linker_arg("-S"); },
- _ => {},
- }
- },
- _ => {},
+ if let DebugInfo::None = self.sess.opts.debuginfo {
+ // If we are building without debuginfo enabled and we were called with
+ // `-Zstrip-debuginfo-if-disabled=yes`, tell the linker to strip any debuginfo
+ // found when linking to get rid of symbols from libstd.
+ if let Some(true) = self.sess.opts.debugging_opts.strip_debuginfo_if_disabled {
+ self.linker_arg("-S");
+ }
};
}
// purely to support rustbuild right now, we should get a more
// principled solution at some point to force the compiler to pass
// the right `-Wl,-install_name` with an `@rpath` in it.
- if self.sess.opts.cg.rpath ||
- self.sess.opts.debugging_opts.osx_rpath_install_name {
+ if self.sess.opts.cg.rpath || self.sess.opts.debugging_opts.osx_rpath_install_name {
self.linker_arg("-install_name");
let mut v = OsString::from("@rpath/");
v.push(out_filename.file_name().unwrap());
fn finalize(&mut self) -> Command {
self.hint_dynamic(); // Reset to default before returning the composed command line.
- let mut cmd = Command::new("");
- ::std::mem::swap(&mut cmd, &mut self.cmd);
- cmd
+
+ ::std::mem::replace(&mut self.cmd, Command::new(""))
}
fn group_start(&mut self) {
}
fn finalize(&mut self) -> Command {
- let mut cmd = Command::new("");
- ::std::mem::swap(&mut cmd, &mut self.cmd);
- cmd
+ ::std::mem::replace(&mut self.cmd, Command::new(""))
}
// MSVC doesn't need group indicators
let res = encoder.emit_seq(symbols.len(), |encoder| {
for (i, sym) in symbols.iter().enumerate() {
encoder.emit_seq_elt(i, |encoder| {
- encoder.emit_str(&("_".to_string() + sym))
+ encoder.emit_str(&("_".to_owned() + sym))
})?;
}
Ok(())
}
fn finalize(&mut self) -> Command {
- let mut cmd = Command::new("");
- ::std::mem::swap(&mut cmd, &mut self.cmd);
- cmd
+ ::std::mem::replace(&mut self.cmd, Command::new(""))
}
// Appears not necessary on Emscripten
// indicative of bugs, let's prevent them.
self.cmd.arg("--fatal-warnings");
- let mut cmd = Command::new("");
- ::std::mem::swap(&mut cmd, &mut self.cmd);
- cmd
+ ::std::mem::replace(&mut self.cmd, Command::new(""))
}
// Not needed for now with LLD
}
}
-pub fn crates_export_threshold(crate_types: &[config::CrateType])
- -> SymbolExportLevel {
- if crate_types.iter().any(|&crate_type| {
- crate_export_threshold(crate_type) == SymbolExportLevel::Rust
- }) {
+pub fn crates_export_threshold(crate_types: &[config::CrateType]) -> SymbolExportLevel {
+ if crate_types.iter().any(|&crate_type|
+ crate_export_threshold(crate_type) == SymbolExportLevel::Rust)
+ {
SymbolExportLevel::Rust
} else {
SymbolExportLevel::C
!tcx.reachable_set(LOCAL_CRATE).0.contains(&node_id)
} else {
bug!("is_unreachable_local_definition called with non-local DefId: {:?}",
- def_id)
+ def_id)
}
}
codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL);
if is_extern && !std_internal {
+ // Emscripten cannot export statics, so reduce their export level here
+ if tcx.sess.target.target.options.is_like_emscripten {
+ if let Some(Node::Item(&hir::Item {
+ node: hir::ItemKind::Static(..),
+ ..
+ })) = tcx.hir.get_if_local(sym_def_id) {
+ return SymbolExportLevel::Rust;
+ }
+ }
+
SymbolExportLevel::C
} else {
SymbolExportLevel::Rust
pub use rustc_serialize::hex::ToHex;
+pub mod macros;
pub mod svh;
pub mod base_n;
pub mod bit_set;
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+/// A simple static assertion macro. The first argument should be a unique
+/// ALL_CAPS identifier that describes the condition.
+#[macro_export]
+macro_rules! static_assert {
+ ($name:ident: $test:expr) => {
+ // Use the bool to access an array such that if the bool is false, the access
+ // is out-of-bounds.
+ #[allow(dead_code)]
+ static $name: () = [()][!$test as usize];
+ }
+}
impl ColorConfig {
fn to_color_choice(&self) -> ColorChoice {
match *self {
- ColorConfig::Always => ColorChoice::Always,
+ ColorConfig::Always => {
+ if atty::is(atty::Stream::Stderr) {
+ ColorChoice::Always
+ } else {
+ ColorChoice::AlwaysAnsi
+ }
+ }
ColorConfig::Never => ColorChoice::Never,
ColorConfig::Auto if atty::is(atty::Stream::Stderr) => {
ColorChoice::Auto
reference: "issue #51443 <https://github.com/rust-lang/rust/issues/51443>",
edition: None,
},
- FutureIncompatibleInfo {
- id: LintId::of(DUPLICATE_ASSOCIATED_TYPE_BINDINGS),
- reference: "issue #50589 <https://github.com/rust-lang/rust/issues/50589>",
- edition: None,
- },
FutureIncompatibleInfo {
id: LintId::of(PROC_MACRO_DERIVE_RESOLUTION_FALLBACK),
reference: "issue #50504 <https://github.com/rust-lang/rust/issues/50504>",
[dependencies]
alloc = { path = "../liballoc" }
-alloc_system = { path = "../liballoc_system" }
core = { path = "../libcore" }
compiler_builtins = { path = "../rustc/compiler_builtins_shim" }
// except according to those terms.
#![sanitizer_runtime]
-#![feature(alloc_system)]
#![feature(nll)]
#![feature(sanitizer_runtime)]
#![feature(staged_api)]
#![unstable(feature = "sanitizer_runtime_lib",
reason = "internal implementation detail of sanitizers",
issue = "0")]
-
-extern crate alloc_system;
-
-use alloc_system::System;
-
-#[global_allocator]
-static ALLOC: System = System;
use schema::CrateRoot;
use rustc_data_structures::sync::{Lrc, RwLock, Lock};
-use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX};
+use rustc::hir::def_id::CrateNum;
use rustc_data_structures::svh::Svh;
use rustc::middle::allocator::AllocatorKind;
use rustc::middle::cstore::DepKind;
needs_allocator = needs_allocator || data.root.needs_allocator;
});
if !needs_allocator {
- self.sess.injected_allocator.set(None);
self.sess.allocator_kind.set(None);
return
}
// At this point we've determined that we need an allocator. Let's see
// if our compilation session actually needs an allocator based on what
// we're emitting.
- let mut need_lib_alloc = false;
- let mut need_exe_alloc = false;
- for ct in self.sess.crate_types.borrow().iter() {
- match *ct {
- config::CrateType::Executable => need_exe_alloc = true,
- config::CrateType::Dylib |
- config::CrateType::ProcMacro |
- config::CrateType::Cdylib |
- config::CrateType::Staticlib => need_lib_alloc = true,
- config::CrateType::Rlib => {}
- }
- }
- if !need_lib_alloc && !need_exe_alloc {
- self.sess.injected_allocator.set(None);
+ let all_rlib = self.sess.crate_types.borrow()
+ .iter()
+ .all(|ct| {
+ match *ct {
+ config::CrateType::Rlib => true,
+ _ => false,
+ }
+ });
+ if all_rlib {
self.sess.allocator_kind.set(None);
return
}
});
if global_allocator.is_some() {
self.sess.allocator_kind.set(Some(AllocatorKind::Global));
- self.sess.injected_allocator.set(None);
return
}
// Ok we haven't found a global allocator but we still need an
- // allocator. At this point we'll either fall back to the "library
- // allocator" or the "exe allocator" depending on a few variables. Let's
- // figure out which one.
- //
- // Note that here we favor linking to the "library allocator" as much as
- // possible. If we're not creating rustc's version of libstd
- // (need_lib_alloc and prefer_dynamic) then we select `None`, and if the
- // exe allocation crate doesn't exist for this target then we also
- // select `None`.
- let exe_allocation_crate_data =
- if need_lib_alloc && !self.sess.opts.cg.prefer_dynamic {
- None
- } else {
- self.sess
- .target
- .target
- .options
- .exe_allocation_crate
- .as_ref()
- .map(|name| {
- // We've determined that we're injecting an "exe allocator" which means
- // that we're going to load up a whole new crate. An example of this is
- // that we're producing a normal binary on Linux which means we need to
- // load the `alloc_jemalloc` crate to link as an allocator.
- let name = Symbol::intern(name);
- let (cnum, data) = self.resolve_crate(&None,
- name,
- name,
- None,
- None,
- DUMMY_SP,
- PathKind::Crate,
- DepKind::Implicit)
- .unwrap_or_else(|err| err.report());
- self.sess.injected_allocator.set(Some(cnum));
- data
- })
- };
-
- let allocation_crate_data = exe_allocation_crate_data.or_else(|| {
- // No allocator was injected
- self.sess.injected_allocator.set(None);
-
- if attr::contains_name(&krate.attrs, "default_lib_allocator") {
- // Prefer self as the allocator if there's a collision
- return None;
+ // allocator. At this point our allocator request is typically fulfilled
+ // by the standard library, denoted by the `#![default_lib_allocator]`
+ // attribute.
+ let mut has_default = attr::contains_name(&krate.attrs, "default_lib_allocator");
+ self.cstore.iter_crate_data(|_, data| {
+ if data.root.has_default_lib_allocator {
+ has_default = true;
}
- // We're not actually going to inject an allocator, we're going to
- // require that something in our crate graph is the default lib
- // allocator. This is typically libstd, so this'll rarely be an
- // error.
- let mut allocator = None;
- self.cstore.iter_crate_data(|_, data| {
- if allocator.is_none() && data.root.has_default_lib_allocator {
- allocator = Some(data.clone());
- }
- });
- allocator
});
- match allocation_crate_data {
- Some(data) => {
- // We have an allocator. We detect separately what kind it is, to allow for some
- // flexibility in misconfiguration.
- let attrs = data.get_item_attrs(CRATE_DEF_INDEX, self.sess);
- let kind_interned = attr::first_attr_value_str_by_name(&attrs, "rustc_alloc_kind")
- .map(Symbol::as_str);
- let kind_str = kind_interned
- .as_ref()
- .map(|s| s as &str);
- let alloc_kind = match kind_str {
- None |
- Some("lib") => AllocatorKind::DefaultLib,
- Some("exe") => AllocatorKind::DefaultExe,
- Some(other) => {
- self.sess.err(&format!("Allocator kind {} not known", other));
- return;
- }
- };
- self.sess.allocator_kind.set(Some(alloc_kind));
- },
- None => {
- if !attr::contains_name(&krate.attrs, "default_lib_allocator") {
- self.sess.err("no global memory allocator found but one is \
- required; link to std or \
- add #[global_allocator] to a static item \
- that implements the GlobalAlloc trait.");
- return;
- }
- self.sess.allocator_kind.set(Some(AllocatorKind::DefaultLib));
- }
+ if !has_default {
+ self.sess.err("no global memory allocator found but one is \
+ required; link to std or \
+ add #[global_allocator] to a static item \
+ that implements the GlobalAlloc trait.");
}
+ self.sess.allocator_kind.set(Some(AllocatorKind::DefaultLib));
fn has_global_allocator(krate: &ast::Crate) -> bool {
struct Finder(bool);
impl<'a> CrateLoader<'a> {
pub fn postprocess(&mut self, krate: &ast::Crate) {
- // inject the sanitizer runtime before the allocator runtime because all
- // sanitizers force the use of the `alloc_system` allocator
self.inject_sanitizer_runtime();
self.inject_profiler_runtime();
self.inject_allocator_crate(krate);
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_data_structures::bit_set::BitSet;
use std::fmt;
-use std::hash::Hash;
use std::ops::Index;
crate struct BorrowSet<'tcx> {
self.insert_as_pending_if_two_phase(location, &assigned_place, region, kind, idx);
- insert(&mut self.region_map, ®ion, idx);
+ self.region_map.entry(region).or_default().insert(idx);
if let Some(local) = borrowed_place.root_local() {
- insert(&mut self.local_map, &local, idx);
+ self.local_map.entry(local).or_default().insert(idx);
}
}
- return self.super_assign(block, assigned_place, rvalue, location);
-
- fn insert<'a, K, V>(map: &'a mut FxHashMap<K, FxHashSet<V>>, k: &K, v: V)
- where
- K: Clone + Eq + Hash,
- V: Eq + Hash,
- {
- map.entry(k.clone()).or_default().insert(v);
- }
+ self.super_assign(block, assigned_place, rvalue, location)
}
fn visit_place(
// Note that this set is expected to be small - only upvars from closures
// would have a chance of erroneously adding non-user-defined mutable vars
// to the set.
- let temporary_used_locals: FxHashSet<Local> = mbcx
- .used_mut
- .iter()
+ let temporary_used_locals: FxHashSet<Local> = mbcx.used_mut.iter()
.filter(|&local| mbcx.mir.local_decls[*local].is_user_variable.is_none())
.cloned()
.collect();
- mbcx.gather_used_muts(temporary_used_locals);
+ // For the remaining unused locals that are marked as mutable, we avoid linting any that
+ // were never initialized. These locals may have been removed as unreachable code; or will be
+ // linted as unused variables.
+ let unused_mut_locals = mbcx.mir.mut_vars_iter()
+ .filter(|local| !mbcx.used_mut.contains(local))
+ .collect();
+ mbcx.gather_used_muts(temporary_used_locals, unused_mut_locals);
debug!("mbcx.used_mut: {:?}", mbcx.used_mut);
-
let used_mut = mbcx.used_mut;
-
- for local in mbcx
- .mir
- .mut_vars_and_args_iter()
- .filter(|local| !used_mut.contains(local))
- {
+ for local in mbcx.mir.mut_vars_and_args_iter().filter(|local| !used_mut.contains(local)) {
if let ClearCrossCrate::Set(ref vsi) = mbcx.mir.source_scope_local_data {
let local_decl = &mbcx.mir.local_decls[local];
}
}
- fn check_parent_of_field<'cx, 'gcx, 'tcx>(this: &mut MirBorrowckCtxt<'cx, 'gcx, 'tcx>,
- context: Context,
- base: &Place<'tcx>,
- span: Span,
- flow_state: &Flows<'cx, 'gcx, 'tcx>)
- {
+ fn check_parent_of_field<'cx, 'gcx, 'tcx>(
+ this: &mut MirBorrowckCtxt<'cx, 'gcx, 'tcx>,
+ context: Context,
+ base: &Place<'tcx>,
+ span: Span,
+ flow_state: &Flows<'cx, 'gcx, 'tcx>,
+ ) {
// rust-lang/rust#21232: Until Rust allows reads from the
// initialized parts of partially initialized structs, we
// will, starting with the 2018 edition, reject attempts
}
if let Some((prefix, mpi)) = shortest_uninit_seen {
+ // Check for a reassignment into a uninitialized field of a union (for example,
+ // after a move out). In this case, do not report a error here. There is an
+ // exception, if this is the first assignment into the union (that is, there is
+ // no move out from an earlier location) then this is an attempt at initialization
+ // of the union - we should error in that case.
+ let tcx = this.infcx.tcx;
+ if let ty::TyKind::Adt(def, _) = base.ty(this.mir, tcx).to_ty(tcx).sty {
+ if def.is_union() {
+ if this.move_data.path_map[mpi].iter().any(|moi| {
+ this.move_data.moves[*moi].source.is_predecessor_of(
+ context.loc, this.mir,
+ )
+ }) {
+ return;
+ }
+ }
+ }
+
this.report_use_of_moved_or_uninitialized(
context,
InitializationRequiringAction::PartialAssignment,
let mir_node_id = tcx.hir.as_local_node_id(mir_def_id).expect("non-local mir");
- let (return_span, mir_description) =
- if let hir::ExprKind::Closure(_, _, _, span, gen_move) =
- tcx.hir.expect_expr(mir_node_id).node
- {
- (
- tcx.sess.source_map().end_point(span),
- if gen_move.is_some() {
- " of generator"
- } else {
- " of closure"
- },
- )
- } else {
- // unreachable?
- (mir.span, "")
- };
+ let (return_span, mir_description) = match tcx.hir.get(mir_node_id) {
+ hir::Node::Expr(hir::Expr {
+ node: hir::ExprKind::Closure(_, _, _, span, gen_move),
+ ..
+ }) => (
+ tcx.sess.source_map().end_point(*span),
+ if gen_move.is_some() {
+ " of generator"
+ } else {
+ " of closure"
+ },
+ ),
+ hir::Node::ImplItem(hir::ImplItem {
+ node: hir::ImplItemKind::Method(method_sig, _),
+ ..
+ }) => (method_sig.decl.output.span(), ""),
+ _ => (mir.span, ""),
+ };
Some(RegionName {
// This counter value will already have been used, so this function will increment it
let v1 = ty::Contravariant.xform(v);
let tcx = self.infcx.tcx;
- let mut projected_ty = PlaceTy::from_ty(ty);
+ let ty = self.normalize(ty, locations);
+
+ // We need to follow any provided projetions into the type.
+ //
+ // if we hit a ty var as we descend, then just skip the
+ // attempt to relate the mir local with any type.
+ #[derive(Debug)] struct HitTyVar;
+ let mut curr_projected_ty: Result<PlaceTy, HitTyVar>;
+
+ curr_projected_ty = Ok(PlaceTy::from_ty(ty));
for proj in &user_ty.projs {
- projected_ty = projected_ty.projection_ty_core(
+ let projected_ty = if let Ok(projected_ty) = curr_projected_ty {
+ projected_ty
+ } else {
+ break;
+ };
+ curr_projected_ty = projected_ty.projection_ty_core(
tcx, proj, |this, field, &()| {
- let ty = this.field_ty(tcx, field);
- self.normalize(ty, locations)
+ if this.to_ty(tcx).is_ty_var() {
+ Err(HitTyVar)
+ } else {
+ let ty = this.field_ty(tcx, field);
+ Ok(self.normalize(ty, locations))
+ }
});
}
debug!("user_ty base: {:?} freshened: {:?} projs: {:?} yields: {:?}",
- user_ty.base, ty, user_ty.projs, projected_ty);
+ user_ty.base, ty, user_ty.projs, curr_projected_ty);
- let ty = projected_ty.to_ty(tcx);
-
- self.relate_types(ty, v1, a, locations, category)?;
+ if let Ok(projected_ty) = curr_projected_ty {
+ let ty = projected_ty.to_ty(tcx);
+ self.relate_types(ty, v1, a, locations, category)?;
+ }
}
UserTypeAnnotation::TypeOf(def_id, canonical_substs) => {
let (
// except according to those terms.
use rustc::mir::visit::{PlaceContext, Visitor};
-use rustc::mir::{Local, Location, Place};
+use rustc::mir::{BasicBlock, Local, Location, Place, Statement, StatementKind, TerminatorKind};
use rustc_data_structures::fx::FxHashSet;
use borrow_check::MirBorrowckCtxt;
impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
- /// Walks the MIR looking for assignments to a set of locals, as part of the unused mutable
- /// local variables lint, to update the context's `used_mut` in a single walk.
- crate fn gather_used_muts(&mut self, locals: FxHashSet<Local>) {
- let mut visitor = GatherUsedMutsVisitor {
- needles: locals,
- mbcx: self,
- };
- visitor.visit_mir(visitor.mbcx.mir);
+ /// Walks the MIR adding to the set of `used_mut` locals that will be ignored for the purposes
+ /// of the `unused_mut` lint.
+ ///
+ /// `temporary_used_locals` should contain locals that were found to be temporary, mutable and
+ /// used from borrow checking. This function looks for assignments into these locals from
+ /// user-declared locals and adds those user-defined locals to the `used_mut` set. This can
+ /// occur due to a rare case involving upvars in closures.
+ ///
+ /// `never_initialized_mut_locals` should contain the set of user-declared mutable locals
+ /// (not arguments) that have not already been marked as being used.
+ /// This function then looks for assignments from statements or the terminator into the locals
+ /// from this set and removes them from the set. This leaves only those locals that have not
+ /// been assigned to - this set is used as a proxy for locals that were not initialized due to
+ /// unreachable code. These locals are then considered "used" to silence the lint for them.
+ /// See #55344 for context.
+ crate fn gather_used_muts(
+ &mut self,
+ temporary_used_locals: FxHashSet<Local>,
+ mut never_initialized_mut_locals: FxHashSet<Local>,
+ ) {
+ {
+ let mut visitor = GatherUsedMutsVisitor {
+ temporary_used_locals,
+ never_initialized_mut_locals: &mut never_initialized_mut_locals,
+ mbcx: self,
+ };
+ visitor.visit_mir(visitor.mbcx.mir);
+ }
+
+ // Take the union of the existed `used_mut` set with those variables we've found were
+ // never initialized.
+ debug!("gather_used_muts: never_initialized_mut_locals={:?}", never_initialized_mut_locals);
+ self.used_mut = self.used_mut.union(&never_initialized_mut_locals).cloned().collect();
}
}
-/// MIR visitor gathering the assignments to a set of locals, in a single walk.
-/// 'visit = the duration of the MIR walk
+/// MIR visitor for collecting used mutable variables.
+/// The 'visit lifetime represents the duration of the MIR walk.
struct GatherUsedMutsVisitor<'visit, 'cx: 'visit, 'gcx: 'tcx, 'tcx: 'cx> {
- needles: FxHashSet<Local>,
+ temporary_used_locals: FxHashSet<Local>,
+ never_initialized_mut_locals: &'visit mut FxHashSet<Local>,
mbcx: &'visit mut MirBorrowckCtxt<'cx, 'gcx, 'tcx>,
}
impl<'visit, 'cx, 'gcx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'gcx, 'tcx> {
+ fn visit_terminator_kind(
+ &mut self,
+ _block: BasicBlock,
+ kind: &TerminatorKind<'tcx>,
+ _location: Location,
+ ) {
+ debug!("visit_terminator_kind: kind={:?}", kind);
+ match &kind {
+ TerminatorKind::Call { destination: Some((into, _)), .. } => {
+ if let Some(local) = into.base_local() {
+ debug!(
+ "visit_terminator_kind: kind={:?} local={:?} \
+ never_initialized_mut_locals={:?}",
+ kind, local, self.never_initialized_mut_locals
+ );
+ let _ = self.never_initialized_mut_locals.remove(&local);
+ }
+ },
+ _ => {},
+ }
+ }
+
+ fn visit_statement(
+ &mut self,
+ _block: BasicBlock,
+ statement: &Statement<'tcx>,
+ _location: Location,
+ ) {
+ match &statement.kind {
+ StatementKind::Assign(into, _) => {
+ // Remove any locals that we found were initialized from the
+ // `never_initialized_mut_locals` set. At the end, the only remaining locals will
+ // be those that were never initialized - we will consider those as being used as
+ // they will either have been removed by unreachable code optimizations; or linted
+ // as unused variables.
+ if let Some(local) = into.base_local() {
+ debug!(
+ "visit_statement: statement={:?} local={:?} \
+ never_initialized_mut_locals={:?}",
+ statement, local, self.never_initialized_mut_locals
+ );
+ let _ = self.never_initialized_mut_locals.remove(&local);
+ }
+ },
+ _ => {},
+ }
+ }
+
fn visit_local(
&mut self,
local: &Local,
place_context: PlaceContext<'tcx>,
location: Location,
) {
- if !self.needles.contains(local) {
- return;
- }
-
- if place_context.is_place_assignment() {
+ if place_context.is_place_assignment() && self.temporary_used_locals.contains(local) {
// Propagate the Local assigned at this Location as a used mutable local variable
for moi in &self.mbcx.move_data.loc_map[location] {
let mpi = &self.mbcx.move_data.moves[*moi].path;
fn gather_init(&mut self, place: &Place<'tcx>, kind: InitKind) {
debug!("gather_init({:?}, {:?})", self.loc, place);
+ let place = match place {
+ // Check if we are assigning into a field of a union, if so, lookup the place
+ // of the union so it is marked as initialized again.
+ Place::Projection(box Projection {
+ base,
+ elem: ProjectionElem::Field(_, _),
+ }) if match base.ty(self.builder.mir, self.builder.tcx).to_ty(self.builder.tcx).sty {
+ ty::TyKind::Adt(def, _) if def.is_union() => true,
+ _ => false,
+ } => base,
+ // Otherwise, lookup the place.
+ _ => place,
+ };
+
if let LookupResult::Exact(path) = self.builder.data.rev_lookup.find(place) {
let init = self.builder.data.inits.push(Init {
location: InitLocation::Statement(self.loc),
}
self.write_scalar(val, dest)?;
}
+ "rotate_left" | "rotate_right" => {
+ // rotate_left: (X << (S % BW)) | (X >> ((BW - S) % BW))
+ // rotate_right: (X << ((BW - S) % BW)) | (X >> (S % BW))
+ let layout = self.layout_of(substs.type_at(0))?;
+ let val_bits = self.read_scalar(args[0])?.to_bits(layout.size)?;
+ let raw_shift_bits = self.read_scalar(args[1])?.to_bits(layout.size)?;
+ let width_bits = layout.size.bits() as u128;
+ let shift_bits = raw_shift_bits % width_bits;
+ let inv_shift_bits = (width_bits - raw_shift_bits) % width_bits;
+ let result_bits = if intrinsic_name == "rotate_left" {
+ (val_bits << shift_bits) | (val_bits >> inv_shift_bits)
+ } else {
+ (val_bits >> shift_bits) | (val_bits << inv_shift_bits)
+ };
+ let truncated_bits = self.truncate(result_bits, layout);
+ let result = Scalar::from_uint(truncated_bits, layout.size);
+ self.write_scalar(result, dest)?;
+ }
"transmute" => {
self.copy_op_transmute(args[0], dest)?;
}
use rustc::ty::{self, layout::{Size, TyLayout}, query::TyCtxtAt};
use super::{
- Allocation, AllocId, EvalResult, Scalar,
+ Allocation, AllocId, EvalResult, Scalar, AllocationExtra,
EvalContext, PlaceTy, MPlaceTy, OpTy, Pointer, MemoryKind,
};
type PointerTag: ::std::fmt::Debug + Default + Copy + Eq + Hash + 'static;
/// Extra data stored in every allocation.
- type AllocExtra: ::std::fmt::Debug + Default + Clone;
+ type AllocExtra: AllocationExtra<Self::PointerTag>;
/// Memory's allocation map
type MemoryMap:
dest: PlaceTy<'tcx, Self::PointerTag>,
) -> EvalResult<'tcx>;
- /// Hook for performing extra checks on a memory read access.
- #[inline]
- fn memory_read(
- _alloc: &Allocation<Self::PointerTag, Self::AllocExtra>,
- _ptr: Pointer<Self::PointerTag>,
- _size: Size,
- ) -> EvalResult<'tcx> {
- Ok(())
- }
-
- /// Hook for performing extra checks on a memory write access.
- #[inline]
- fn memory_written(
- _alloc: &mut Allocation<Self::PointerTag, Self::AllocExtra>,
- _ptr: Pointer<Self::PointerTag>,
- _size: Size,
- ) -> EvalResult<'tcx> {
- Ok(())
- }
-
/// Hook for performing extra checks when memory gets deallocated.
#[inline]
fn memory_deallocated(
use syntax::ast::Mutability;
use super::{
- Pointer, AllocId, Allocation, ConstValue, GlobalId,
+ Pointer, AllocId, Allocation, ConstValue, GlobalId, AllocationExtra,
EvalResult, Scalar, EvalErrorKind, AllocType, PointerArithmetic,
Machine, AllocMap, MayLeak, ScalarMaybeUndef, ErrorHandled,
};
}
let alloc = self.get(ptr.alloc_id)?;
- M::memory_read(alloc, ptr, size)?;
+ AllocationExtra::memory_read(alloc, ptr, size)?;
assert_eq!(ptr.offset.bytes() as usize as u64, ptr.offset.bytes());
assert_eq!(size.bytes() as usize as u64, size.bytes());
self.clear_relocations(ptr, size)?;
let alloc = self.get_mut(ptr.alloc_id)?;
- M::memory_written(alloc, ptr, size)?;
+ AllocationExtra::memory_written(alloc, ptr, size)?;
assert_eq!(ptr.offset.bytes() as usize as u64, ptr.offset.bytes());
assert_eq!(size.bytes() as usize as u64, size.bytes());
//! All high-level functions to read from memory work on operands as sources.
use std::convert::TryInto;
-use std::fmt;
use rustc::{mir, ty};
use rustc::ty::layout::{self, Size, LayoutOf, TyLayout, HasDataLayout, IntegerExt};
EvalResult, EvalErrorKind
};
use super::{EvalContext, Machine, MemPlace, MPlaceTy, MemoryKind};
-
-#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
-pub enum ScalarMaybeUndef<Tag=(), Id=AllocId> {
- Scalar(Scalar<Tag, Id>),
- Undef,
-}
-
-impl<Tag> From<Scalar<Tag>> for ScalarMaybeUndef<Tag> {
- #[inline(always)]
- fn from(s: Scalar<Tag>) -> Self {
- ScalarMaybeUndef::Scalar(s)
- }
-}
-
-impl<Tag> fmt::Display for ScalarMaybeUndef<Tag> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self {
- ScalarMaybeUndef::Undef => write!(f, "uninitialized bytes"),
- ScalarMaybeUndef::Scalar(s) => write!(f, "{}", s),
- }
- }
-}
-
-impl<'tcx> ScalarMaybeUndef<()> {
- #[inline]
- pub fn with_default_tag<Tag>(self) -> ScalarMaybeUndef<Tag>
- where Tag: Default
- {
- match self {
- ScalarMaybeUndef::Scalar(s) => ScalarMaybeUndef::Scalar(s.with_default_tag()),
- ScalarMaybeUndef::Undef => ScalarMaybeUndef::Undef,
- }
- }
-}
-
-impl<'tcx, Tag> ScalarMaybeUndef<Tag> {
- #[inline]
- pub fn erase_tag(self) -> ScalarMaybeUndef
- {
- match self {
- ScalarMaybeUndef::Scalar(s) => ScalarMaybeUndef::Scalar(s.erase_tag()),
- ScalarMaybeUndef::Undef => ScalarMaybeUndef::Undef,
- }
- }
-
- #[inline]
- pub fn not_undef(self) -> EvalResult<'static, Scalar<Tag>> {
- match self {
- ScalarMaybeUndef::Scalar(scalar) => Ok(scalar),
- ScalarMaybeUndef::Undef => err!(ReadUndefBytes(Size::from_bytes(0))),
- }
- }
-
- #[inline(always)]
- pub fn to_ptr(self) -> EvalResult<'tcx, Pointer<Tag>> {
- self.not_undef()?.to_ptr()
- }
-
- #[inline(always)]
- pub fn to_bits(self, target_size: Size) -> EvalResult<'tcx, u128> {
- self.not_undef()?.to_bits(target_size)
- }
-
- #[inline(always)]
- pub fn to_bool(self) -> EvalResult<'tcx, bool> {
- self.not_undef()?.to_bool()
- }
-
- #[inline(always)]
- pub fn to_char(self) -> EvalResult<'tcx, char> {
- self.not_undef()?.to_char()
- }
-
- #[inline(always)]
- pub fn to_f32(self) -> EvalResult<'tcx, f32> {
- self.not_undef()?.to_f32()
- }
-
- #[inline(always)]
- pub fn to_f64(self) -> EvalResult<'tcx, f64> {
- self.not_undef()?.to_f64()
- }
-
- #[inline(always)]
- pub fn to_u8(self) -> EvalResult<'tcx, u8> {
- self.not_undef()?.to_u8()
- }
-
- #[inline(always)]
- pub fn to_u32(self) -> EvalResult<'tcx, u32> {
- self.not_undef()?.to_u32()
- }
-
- #[inline(always)]
- pub fn to_u64(self) -> EvalResult<'tcx, u64> {
- self.not_undef()?.to_u64()
- }
-
- #[inline(always)]
- pub fn to_usize(self, cx: &impl HasDataLayout) -> EvalResult<'tcx, u64> {
- self.not_undef()?.to_usize(cx)
- }
-
- #[inline(always)]
- pub fn to_i8(self) -> EvalResult<'tcx, i8> {
- self.not_undef()?.to_i8()
- }
-
- #[inline(always)]
- pub fn to_i32(self) -> EvalResult<'tcx, i32> {
- self.not_undef()?.to_i32()
- }
-
- #[inline(always)]
- pub fn to_i64(self) -> EvalResult<'tcx, i64> {
- self.not_undef()?.to_i64()
- }
-
- #[inline(always)]
- pub fn to_isize(self, cx: &impl HasDataLayout) -> EvalResult<'tcx, i64> {
- self.not_undef()?.to_isize(cx)
- }
-}
-
+pub use rustc::mir::interpret::ScalarMaybeUndef;
/// A `Value` represents a single immediate self-contained Rust value.
///
GlobalId, AllocId, Allocation, Scalar, EvalResult, Pointer, PointerArithmetic
};
use super::{
- EvalContext, Machine, AllocMap,
+ EvalContext, Machine, AllocMap, AllocationExtra,
Immediate, ImmTy, ScalarMaybeUndef, Operand, OpTy, MemoryKind
};
Tag: ::std::fmt::Debug+Default+Copy+Eq+Hash+'static,
M: Machine<'a, 'mir, 'tcx, PointerTag=Tag>,
M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation<Tag, M::AllocExtra>)>,
+ M::AllocExtra: AllocationExtra<Tag>,
{
/// Take a value, which represents a (thin or fat) reference, and make it a place.
/// Alignment is just based on the type. This is the inverse of `create_ref`.
}
}
-impl_stable_hash_for!(enum ::interpret::ScalarMaybeUndef {
- Scalar(v),
- Undef
-});
-
impl_snapshot_for!(enum ScalarMaybeUndef {
Scalar(s),
Undef,
use rustc::ty;
use rustc_data_structures::fx::FxHashSet;
use rustc::mir::interpret::{
- Scalar, AllocType, EvalResult, EvalErrorKind
+ Scalar, AllocType, EvalResult, EvalErrorKind,
};
use super::{
let source_info = SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE };
let return_block = BasicBlock::new(1);
- let mut blocks = IndexVec::new();
+ let mut blocks = IndexVec::with_capacity(2);
let block = |blocks: &mut IndexVec<_, _>, kind| {
blocks.push(BasicBlockData {
statements: vec![],
}));
}
- let mut blocks = IndexVec::new();
+ let n_blocks = if let Adjustment::RefMut = rcvr_adjustment { 5 } else { 2 };
+ let mut blocks = IndexVec::with_capacity(n_blocks);
let block = |blocks: &mut IndexVec<_, _>, statements, kind, is_cleanup| {
blocks.push(BasicBlockData {
statements,
use rustc::mir::{Rvalue, Statement, StatementKind};
use rustc::mir::visit::{MutVisitor, Visitor, TyContext};
use rustc::ty::{Ty, RegionKind, TyCtxt};
+use smallvec::smallvec;
use transform::{MirPass, MirSource};
pub struct CleanEndRegions;
fn visit_ty(&mut self, ty: &Ty<'tcx>, _: TyContext) {
// Gather regions that occur in types
- for re in ty.walk().flat_map(|t| t.regions()) {
+ let mut regions = smallvec![];
+ for t in ty.walk() {
+ t.push_regions(&mut regions);
+ }
+ for re in regions {
match *re {
RegionKind::ReScope(ce) => { self.seen_regions.insert(ce); }
_ => {},
if let TerminatorKind::Assert { expected, msg, cond, .. } = kind {
if let Some(value) = self.eval_operand(cond, source_info) {
trace!("assertion on {:?} should be {:?}", value, expected);
- let expected = Immediate::Scalar(Scalar::from_bool(*expected).into());
- if expected != value.0.to_immediate() {
+ let expected = ScalarMaybeUndef::from(Scalar::from_bool(*expected));
+ if expected != self.ecx.read_scalar(value.0).unwrap() {
// poison all places this operand references so that further code
// doesn't use the invalid value
match cond {
let len = self
.eval_operand(len, source_info)
.expect("len must be const");
- let len = match len.0.to_immediate() {
- Immediate::Scalar(ScalarMaybeUndef::Scalar(Scalar::Bits {
+ let len = match self.ecx.read_scalar(len.0) {
+ Ok(ScalarMaybeUndef::Scalar(Scalar::Bits {
bits, ..
})) => bits,
- _ => bug!("const len not primitive: {:?}", len),
+ other => bug!("const len not primitive: {:?}", other),
};
let index = self
.eval_operand(index, source_info)
.expect("index must be const");
- let index = match index.0.to_immediate() {
- Immediate::Scalar(ScalarMaybeUndef::Scalar(Scalar::Bits {
+ let index = match self.ecx.read_scalar(index.0) {
+ Ok(ScalarMaybeUndef::Scalar(Scalar::Bits {
bits, ..
})) => bits,
- _ => bug!("const index not primitive: {:?}", index),
+ other => bug!("const index not primitive: {:?}", other),
};
format!(
"index out of bounds: \
use rustc::mir::*;
use rustc::mir::visit::*;
-use rustc::ty::{self, Instance, InstanceDef, Ty, TyCtxt};
+use rustc::ty::{self, Instance, InstanceDef, ParamEnv, Ty, TyCtxt};
use rustc::ty::subst::{Subst,Substs};
use std::collections::VecDeque;
// Only do inlining into fn bodies.
let id = self.tcx.hir.as_local_node_id(self.source.def_id).unwrap();
let body_owner_kind = self.tcx.hir.body_owner_kind(id);
+
if let (hir::BodyOwnerKind::Fn, None) = (body_owner_kind, self.source.promoted) {
for (bb, bb_data) in caller_mir.basic_blocks().iter_enumerated() {
- // Don't inline calls that are in cleanup blocks.
- if bb_data.is_cleanup { continue; }
-
- // Only consider direct calls to functions
- let terminator = bb_data.terminator();
- if let TerminatorKind::Call {
- func: ref op, .. } = terminator.kind {
- if let ty::FnDef(callee_def_id, substs) = op.ty(caller_mir, self.tcx).sty {
- if let Some(instance) = Instance::resolve(self.tcx,
- param_env,
- callee_def_id,
- substs) {
- let is_virtual =
- if let InstanceDef::Virtual(..) = instance.def {
- true
- } else {
- false
- };
-
- if !is_virtual {
- callsites.push_back(CallSite {
- callee: instance.def_id(),
- substs: instance.substs,
- bb,
- location: terminator.source_info
- });
- }
- }
- }
- }
+ if let Some(callsite) = self.get_valid_function_call(bb,
+ bb_data,
+ caller_mir,
+ param_env) {
+ callsites.push_back(callsite);
+ }
}
} else {
return;
let callee_mir = match self.tcx.try_optimized_mir(callsite.location.span,
callsite.callee) {
- Ok(callee_mir) if self.should_inline(callsite, callee_mir) => {
+ Ok(callee_mir) if self.consider_optimizing(callsite, callee_mir) => {
self.tcx.subst_and_normalize_erasing_regions(
&callsite.substs,
param_env,
// Add callsites from inlined function
for (bb, bb_data) in caller_mir.basic_blocks().iter_enumerated().skip(start) {
- // Only consider direct calls to functions
- let terminator = bb_data.terminator();
- if let TerminatorKind::Call {
- func: Operand::Constant(ref f), .. } = terminator.kind {
- if let ty::FnDef(callee_def_id, substs) = f.ty.sty {
- // Don't inline the same function multiple times.
- if callsite.callee != callee_def_id {
- callsites.push_back(CallSite {
- callee: callee_def_id,
- substs,
- bb,
- location: terminator.source_info
- });
- }
+ if let Some(new_callsite) = self.get_valid_function_call(bb,
+ bb_data,
+ caller_mir,
+ param_env) {
+ // Don't inline the same function multiple times.
+ if callsite.callee != new_callsite.callee {
+ callsites.push_back(new_callsite);
}
}
}
}
}
+ fn get_valid_function_call(&self,
+ bb: BasicBlock,
+ bb_data: &BasicBlockData<'tcx>,
+ caller_mir: &Mir<'tcx>,
+ param_env: ParamEnv<'tcx>,
+ ) -> Option<CallSite<'tcx>> {
+ // Don't inline calls that are in cleanup blocks.
+ if bb_data.is_cleanup { return None; }
+
+ // Only consider direct calls to functions
+ let terminator = bb_data.terminator();
+ if let TerminatorKind::Call { func: ref op, .. } = terminator.kind {
+ if let ty::FnDef(callee_def_id, substs) = op.ty(caller_mir, self.tcx).sty {
+ let instance = Instance::resolve(self.tcx,
+ param_env,
+ callee_def_id,
+ substs)?;
+
+ if let InstanceDef::Virtual(..) = instance.def {
+ return None;
+ }
+
+ return Some(CallSite {
+ callee: instance.def_id(),
+ substs: instance.substs,
+ bb,
+ location: terminator.source_info
+ });
+ }
+ }
+
+ None
+ }
+
+ fn consider_optimizing(&self,
+ callsite: CallSite<'tcx>,
+ callee_mir: &Mir<'tcx>)
+ -> bool
+ {
+ debug!("consider_optimizing({:?})", callsite);
+ self.should_inline(callsite, callee_mir)
+ && self.tcx.consider_optimizing(|| format!("Inline {:?} into {:?}",
+ callee_mir.span,
+ callsite))
+ }
+
fn should_inline(&self,
callsite: CallSite<'tcx>,
callee_mir: &Mir<'tcx>)
match statement.kind {
StatementKind::Assign(_, box Rvalue::Ref(_, _, ref mut place)) => {
// Find the underlying local for this (necessarily interior) borrow.
- // HACK(eddyb) using a recursive function because of mutable borrows.
- fn interior_base<'a, 'tcx>(place: &'a mut Place<'tcx>)
- -> &'a mut Place<'tcx> {
- if let Place::Projection(ref mut proj) = *place {
- assert_ne!(proj.elem, ProjectionElem::Deref);
- return interior_base(&mut proj.base);
- }
- place
- }
- let place = interior_base(place);
+ let mut place = place;
+ while let Place::Projection(ref mut proj) = *place {
+ assert_ne!(proj.elem, ProjectionElem::Deref);
+ place = &mut proj.base;
+ };
let ty = place.ty(local_decls, self.tcx).to_ty(self.tcx);
let span = statement.source_info.span;
| "overflowing_mul"
| "unchecked_shl"
| "unchecked_shr"
+ | "rotate_left"
+ | "rotate_right"
| "add_with_overflow"
| "sub_with_overflow"
| "mul_with_overflow"
[dependencies]
alloc = { path = "../liballoc" }
-alloc_system = { path = "../liballoc_system" }
core = { path = "../libcore" }
compiler_builtins = { path = "../rustc/compiler_builtins_shim" }
// except according to those terms.
#![sanitizer_runtime]
-#![feature(alloc_system)]
#![feature(nll)]
#![feature(sanitizer_runtime)]
#![feature(staged_api)]
#![unstable(feature = "sanitizer_runtime_lib",
reason = "internal implementation detail of sanitizers",
issue = "0")]
-
-extern crate alloc_system;
-
-use alloc_system::System;
-
-#[global_allocator]
-static ALLOC: System = System;
binding.map(|binding| (binding, Flags::MODULE, Flags::empty()))
}
WhereToResolve::MacroUsePrelude => {
- match self.macro_use_prelude.get(&ident.name).cloned() {
- Some(binding) => Ok((binding, Flags::PRELUDE, Flags::empty())),
- None => Err(Determinacy::Determined),
+ let mut result = Err(Determinacy::Determined);
+ if use_prelude || self.session.rust_2015() {
+ if let Some(binding) = self.macro_use_prelude.get(&ident.name).cloned() {
+ result = Ok((binding, Flags::PRELUDE, Flags::empty()));
+ }
}
+ result
}
WhereToResolve::BuiltinMacros => {
match self.builtin_macros.get(&ident.name).cloned() {
}
}
WhereToResolve::LegacyPluginHelpers => {
- if self.session.plugin_attributes.borrow().iter()
+ if (use_prelude || self.session.rust_2015()) &&
+ self.session.plugin_attributes.borrow().iter()
.any(|(name, _)| ident.name == &**name) {
let binding = (Def::NonMacroAttr(NonMacroAttrKind::LegacyPluginHelper),
ty::Visibility::Public, ident.span, Mark::root())
pub aggregate_align: Align,
/// Alignments for vector types.
- pub vector_align: Vec<(Size, Align)>
+ pub vector_align: Vec<(Size, Align)>,
+ pub instruction_address_space: u32,
}
impl Default for TargetDataLayout {
vector_align: vec![
(Size::from_bits(64), Align::from_bits(64, 64).unwrap()),
(Size::from_bits(128), Align::from_bits(128, 128).unwrap())
- ]
+ ],
+ instruction_address_space: 0,
}
}
}
impl TargetDataLayout {
pub fn parse(target: &Target) -> Result<TargetDataLayout, String> {
+ // Parse an address space index from a string.
+ let parse_address_space = |s: &str, cause: &str| {
+ s.parse::<u32>().map_err(|err| {
+ format!("invalid address space `{}` for `{}` in \"data-layout\": {}",
+ s, cause, err)
+ })
+ };
+
// Parse a bit count from a string.
let parse_bits = |s: &str, kind: &str, cause: &str| {
s.parse::<u64>().map_err(|err| {
match spec.split(':').collect::<Vec<_>>()[..] {
["e"] => dl.endian = Endian::Little,
["E"] => dl.endian = Endian::Big,
+ [p] if p.starts_with("P") => {
+ dl.instruction_address_space = parse_address_space(&p[1..], "P")?
+ }
["a", ref a..] => dl.aggregate_align = align(a, "a")?,
["f32", ref a..] => dl.f32_align = align(a, "f32")?,
["f64", ref a..] => dl.f64_align = align(a, "f64")?,
let mut base = super::freebsd_base::opts();
base.max_atomic_width = Some(128);
- // see #36994
- base.exe_allocation_crate = None;
-
Ok(Target {
llvm_target: "aarch64-unknown-freebsd".to_string(),
target_endian: "little".to_string(),
let mut base = super::linux_base::opts();
base.max_atomic_width = Some(128);
- // see #36994
- base.exe_allocation_crate = None;
-
Ok(Target {
llvm_target: "aarch64-unknown-linux-gnu".to_string(),
target_endian: "little".to_string(),
let mut base = super::linux_musl_base::opts();
base.max_atomic_width = Some(128);
- // see #36994
- base.exe_allocation_crate = None;
-
Ok(Target {
llvm_target: "aarch64-unknown-linux-musl".to_string(),
target_endian: "little".to_string(),
]);
TargetOptions {
- exe_allocation_crate: None,
executables: true,
has_elf_tls: true,
linker_is_gnu: true,
TargetOptions {
executables: true,
has_elf_tls: false,
- exe_allocation_crate: None,
panic_strategy: PanicStrategy::Abort,
linker: Some("ld".to_string()),
pre_link_args: args,
// argument is *not* necessary for normal builds, but it can't hurt!
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,--eh-frame-hdr".to_string());
- // There's a whole bunch of circular dependencies when dealing with MUSL
- // unfortunately. To put this in perspective libc is statically linked to
- // liblibc and libunwind is statically linked to libstd:
- //
- // * libcore depends on `fmod` which is in libc (transitively in liblibc).
- // liblibc, however, depends on libcore.
- // * compiler-rt has personality symbols that depend on libunwind, but
- // libunwind is in libstd which depends on compiler-rt.
- //
- // Recall that linkers discard libraries and object files as much as
- // possible, and with all the static linking and archives flying around with
- // MUSL the linker is super aggressively stripping out objects. For example
- // the first case has fmod stripped from liblibc (it's in its own object
- // file) so it's not there when libcore needs it. In the second example all
- // the unused symbols from libunwind are stripped (each is in its own object
- // file in libstd) before we end up linking compiler-rt which depends on
- // those symbols.
- //
- // To deal with these circular dependencies we just force the compiler to
- // link everything as a group, not stripping anything out until everything
- // is processed. The linker will still perform a pass to strip out object
- // files but it won't do so until all objects/archives have been processed.
- base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,-(".to_string());
- base.post_link_args.insert(LinkerFlavor::Gcc, vec!["-Wl,-)".to_string()]);
-
// When generating a statically linked executable there's generally some
// small setup needed which is listed in these files. These are provided by
// a musl toolchain and are linked by default by the `musl-gcc` script. Note
features: "+mips64r2".to_string(),
max_atomic_width: Some(64),
- // see #36994
- exe_allocation_crate: None,
-
..super::linux_base::opts()
},
})
features: "+mips64r2".to_string(),
max_atomic_width: Some(64),
- // see #36994
- exe_allocation_crate: None,
-
..super::linux_base::opts()
},
})
features: "+mips32r2,+fpxx,+nooddspreg".to_string(),
max_atomic_width: Some(32),
- // see #36994
- exe_allocation_crate: None,
-
..super::linux_base::opts()
},
})
base.cpu = "mips32r2".to_string();
base.features = "+mips32r2,+soft-float".to_string();
base.max_atomic_width = Some(32);
- // see #36994
- base.exe_allocation_crate = None;
base.crt_static_default = false;
Ok(Target {
llvm_target: "mips-unknown-linux-musl".to_string(),
features: "+mips32r2,+soft-float".to_string(),
max_atomic_width: Some(32),
- // see #36994
- exe_allocation_crate: None,
-
..super::linux_base::opts()
},
})
features: "+mips32r2,+fpxx,+nooddspreg".to_string(),
max_atomic_width: Some(32),
- // see #36994
- exe_allocation_crate: None,
-
..super::linux_base::opts()
},
})
base.cpu = "mips32r2".to_string();
base.features = "+mips32r2,+soft-float".to_string();
base.max_atomic_width = Some(32);
- // see #36994
- base.exe_allocation_crate = None;
base.crt_static_default = false;
Ok(Target {
llvm_target: "mipsel-unknown-linux-musl".to_string(),
features: "+mips32r2,+soft-float".to_string(),
max_atomic_width: Some(32),
- // see #36994
- exe_allocation_crate: None,
-
..super::linux_base::opts()
},
})
/// `eh_unwind_resume` lang item.
pub custom_unwind_resume: bool,
- /// If necessary, a different crate to link exe allocators by default
- pub exe_allocation_crate: Option<String>,
-
/// Flag indicating whether ELF TLS (e.g. #[thread_local]) is available for
/// this target.
pub has_elf_tls: bool,
link_env: Vec::new(),
archive_format: "gnu".to_string(),
custom_unwind_resume: false,
- exe_allocation_crate: None,
allow_asm: true,
has_elf_tls: false,
obj_is_bitcode: false,
key!(archive_format);
key!(allow_asm, bool);
key!(custom_unwind_resume, bool);
- key!(exe_allocation_crate, optional);
key!(has_elf_tls, bool);
key!(obj_is_bitcode, bool);
key!(no_integrated_as, bool);
target_option_val!(archive_format);
target_option_val!(allow_asm);
target_option_val!(custom_unwind_resume);
- target_option_val!(exe_allocation_crate);
target_option_val!(has_elf_tls);
target_option_val!(obj_is_bitcode);
target_option_val!(no_integrated_as);
// for now. https://github.com/rust-lang/rust/pull/43170#issuecomment-315411474
base.relro_level = RelroLevel::Partial;
- // see #36994
- base.exe_allocation_crate = None;
-
Ok(Target {
llvm_target: "powerpc64-unknown-linux-gnu".to_string(),
target_endian: "big".to_string(),
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
base.max_atomic_width = Some(64);
- // see #36994
- base.exe_allocation_crate = None;
-
Ok(Target {
llvm_target: "powerpc64le-unknown-linux-gnu".to_string(),
target_endian: "little".to_string(),
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
base.max_atomic_width = Some(64);
- // see #36994
- base.exe_allocation_crate = None;
-
Ok(Target {
llvm_target: "powerpc64le-unknown-linux-musl".to_string(),
target_endian: "little".to_string(),
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
base.max_atomic_width = Some(32);
- // see #36994
- base.exe_allocation_crate = None;
-
Ok(Target {
llvm_target: "powerpc-unknown-linux-gnu".to_string(),
target_endian: "big".to_string(),
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mspe".to_string());
base.max_atomic_width = Some(32);
- // see #36994
- base.exe_allocation_crate = None;
-
Ok(Target {
llvm_target: "powerpc-unknown-linux-gnuspe".to_string(),
target_endian: "big".to_string(),
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
base.max_atomic_width = Some(32);
- // see #36994
- base.exe_allocation_crate = None;
-
Ok(Target {
llvm_target: "powerpc-unknown-netbsd".to_string(),
target_endian: "big".to_string(),
// Pass the -vector feature string to LLVM to respect this assumption.
base.features = "-vector".to_string();
base.max_atomic_width = Some(64);
- // see #36994
- base.exe_allocation_crate = None;
base.min_global_align = Some(16);
Ok(Target {
let mut base = super::linux_base::opts();
base.cpu = "v9".to_string();
base.max_atomic_width = Some(64);
- base.exe_allocation_crate = None;
Ok(Target {
llvm_target: "sparc64-unknown-linux-gnu".to_string(),
base.cpu = "v9".to_string();
base.max_atomic_width = Some(64);
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mv8plus".to_string());
- base.exe_allocation_crate = None;
Ok(Target {
llvm_target: "sparc-unknown-linux-gnu".to_string(),
// llvm calls this "v9"
base.cpu = "v9".to_string();
base.max_atomic_width = Some(64);
- base.exe_allocation_crate = None;
Ok(Target {
llvm_target: "sparcv9-sun-solaris".to_string(),
use super::{LinkArgs, LinkerFlavor, Target, TargetOptions};
pub fn target() -> Result<Target, String> {
+ // FIXME(nikic) BINARYEN_TRAP_MODE=clamp is needed to avoid trapping in our
+ // -Zsaturating-float-casts implementation. This can be dropped if/when
+ // we have native fpto[su]i.sat intrinsics, or the implementation otherwise
+ // stops relying on non-trapping fpto[su]i.
let mut post_link_args = LinkArgs::new();
post_link_args.insert(LinkerFlavor::Em,
vec!["-s".to_string(),
"BINARYEN=1".to_string(),
"-s".to_string(),
- "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()]);
+ "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string(),
+ "-s".to_string(),
+ "BINARYEN_TRAP_MODE='clamp'".to_string()]);
let opts = TargetOptions {
dynamic_linking: false,
base.has_rpath = false;
base.position_independent_executables = false;
base.disable_redzone = true;
- base.exe_allocation_crate = None;
base.stack_probes = true;
Ok(Target {
use rustc::ty::outlives::Component;
use rustc::ty::query::Providers;
use rustc::ty::wf;
+use smallvec::{SmallVec, smallvec};
use syntax::ast::DUMMY_NODE_ID;
use syntax::source_map::DUMMY_SP;
use rustc::traits::FulfillmentContext;
None => vec![],
Some(ty::OutlivesPredicate(ty_a, r_b)) => {
let ty_a = infcx.resolve_type_vars_if_possible(&ty_a);
- let components = tcx.outlives_components(ty_a);
+ let mut components = smallvec![];
+ tcx.push_outlives_components(ty_a, &mut components);
implied_bounds_from_components(r_b, components)
}
},
/// those relationships.
fn implied_bounds_from_components(
sub_region: ty::Region<'tcx>,
- sup_components: Vec<Component<'tcx>>,
+ sup_components: SmallVec<[Component<'tcx>; 4]>,
) -> Vec<OutlivesBound<'tcx>> {
sup_components
.into_iter()
debug!("relate_type_and_user_type: ty of def-id is {:?}", ty);
let ty = self.normalize(ty);
- let mut projected_ty = PlaceTy::from_ty(ty);
+ // We need to follow any provided projetions into the type.
+ //
+ // if we hit a ty var as we descend, then just skip the
+ // attempt to relate the mir local with any type.
+
+ struct HitTyVar;
+ let mut curr_projected_ty: Result<PlaceTy, HitTyVar>;
+ curr_projected_ty = Ok(PlaceTy::from_ty(ty));
for proj in projs {
- projected_ty = projected_ty.projection_ty_core(
+ let projected_ty = if let Ok(projected_ty) = curr_projected_ty {
+ projected_ty
+ } else {
+ break;
+ };
+ curr_projected_ty = projected_ty.projection_ty_core(
tcx, proj, |this, field, &()| {
- let ty = this.field_ty(tcx, field);
- self.normalize(ty)
+ if this.to_ty(tcx).is_ty_var() {
+ Err(HitTyVar)
+ } else {
+ let ty = this.field_ty(tcx, field);
+ Ok(self.normalize(ty))
+ }
});
}
- let ty = projected_ty.to_ty(tcx);
- self.relate(mir_ty, variance, ty)?;
+ if let Ok(projected_ty) = curr_projected_ty {
+ let ty = projected_ty.to_ty(tcx);
+ self.relate(mir_ty, variance, ty)?;
+ }
if let Some(UserSelfTy {
impl_def_id,
[dependencies]
alloc = { path = "../liballoc" }
-alloc_system = { path = "../liballoc_system" }
core = { path = "../libcore" }
compiler_builtins = { path = "../rustc/compiler_builtins_shim" }
// except according to those terms.
#![sanitizer_runtime]
-#![feature(alloc_system)]
#![feature(nll)]
#![feature(sanitizer_runtime)]
#![feature(staged_api)]
#![unstable(feature = "sanitizer_runtime_lib",
reason = "internal implementation detail of sanitizers",
issue = "0")]
-
-extern crate alloc_system;
-
-use alloc_system::System;
-
-#[global_allocator]
-static ALLOC: System = System;
use syntax::ast;
use syntax::ptr::P;
use syntax::feature_gate::{GateIssue, emit_feature_err};
-use syntax_pos::{Span, MultiSpan};
+use syntax_pos::{DUMMY_SP, Span, MultiSpan};
pub trait AstConv<'gcx, 'tcx> {
fn tcx<'a>(&'a self) -> TyCtxt<'a, 'gcx, 'tcx>;
}
// We manually build up the substitution, rather than using convenience
- // methods in subst.rs so that we can iterate over the arguments and
+ // methods in `subst.rs` so that we can iterate over the arguments and
// parameters in lock-step linearly, rather than trying to match each pair.
let mut substs: SmallVec<[Kind<'tcx>; 8]> = SmallVec::with_capacity(count);
}
}
- // (Unless it's been handled in `parent_substs`) `Self` is handled first.
+ // `Self` is handled first, unless it's been handled in `parent_substs`.
if has_self {
if let Some(¶m) = params.peek() {
if param.index == 0 {
trait_ref.path.segments.last().unwrap())
}
- /// Get the DefId of the given trait ref. It _must_ actually be a trait.
+ /// Get the `DefId` of the given trait ref. It _must_ actually be a trait.
fn trait_def_id(&self, trait_ref: &hir::TraitRef) -> DefId {
let path = &trait_ref.path;
match path.def {
}
}
- /// The given `trait_ref` must actually be trait.
+ /// The given trait ref must actually be a trait.
pub(super) fn instantiate_poly_trait_ref_inner(&self,
trait_ref: &hir::TraitRef,
self_ty: Ty<'tcx>,
let predicate: Result<_, ErrorReported> =
self.ast_type_binding_to_poly_projection_predicate(
trait_ref.ref_id, poly_trait_ref, binding, speculative, &mut dup_bindings);
- // ok to ignore Err because ErrorReported (see above)
+ // okay to ignore Err because of ErrorReported (see above)
Some((predicate.ok()?, binding.span))
}));
let tcx = self.tcx();
if !speculative {
- // Given something like `U : SomeTrait<T=X>`, we want to produce a
+ // Given something like `U: SomeTrait<T = X>`, we want to produce a
// predicate like `<U as SomeTrait>::T = X`. This is somewhat
// subtle in the event that `T` is defined in a supertrait of
// `SomeTrait`, because in that case we need to upcast.
// That is, consider this case:
//
// ```
- // trait SubTrait : SuperTrait<int> { }
+ // trait SubTrait: SuperTrait<int> { }
// trait SuperTrait<A> { type T; }
//
// ... B : SubTrait<T=foo> ...
if !speculative {
dup_bindings.entry(assoc_ty.def_id)
.and_modify(|prev_span| {
- let mut err = self.tcx().struct_span_lint_node(
- ::rustc::lint::builtin::DUPLICATE_ASSOCIATED_TYPE_BINDINGS,
- ref_id,
- binding.span,
- &format!("associated type binding `{}` specified more than once",
- binding.item_name)
- );
- err.span_label(binding.span, "used more than once");
- err.span_label(*prev_span, format!("first use of `{}`", binding.item_name));
- err.emit();
+ struct_span_err!(self.tcx().sess, binding.span, E0719,
+ "the value of the associated type `{}` (from the trait `{}`) \
+ is already specified",
+ binding.item_name,
+ tcx.item_path_str(assoc_ty.container.id()))
+ .span_label(binding.span, "re-bound here")
+ .span_label(*prev_span, format!("`{}` bound here first", binding.item_name))
+ .emit();
})
.or_insert(binding.span);
}
return tcx.types.err;
}
- let mut projection_bounds = vec![];
+ let mut projection_bounds = Vec::new();
let dummy_self = tcx.mk_ty(TRAIT_OBJECT_DUMMY_SELF);
let principal = self.instantiate_poly_trait_ref(&trait_bounds[0],
dummy_self,
.emit();
}
- // Erase the dummy_self (TRAIT_OBJECT_DUMMY_SELF) used above.
- let existential_principal = principal.map_bound(|trait_ref| {
- self.trait_ref_to_existential(trait_ref)
- });
- let existential_projections = projection_bounds.iter().map(|(bound, _)| {
- bound.map_bound(|b| {
- let trait_ref = self.trait_ref_to_existential(b.projection_ty.trait_ref(tcx));
- ty::ExistentialProjection {
- ty: b.ty,
- item_def_id: b.projection_ty.item_def_id,
- substs: trait_ref.substs,
- }
- })
- });
-
// Check that there are no gross object safety violations;
- // most importantly, that the supertraits don't contain Self,
+ // most importantly, that the supertraits don't contain `Self`,
// to avoid ICEs.
let object_safety_violations =
tcx.global_tcx().astconv_object_safety_violations(principal.def_id());
return tcx.types.err;
}
- // Use a BTreeSet to keep output in a more consistent order.
+ // Use a `BTreeSet` to keep output in a more consistent order.
let mut associated_types = BTreeSet::default();
- for tr in traits::supertraits(tcx, principal) {
- associated_types.extend(tcx.associated_items(tr.def_id())
- .filter(|item| item.kind == ty::AssociatedKind::Type)
- .map(|item| item.def_id));
+ for tr in traits::elaborate_trait_ref(tcx, principal) {
+ match tr {
+ ty::Predicate::Trait(pred) => {
+ associated_types.extend(tcx.associated_items(pred.def_id())
+ .filter(|item| item.kind == ty::AssociatedKind::Type)
+ .map(|item| item.def_id));
+ }
+ ty::Predicate::Projection(pred) => {
+ // Include projections defined on supertraits.
+ projection_bounds.push((pred, DUMMY_SP))
+ }
+ _ => ()
+ }
}
for (projection_bound, _) in &projection_bounds {
.emit();
}
+ // Erase the `dummy_self` (`TRAIT_OBJECT_DUMMY_SELF`) used above.
+ let existential_principal = principal.map_bound(|trait_ref| {
+ self.trait_ref_to_existential(trait_ref)
+ });
+ let existential_projections = projection_bounds.iter().map(|(bound, _)| {
+ bound.map_bound(|b| {
+ let trait_ref = self.trait_ref_to_existential(b.projection_ty.trait_ref(tcx));
+ ty::ExistentialProjection {
+ ty: b.ty,
+ item_def_id: b.projection_ty.item_def_id,
+ substs: trait_ref.substs,
+ }
+ })
+ });
+
// Dedup auto traits so that `dyn Trait + Send + Send` is the same as `dyn Trait + Send`.
auto_traits.sort();
auto_traits.dedup();
- // skip_binder is okay, because the predicates are re-bound.
+ // Calling `skip_binder` is okay, because the predicates are re-bound.
let mut v =
iter::once(ty::ExistentialPredicate::Trait(*existential_principal.skip_binder()))
.chain(auto_traits.into_iter().map(ty::ExistentialPredicate::AutoTrait))
span)
}
-
- // Checks that bounds contains exactly one element and reports appropriate
+ // Checks that `bounds` contains exactly one element and reports appropriate
// errors otherwise.
fn one_bound_for_assoc_type<I>(&self,
mut bounds: I,
}
// Create a type from a path to an associated type.
- // For a path A::B::C::D, ty and ty_path_def are the type and def for A::B::C
- // and item_segment is the path segment for D. We return a type and a def for
+ // For a path `A::B::C::D`, `ty` and `ty_path_def` are the type and def for `A::B::C`
+ // and item_segment is the path segment for `D`. We return a type and a def for
// the whole path.
- // Will fail except for T::A and Self::A; i.e., if ty/ty_path_def are not a type
- // parameter or Self.
+ // Will fail except for `T::A` and `Self::A`; i.e., if `ty`/`ty_path_def` are not a type
+ // parameter or `Self`.
pub fn associated_path_def_to_ty(&self,
ref_id: ast::NodeId,
span: Span,
// item is declared.
let bound = match (&ty.sty, ty_path_def) {
(_, Def::SelfTy(Some(_), Some(impl_def_id))) => {
- // `Self` in an impl of a trait - we have a concrete self type and a
+ // `Self` in an impl of a trait - we have a concrete `self` type and a
// trait reference.
let trait_ref = match tcx.impl_trait_ref(impl_def_id) {
Some(trait_ref) => trait_ref,
let span = path.span;
match path.def {
Def::Existential(did) => {
- // check for desugared impl trait
+ // Check for desugared impl trait.
assert!(ty::is_impl_trait_defn(tcx, did).is_none());
let item_segment = path.segments.split_last().unwrap();
self.prohibit_generics(item_segment.1);
tcx.mk_ty_param(index, tcx.hir.name(node_id).as_interned_str())
}
Def::SelfTy(_, Some(def_id)) => {
- // Self in impl (we know the concrete type).
+ // `Self` in impl (we know the concrete type)
assert_eq!(opt_self_ty, None);
self.prohibit_generics(&path.segments);
tcx.at(span).type_of(def_id)
}
Def::SelfTy(Some(_), None) => {
- // Self in trait.
+ // `Self` in trait
assert_eq!(opt_self_ty, None);
self.prohibit_generics(&path.segments);
tcx.mk_self_type()
let discrim_diverges = self.diverges.get();
self.diverges.set(Diverges::Maybe);
- // Typecheck the patterns first, so that we get types for all the
- // bindings.
- let all_arm_pats_diverge = arms.iter().map(|arm| {
+ // rust-lang/rust#55810: Typecheck patterns first (via eager
+ // collection into `Vec`), so we get types for all bindings.
+ let all_arm_pats_diverge: Vec<_> = arms.iter().map(|arm| {
let mut all_pats_diverge = Diverges::WarnedAlways;
for p in &arm.pats {
self.diverges.set(Diverges::Maybe);
Diverges::Maybe => Diverges::Maybe,
Diverges::Always | Diverges::WarnedAlways => Diverges::WarnedAlways,
}
- });
+ }).collect();
// Now typecheck the blocks.
//
report_unexpected_def(def);
return self.tcx.types.err;
}
- // Replace constructor type with constructed type for tuple struct patterns.
- let pat_ty = pat_ty.fn_sig(tcx).output();
- let pat_ty = pat_ty.no_bound_vars().expect("expected fn type");
-
- self.demand_eqtype(pat.span, expected, pat_ty);
let variant = match def {
Def::Err => {
}
_ => bug!("unexpected pattern definition: {:?}", def)
};
+
+ // Replace constructor type with constructed type for tuple struct patterns.
+ let pat_ty = pat_ty.fn_sig(tcx).output();
+ let pat_ty = pat_ty.no_bound_vars().expect("expected fn type");
+
+ self.demand_eqtype(pat.span, expected, pat_ty);
+
// Type check subpatterns.
if subpats.len() == variant.fields.len() ||
subpats.len() < variant.fields.len() && ddpos.is_some() {
"unchecked_div" | "unchecked_rem" | "exact_div" =>
(1, vec![param(0), param(0)], param(0)),
- "unchecked_shl" | "unchecked_shr" =>
+ "unchecked_shl" | "unchecked_shr" |
+ "rotate_left" | "rotate_right" =>
(1, vec![param(0), param(0)], param(0)),
"overflowing_add" | "overflowing_sub" | "overflowing_mul" =>
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
use rustc::hir;
-/// Helper type of a temporary returned by .for_item(...).
+/// Helper type of a temporary returned by `.for_item(...)`.
/// Necessary because we can't write the following bound:
-/// F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(FnCtxt<'b, 'gcx, 'tcx>).
+/// `F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(FnCtxt<'b, 'gcx, 'tcx>)`.
struct CheckWfFcxBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
inherited: super::InheritedBuilder<'a, 'gcx, 'tcx>,
id: ast::NodeId,
item_id: ast::NodeId,
span: Span,
sig_if_method: Option<&hir::MethodSig>) {
+ debug!("check_associated_item: {:?}", item_id);
+
let code = ObligationCauseCode::MiscObligation;
for_id(tcx, item_id, span).with_fcx(|fcx, tcx| {
let item = fcx.tcx.associated_item(fcx.tcx.hir.local_def_id(item_id));
}
fn check_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item: &hir::Item) {
+ debug!("check_trait: {:?}", item.id);
+
let trait_def_id = tcx.hir.local_def_id(item.id);
let trait_def = tcx.trait_def(trait_def_id);
}
None => {
- // Inherent impl: take implied bounds from the self type.
+ // Inherent impl: take implied bounds from the `self` type.
let self_ty = self.tcx.type_of(impl_def_id);
let self_ty = self.normalize_associated_types_in(span, &self_ty);
vec![self_ty]
No,
}
-/// Translate the AST's notion of ty param bounds (which are an enum consisting of a newtyped Ty or
-/// a region) to ty's notion of ty param bounds, which can either be user-defined traits, or the
-/// built-in trait (formerly known as kind): Send.
+/// Translate the AST's notion of ty param bounds (which are an enum consisting of a newtyped `Ty`
+/// or a region) to ty's notion of ty param bounds, which can either be user-defined traits, or the
+/// built-in trait `Send`.
pub fn compute_bounds<'gcx: 'tcx, 'tcx>(
astconv: &dyn AstConv<'gcx, 'tcx>,
param_ty: Ty<'tcx>,
sized_by_default: SizedByDefault,
span: Span,
) -> Bounds<'tcx> {
- let mut region_bounds = vec![];
- let mut trait_bounds = vec![];
+ let mut region_bounds = Vec::new();
+ let mut trait_bounds = Vec::new();
for ast_bound in ast_bounds {
match *ast_bound {
}
}
- let mut projection_bounds = vec![];
+ let mut projection_bounds = Vec::new();
let mut trait_bounds: Vec<_> = trait_bounds.iter().map(|&bound| {
(astconv.instantiate_poly_trait_ref(bound, param_ty, &mut projection_bounds), bound.span)
E0641, // cannot cast to/from a pointer with an unknown kind
E0645, // trait aliases not finished
E0698, // type inside generator must be known in this context
+ E0719, // duplicate values for associated type binding
}
use rustc::ty::outlives::Component;
use rustc::ty::subst::{Kind, UnpackedKind};
use rustc::ty::{self, Region, RegionKind, Ty, TyCtxt};
+use smallvec::smallvec;
use std::collections::BTreeSet;
/// Tracks the `T: 'a` or `'a: 'a` predicates that we have inferred
//
// Or if within `struct Foo<U>` you had `T = Vec<U>`, then
// we would want to add `U: 'outlived_region`
- for component in tcx.outlives_components(ty) {
+ let mut components = smallvec![];
+ tcx.push_outlives_components(ty, &mut components);
+ for component in components {
match component {
Component::Region(r) => {
// This would arise from something like:
// forcefully don't inline if this is not public or if the
// #[doc(no_inline)] attribute is present.
// Don't inline doc(hidden) imports so they can be stripped at a later stage.
- let denied = !self.vis.node.is_pub() || self.attrs.iter().any(|a| {
+ let mut denied = !self.vis.node.is_pub() || self.attrs.iter().any(|a| {
a.name() == "doc" && match a.meta_item_list() {
Some(l) => attr::list_contains_name(&l, "no_inline") ||
attr::list_contains_name(&l, "hidden"),
None => false,
}
});
+ // Also check whether imports were asked to be inlined, in case we're trying to re-export a
+ // crate in Rust 2018+
+ let please_inline = self.attrs.lists("doc").has_word("inline");
let path = self.path.clean(cx);
let inner = if self.glob {
if !denied {
Import::Glob(resolve_use_source(cx, path))
} else {
let name = self.name;
+ if !please_inline {
+ match path.def {
+ Def::Mod(did) => if !did.is_local() && did.index == CRATE_DEF_INDEX {
+ // if we're `pub use`ing an extern crate root, don't inline it unless we
+ // were specifically asked for it
+ denied = true;
+ }
+ _ => {}
+ }
+ }
if !denied {
let mut visited = FxHashSet::default();
if let Some(items) = inline::try_inline(cx, path.def, name, &mut visited) {
use externalfiles::ExternalHtml;
use html;
use html::markdown::IdMap;
+use html::static_files;
use opts;
use passes::{self, DefaultPassOption};
use theme;
let to_check = matches.opt_strs("theme-checker");
if !to_check.is_empty() {
- let paths = theme::load_css_paths(include_bytes!("html/static/themes/light.css"));
+ let paths = theme::load_css_paths(static_files::themes::LIGHT.as_bytes());
let mut errors = 0;
println!("rustdoc: [theme-checker] Starting tests!");
let mut themes = Vec::new();
if matches.opt_present("themes") {
- let paths = theme::load_css_paths(include_bytes!("html/static/themes/light.css"));
+ let paths = theme::load_css_paths(static_files::themes::LIGHT.as_bytes());
for (theme_file, theme_s) in matches.opt_strs("themes")
.iter()
use html::format::fmt_impl_for_trait_page;
use html::item_type::ItemType;
use html::markdown::{self, Markdown, MarkdownHtml, MarkdownSummaryLine, ErrorCodes, IdMap};
-use html::{highlight, layout};
+use html::{highlight, layout, static_files};
use minifier;
// overwrite them anyway to make sure that they're fresh and up-to-date.
write_minify(cx.dst.join(&format!("rustdoc{}.css", cx.shared.resource_suffix)),
- include_str!("static/rustdoc.css"),
+ static_files::RUSTDOC_CSS,
options.enable_minification)?;
write_minify(cx.dst.join(&format!("settings{}.css", cx.shared.resource_suffix)),
- include_str!("static/settings.css"),
+ static_files::SETTINGS_CSS,
options.enable_minification)?;
// To avoid "light.css" to be overwritten, we'll first run over the received themes and only
}
write(cx.dst.join(&format!("brush{}.svg", cx.shared.resource_suffix)),
- include_bytes!("static/brush.svg"))?;
+ static_files::BRUSH_SVG)?;
write(cx.dst.join(&format!("wheel{}.svg", cx.shared.resource_suffix)),
- include_bytes!("static/wheel.svg"))?;
+ static_files::WHEEL_SVG)?;
write_minify(cx.dst.join(&format!("light{}.css", cx.shared.resource_suffix)),
- include_str!("static/themes/light.css"),
+ static_files::themes::LIGHT,
options.enable_minification)?;
themes.insert("light".to_owned());
write_minify(cx.dst.join(&format!("dark{}.css", cx.shared.resource_suffix)),
- include_str!("static/themes/dark.css"),
+ static_files::themes::DARK,
options.enable_minification)?;
themes.insert("dark".to_owned());
)?;
write_minify(cx.dst.join(&format!("main{}.js", cx.shared.resource_suffix)),
- include_str!("static/main.js"),
+ static_files::MAIN_JS,
options.enable_minification)?;
write_minify(cx.dst.join(&format!("settings{}.js", cx.shared.resource_suffix)),
- include_str!("static/settings.js"),
+ static_files::SETTINGS_JS,
options.enable_minification)?;
{
let mut data = format!("var resourcesSuffix = \"{}\";\n",
cx.shared.resource_suffix);
- data.push_str(include_str!("static/storage.js"));
+ data.push_str(static_files::STORAGE_JS);
write_minify(cx.dst.join(&format!("storage{}.js", cx.shared.resource_suffix)),
&data,
options.enable_minification)?;
}
}
write_minify(cx.dst.join(&format!("normalize{}.css", cx.shared.resource_suffix)),
- include_str!("static/normalize.css"),
+ static_files::NORMALIZE_CSS,
options.enable_minification)?;
write(cx.dst.join("FiraSans-Regular.woff"),
- include_bytes!("static/FiraSans-Regular.woff"))?;
+ static_files::fira_sans::REGULAR)?;
write(cx.dst.join("FiraSans-Medium.woff"),
- include_bytes!("static/FiraSans-Medium.woff"))?;
+ static_files::fira_sans::MEDIUM)?;
write(cx.dst.join("FiraSans-LICENSE.txt"),
- include_bytes!("static/FiraSans-LICENSE.txt"))?;
+ static_files::fira_sans::LICENSE)?;
write(cx.dst.join("Heuristica-Italic.woff"),
- include_bytes!("static/Heuristica-Italic.woff"))?;
+ static_files::heuristica::ITALIC)?;
write(cx.dst.join("Heuristica-LICENSE.txt"),
- include_bytes!("static/Heuristica-LICENSE.txt"))?;
+ static_files::heuristica::LICENSE)?;
write(cx.dst.join("SourceSerifPro-Regular.woff"),
- include_bytes!("static/SourceSerifPro-Regular.woff"))?;
+ static_files::source_serif_pro::REGULAR)?;
write(cx.dst.join("SourceSerifPro-Bold.woff"),
- include_bytes!("static/SourceSerifPro-Bold.woff"))?;
+ static_files::source_serif_pro::BOLD)?;
write(cx.dst.join("SourceSerifPro-LICENSE.txt"),
- include_bytes!("static/SourceSerifPro-LICENSE.txt"))?;
+ static_files::source_serif_pro::LICENSE)?;
write(cx.dst.join("SourceCodePro-Regular.woff"),
- include_bytes!("static/SourceCodePro-Regular.woff"))?;
+ static_files::source_code_pro::REGULAR)?;
write(cx.dst.join("SourceCodePro-Semibold.woff"),
- include_bytes!("static/SourceCodePro-Semibold.woff"))?;
+ static_files::source_code_pro::SEMIBOLD)?;
write(cx.dst.join("SourceCodePro-LICENSE.txt"),
- include_bytes!("static/SourceCodePro-LICENSE.txt"))?;
+ static_files::source_code_pro::LICENSE)?;
write(cx.dst.join("LICENSE-MIT.txt"),
- include_bytes!("static/LICENSE-MIT.txt"))?;
+ static_files::LICENSE_MIT)?;
write(cx.dst.join("LICENSE-APACHE.txt"),
- include_bytes!("static/LICENSE-APACHE.txt"))?;
+ static_files::LICENSE_APACHE)?;
write(cx.dst.join("COPYRIGHT.txt"),
- include_bytes!("static/COPYRIGHT.txt"))?;
+ static_files::COPYRIGHT)?;
fn collect(path: &Path, krate: &str, key: &str) -> io::Result<(Vec<String>, Vec<String>)> {
let mut ret = Vec::new();
/* General structure and fonts */
body {
- font: 16px/1.4 "Source Serif Pro", Georgia, Times, "Times New Roman", serif;
+ font: 16px/1.4 "Source Serif Pro", serif;
margin: 0;
position: relative;
padding: 10px 15px 20px 15px;
h1, h2, h3, h4,
.sidebar, a.source, .search-input, .content table :not(code)>a,
.collapse-toggle, div.item-list .out-of-band {
- font-family: "Fira Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-family: "Fira Sans", sans-serif;
}
ol, ul {
}
code, pre {
- font-family: "Source Code Pro", Menlo, Monaco, Consolas, "DejaVu Sans Mono", Inconsolata, monospace;
+ font-family: "Source Code Pro", monospace;
white-space: pre-wrap;
}
.docblock code, .docblock-short code {
}
#main > .since {
top: inherit;
- font-family: "Fira Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-family: "Fira Sans", sans-serif;
}
.content table:not(.table-display) {
kbd {
display: inline-block;
padding: 3px 5px;
- font: 15px "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
+ font: 15px monospace;
line-height: 10px;
vertical-align: middle;
border: solid 1px;
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+//! Static files bundled with documentation output.
+//!
+//! All the static files are included here for centralized access in case anything other than the
+//! HTML rendering code (say, the theme checker) needs to access one of these files.
+//!
+//! Note about types: CSS and JavaScript files are included as `&'static str` to allow for the
+//! minifier to run on them. All other files are included as `&'static [u8]` so they can be
+//! directly written to a `Write` handle.
+
+/// The file contents of the main `rustdoc.css` file, responsible for the core layout of the page.
+pub static RUSTDOC_CSS: &'static str = include_str!("static/rustdoc.css");
+
+/// The file contents of `settings.css`, responsible for the items on the settings page.
+pub static SETTINGS_CSS: &'static str = include_str!("static/settings.css");
+
+/// The file contents of `normalize.css`, included to even out standard elements between browser
+/// implementations.
+pub static NORMALIZE_CSS: &'static str = include_str!("static/normalize.css");
+
+/// The file contents of `main.js`, which contains the core JavaScript used on documentation pages,
+/// including search behavior and docblock folding, among others.
+pub static MAIN_JS: &'static str = include_str!("static/main.js");
+
+/// The file contents of `settings.js`, which contains the JavaScript used to handle the settings
+/// page.
+pub static SETTINGS_JS: &'static str = include_str!("static/settings.js");
+
+/// The file contents of `storage.js`, which contains functionality related to browser Local
+/// Storage, used to store documentation settings.
+pub static STORAGE_JS: &'static str = include_str!("static/storage.js");
+
+/// The file contents of `brush.svg`, the icon used for the theme-switch button.
+pub static BRUSH_SVG: &'static [u8] = include_bytes!("static/brush.svg");
+
+/// The file contents of `wheel.svg`, the icon used for the settings button.
+pub static WHEEL_SVG: &'static [u8] = include_bytes!("static/wheel.svg");
+
+/// The contents of `COPYRIGHT.txt`, the license listing for files distributed with documentation
+/// output.
+pub static COPYRIGHT: &'static [u8] = include_bytes!("static/COPYRIGHT.txt");
+
+/// The contents of `LICENSE-APACHE.txt`, the text of the Apache License, version 2.0.
+pub static LICENSE_APACHE: &'static [u8] = include_bytes!("static/LICENSE-APACHE.txt");
+
+/// The contents of `LICENSE-MIT.txt`, the text of the MIT License.
+pub static LICENSE_MIT: &'static [u8] = include_bytes!("static/LICENSE-MIT.txt");
+
+/// The built-in themes given to every documentation site.
+pub mod themes {
+ /// The "light" theme, selected by default when no setting is available. Used as the basis for
+ /// the `--theme-checker` functionality.
+ pub static LIGHT: &'static str = include_str!("static/themes/light.css");
+
+ /// The "dark" theme.
+ pub static DARK: &'static str = include_str!("static/themes/dark.css");
+}
+
+/// Files related to the Fira Sans font.
+pub mod fira_sans {
+ /// The file `FiraSans-Regular.woff`, the Regular variant of the Fira Sans font.
+ pub static REGULAR: &'static [u8] = include_bytes!("static/FiraSans-Regular.woff");
+
+ /// The file `FiraSans-Medium.woff`, the Medium variant of the Fira Sans font.
+ pub static MEDIUM: &'static [u8] = include_bytes!("static/FiraSans-Medium.woff");
+
+ /// The file `FiraSans-LICENSE.txt`, the license text for the Fira Sans font.
+ pub static LICENSE: &'static [u8] = include_bytes!("static/FiraSans-LICENSE.txt");
+}
+
+/// Files related to the Heuristica font.
+pub mod heuristica {
+ /// The file `Heuristica-Italic.woff`, the Italic variant of the Heuristica font.
+ pub static ITALIC: &'static [u8] = include_bytes!("static/Heuristica-Italic.woff");
+
+ /// The file `Heuristica-LICENSE.txt`, the license text for the Heuristica font.
+ pub static LICENSE: &'static [u8] = include_bytes!("static/Heuristica-LICENSE.txt");
+}
+
+/// Files related to the Source Serif Pro font.
+pub mod source_serif_pro {
+ /// The file `SourceSerifPro-Regular.woff`, the Regular variant of the Source Serif Pro font.
+ pub static REGULAR: &'static [u8] = include_bytes!("static/SourceSerifPro-Regular.woff");
+
+ /// The file `SourceSerifPro-Bold.woff`, the Bold variant of the Source Serif Pro font.
+ pub static BOLD: &'static [u8] = include_bytes!("static/SourceSerifPro-Bold.woff");
+
+ /// The file `SourceSerifPro-LICENSE.txt`, the license text for the Source Serif Pro font.
+ pub static LICENSE: &'static [u8] = include_bytes!("static/SourceSerifPro-LICENSE.txt");
+}
+
+/// Files related to the Source Code Pro font.
+pub mod source_code_pro {
+ /// The file `SourceCodePro-Regular.woff`, the Regular variant of the Source Code Pro font.
+ pub static REGULAR: &'static [u8] = include_bytes!("static/SourceCodePro-Regular.woff");
+
+ /// The file `SourceCodePro-Semibold.woff`, the Semibold variant of the Source Code Pro font.
+ pub static SEMIBOLD: &'static [u8] = include_bytes!("static/SourceCodePro-Semibold.woff");
+
+ /// The file `SourceCodePro-LICENSE.txt`, the license text of the Source Code Pro font.
+ pub static LICENSE: &'static [u8] = include_bytes!("static/SourceCodePro-LICENSE.txt");
+}
crate mod layout;
pub mod markdown;
crate mod render;
+ crate mod static_files;
crate mod toc;
}
mod markdown;
[dependencies]
alloc = { path = "../liballoc" }
-alloc_system = { path = "../liballoc_system" }
panic_unwind = { path = "../libpanic_unwind", optional = true }
panic_abort = { path = "../libpanic_abort" }
core = { path = "../libcore" }
rustc_msan = { path = "../librustc_msan" }
rustc_tsan = { path = "../librustc_tsan" }
+[target.'cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))'.dependencies]
+dlmalloc = { path = '../rustc/dlmalloc_shim' }
+
[build-dependencies]
cc = "1.0"
build_helper = { path = "../build_helper" }
use core::sync::atomic::{AtomicPtr, Ordering};
use core::{mem, ptr};
+use core::ptr::NonNull;
use sys_common::util::dumb_print;
#[stable(feature = "alloc_module", since = "1.28.0")]
#[doc(inline)]
pub use alloc_crate::alloc::*;
+/// The default memory allocator provided by the operating system.
+///
+/// This is based on `malloc` on Unix platforms and `HeapAlloc` on Windows,
+/// plus related functions.
+///
+/// This type implements the `GlobalAlloc` trait and Rust programs by deafult
+/// work as if they had this definition:
+///
+/// ```rust
+/// use std::alloc::System;
+///
+/// #[global_allocator]
+/// static A: System = System;
+///
+/// fn main() {
+/// let a = Box::new(4); // Allocates from the system allocator.
+/// println!("{}", a);
+/// }
+/// ```
+///
+/// You can also define your own wrapper around `System` if you'd like, such as
+/// keeping track of the number of all bytes allocated:
+///
+/// ```rust
+/// use std::alloc::{System, GlobalAlloc, Layout};
+/// use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering::SeqCst};
+///
+/// struct Counter;
+///
+/// static ALLOCATED: AtomicUsize = ATOMIC_USIZE_INIT;
+///
+/// unsafe impl GlobalAlloc for Counter {
+/// unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+/// let ret = System.alloc(layout);
+/// if !ret.is_null() {
+/// ALLOCATED.fetch_add(layout.size(), SeqCst);
+/// }
+/// return ret
+/// }
+///
+/// unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+/// System.dealloc(ptr, layout);
+/// ALLOCATED.fetch_sub(layout.size(), SeqCst);
+/// }
+/// }
+///
+/// #[global_allocator]
+/// static A: Counter = Counter;
+///
+/// fn main() {
+/// println!("allocated bytes before main: {}", ALLOCATED.load(SeqCst));
+/// }
+/// ```
+///
+/// It can also be used directly to allocate memory independently of whatever
+/// global allocator has been selected for a Rust program. For example if a Rust
+/// program opts in to using jemalloc as the global allocator, `System` will
+/// still allocate memory using `malloc` and `HeapAlloc`.
#[stable(feature = "alloc_system_type", since = "1.28.0")]
-#[doc(inline)]
-pub use alloc_system::System;
+#[derive(Debug, Copy, Clone)]
+pub struct System;
+
+#[unstable(feature = "allocator_api", issue = "32838")]
+unsafe impl Alloc for System {
+ #[inline]
+ unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
+ NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr)
+ }
+
+ #[inline]
+ unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
+ NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr)
+ }
+
+ #[inline]
+ unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
+ GlobalAlloc::dealloc(self, ptr.as_ptr(), layout)
+ }
+
+ #[inline]
+ unsafe fn realloc(&mut self,
+ ptr: NonNull<u8>,
+ layout: Layout,
+ new_size: usize) -> Result<NonNull<u8>, AllocErr> {
+ NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr)
+ }
+}
static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());
/// [`CString`]: struct.CString.html
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn as_ptr(&self) -> *const c_char {
+ pub const fn as_ptr(&self) -> *const c_char {
self.inner.as_ptr()
}
///
/// If the contents of the `CStr` are valid UTF-8 data, this
/// function will return a [`Cow`]`::`[`Borrowed`]`(`[`&str`]`)`
- /// with the the corresponding [`&str`] slice. Otherwise, it will
+ /// with the corresponding [`&str`] slice. Otherwise, it will
/// replace any invalid UTF-8 sequences with
/// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD] and return a
/// [`Cow`]`::`[`Owned`]`(`[`String`]`)` with the result.
#![cfg_attr(test, feature(test, update_panic_count))]
#![feature(alloc)]
#![feature(alloc_error_handler)]
-#![feature(alloc_system)]
#![feature(allocator_api)]
#![feature(allocator_internals)]
#![feature(allow_internal_unsafe)]
#[cfg(stage0)]
#[global_allocator]
-static ALLOC: alloc_system::System = alloc_system::System;
+static ALLOC: alloc::System = alloc::System;
// Explicitly import the prelude. The compiler uses this same unstable attribute
// to import the prelude implicitly when building crates that depend on std.
#[allow(unused_imports)] // macros from `alloc` are not used on all platforms
#[macro_use]
extern crate alloc as alloc_crate;
-extern crate alloc_system;
#[doc(masked)]
extern crate libc;
// compiler
pub mod rt;
-// Pull in the the `stdsimd` crate directly into libstd. This is the same as
+// Pull in the `stdsimd` crate directly into libstd. This is the same as
// libcore's arch/simd modules where the source of truth here is in a different
// repository, but we pull things in here manually to get it into libstd.
//
/// For more information about select, see the `std::sync::mpsc::Select` structure.
#[macro_export]
#[unstable(feature = "mpsc_select", issue = "27800")]
+#[rustc_deprecated(since = "1.32.0",
+ reason = "channel selection will be removed in a future release")]
macro_rules! select {
(
$($name:pat = $rx:ident.$meth:ident() => $code:expr),+
/// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_unspecified(), false);
/// ```
#[stable(feature = "ip_shared", since = "1.12.0")]
- pub fn is_unspecified(&self) -> bool {
+ pub const fn is_unspecified(&self) -> bool {
self.inner.s_addr == 0
}
/// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_ip")]
pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16,
g: u16, h: u16) -> Ipv6Addr {
Ipv6Addr {
/// [255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
/// ```
#[stable(feature = "ipv6_to_octets", since = "1.12.0")]
- pub fn octets(&self) -> [u8; 16] {
+ pub const fn octets(&self) -> [u8; 16] {
self.inner.s6_addr
}
}
///
/// ```should_panic
/// use std::process::Command;
+ /// use std::io::{self, Write};
/// let output = Command::new("/bin/cat")
/// .arg("file.txt")
/// .output()
/// .expect("failed to execute process");
///
/// println!("status: {}", output.status);
- /// println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
- /// println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
+ /// io::stdout().write_all(&output.stdout).unwrap();
+ /// io::stderr().write_all(&output.stderr).unwrap();
///
/// assert!(output.status.success());
/// ```
///
/// ```no_run
/// use std::process::{Command, Stdio};
+ /// use std::io::{self, Write};
///
/// let output = Command::new("rev")
/// .stdin(Stdio::inherit())
/// .output()
/// .expect("Failed to execute command");
///
- /// println!("You piped in the reverse of: {}", String::from_utf8_lossy(&output.stdout));
+ /// print!("You piped in the reverse of: ");
+ /// io::stdout().write_all(&output.stdout).unwrap();
/// ```
#[stable(feature = "process", since = "1.0.0")]
pub fn inherit() -> Stdio { Stdio(imp::Stdio::Inherit) }
//! ```
#![stable(feature = "rust1", since = "1.0.0")]
+#![allow(deprecated)] // for mpsc_select
// A description of how Rust's channel implementation works
//
#![unstable(feature = "mpsc_select",
reason = "This implementation, while likely sufficient, is unsafe and \
likely to be error prone. At some point in the future this \
- module will likely be replaced, and it is currently \
- unknown how much API breakage that will cause. The ability \
- to select over a number of channels will remain forever, \
- but no guarantees beyond this are being made",
+ module will be removed.",
issue = "27800")]
+#![rustc_deprecated(since = "1.32.0",
+ reason = "channel selection will be removed in a future release")]
use fmt;
use libc;
use mem;
+#[path = "../unix/alloc.rs"]
+pub mod alloc;
pub mod args;
#[cfg(feature = "backtrace")]
pub mod backtrace;
pub use libc::strlen;
pub use self::rand::hashmap_random_keys;
+#[path = "../unix/alloc.rs"]
+pub mod alloc;
pub mod args;
#[cfg(feature = "backtrace")]
pub mod backtrace;
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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 ptr;
+use libc;
+use sys_common::alloc::{MIN_ALIGN, realloc_fallback};
+use alloc::{GlobalAlloc, Layout, System};
+
+#[stable(feature = "alloc_system_type", since = "1.28.0")]
+unsafe impl GlobalAlloc for System {
+ #[inline]
+ unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+ if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
+ libc::malloc(layout.size()) as *mut u8
+ } else {
+ #[cfg(target_os = "macos")]
+ {
+ if layout.align() > (1 << 31) {
+ return ptr::null_mut()
+ }
+ }
+ aligned_malloc(&layout)
+ }
+ }
+
+ #[inline]
+ unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+ if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
+ libc::calloc(layout.size(), 1) as *mut u8
+ } else {
+ let ptr = self.alloc(layout.clone());
+ if !ptr.is_null() {
+ ptr::write_bytes(ptr, 0, layout.size());
+ }
+ ptr
+ }
+ }
+
+ #[inline]
+ unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
+ libc::free(ptr as *mut libc::c_void)
+ }
+
+ #[inline]
+ unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+ if layout.align() <= MIN_ALIGN && layout.align() <= new_size {
+ libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8
+ } else {
+ realloc_fallback(self, ptr, layout, new_size)
+ }
+ }
+}
+
+#[cfg(any(target_os = "android",
+ target_os = "hermit",
+ target_os = "redox",
+ target_os = "solaris"))]
+#[inline]
+unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
+ // On android we currently target API level 9 which unfortunately
+ // doesn't have the `posix_memalign` API used below. Instead we use
+ // `memalign`, but this unfortunately has the property on some systems
+ // where the memory returned cannot be deallocated by `free`!
+ //
+ // Upon closer inspection, however, this appears to work just fine with
+ // Android, so for this platform we should be fine to call `memalign`
+ // (which is present in API level 9). Some helpful references could
+ // possibly be chromium using memalign [1], attempts at documenting that
+ // memalign + free is ok [2] [3], or the current source of chromium
+ // which still uses memalign on android [4].
+ //
+ // [1]: https://codereview.chromium.org/10796020/
+ // [2]: https://code.google.com/p/android/issues/detail?id=35391
+ // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579
+ // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/
+ // /memory/aligned_memory.cc
+ libc::memalign(layout.align(), layout.size()) as *mut u8
+}
+
+#[cfg(not(any(target_os = "android",
+ target_os = "hermit",
+ target_os = "redox",
+ target_os = "solaris")))]
+#[inline]
+unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
+ let mut out = ptr::null_mut();
+ let ret = libc::posix_memalign(&mut out, layout.align(), layout.size());
+ if ret != 0 {
+ ptr::null_mut()
+ } else {
+ out as *mut u8
+ }
+}
#[macro_use]
pub mod weak;
+pub mod alloc;
pub mod args;
pub mod android;
#[cfg(feature = "backtrace")]
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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 an implementation of a global allocator on the wasm32 platform when
+//! emscripten is not in use. In that situation there's no actual runtime for us
+//! to lean on for allocation, so instead we provide our own!
+//!
+//! The wasm32 instruction set has two instructions for getting the current
+//! amount of memory and growing the amount of memory. These instructions are the
+//! foundation on which we're able to build an allocator, so we do so! Note that
+//! the instructions are also pretty "global" and this is the "global" allocator
+//! after all!
+//!
+//! The current allocator here is the `dlmalloc` crate which we've got included
+//! in the rust-lang/rust repository as a submodule. The crate is a port of
+//! dlmalloc.c from C to Rust and is basically just so we can have "pure Rust"
+//! for now which is currently technically required (can't link with C yet).
+//!
+//! The crate itself provides a global allocator which on wasm has no
+//! synchronization as there are no threads!
+
+extern crate dlmalloc;
+
+use alloc::{GlobalAlloc, Layout, System};
+
+static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::DLMALLOC_INIT;
+
+#[stable(feature = "alloc_system_type", since = "1.28.0")]
+unsafe impl GlobalAlloc for System {
+ #[inline]
+ unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+ let _lock = lock::lock();
+ DLMALLOC.malloc(layout.size(), layout.align())
+ }
+
+ #[inline]
+ unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+ let _lock = lock::lock();
+ DLMALLOC.calloc(layout.size(), layout.align())
+ }
+
+ #[inline]
+ unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+ let _lock = lock::lock();
+ DLMALLOC.free(ptr, layout.size(), layout.align())
+ }
+
+ #[inline]
+ unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+ let _lock = lock::lock();
+ DLMALLOC.realloc(ptr, layout.size(), layout.align(), new_size)
+ }
+}
+
+#[cfg(target_feature = "atomics")]
+mod lock {
+ use arch::wasm32;
+ use sync::atomic::{AtomicI32, Ordering::SeqCst};
+
+ static LOCKED: AtomicI32 = AtomicI32::new(0);
+
+ pub struct DropLock;
+
+ pub fn lock() -> DropLock {
+ loop {
+ if LOCKED.swap(1, SeqCst) == 0 {
+ return DropLock
+ }
+ unsafe {
+ let r = wasm32::atomic::wait_i32(
+ &LOCKED as *const AtomicI32 as *mut i32,
+ 1, // expected value
+ -1, // timeout
+ );
+ debug_assert!(r == 0 || r == 1);
+ }
+ }
+ }
+
+ impl Drop for DropLock {
+ fn drop(&mut self) {
+ let r = LOCKED.swap(0, SeqCst);
+ debug_assert_eq!(r, 1);
+ unsafe {
+ wasm32::atomic::wake(
+ &LOCKED as *const AtomicI32 as *mut i32,
+ 1, // only one thread
+ );
+ }
+ }
+ }
+}
+
+#[cfg(not(target_feature = "atomics"))]
+mod lock {
+ #[inline]
+ pub fn lock() {} // no atomics, no threads, that's easy!
+}
use ffi::{OsString, OsStr};
use time::Duration;
+pub mod alloc;
pub mod args;
#[cfg(feature = "backtrace")]
pub mod backtrace;
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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 alloc::{GlobalAlloc, Layout, System};
+use sys::c;
+use sys_common::alloc::{MIN_ALIGN, realloc_fallback};
+
+#[repr(C)]
+struct Header(*mut u8);
+
+unsafe fn get_header<'a>(ptr: *mut u8) -> &'a mut Header {
+ &mut *(ptr as *mut Header).offset(-1)
+}
+
+unsafe fn align_ptr(ptr: *mut u8, align: usize) -> *mut u8 {
+ let aligned = ptr.add(align - (ptr as usize & (align - 1)));
+ *get_header(aligned) = Header(ptr);
+ aligned
+}
+
+#[inline]
+unsafe fn allocate_with_flags(layout: Layout, flags: c::DWORD) -> *mut u8 {
+ if layout.align() <= MIN_ALIGN {
+ return c::HeapAlloc(c::GetProcessHeap(), flags, layout.size()) as *mut u8
+ }
+
+ let size = layout.size() + layout.align();
+ let ptr = c::HeapAlloc(c::GetProcessHeap(), flags, size);
+ if ptr.is_null() {
+ ptr as *mut u8
+ } else {
+ align_ptr(ptr as *mut u8, layout.align())
+ }
+}
+
+#[stable(feature = "alloc_system_type", since = "1.28.0")]
+unsafe impl GlobalAlloc for System {
+ #[inline]
+ unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+ allocate_with_flags(layout, 0)
+ }
+
+ #[inline]
+ unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+ allocate_with_flags(layout, c::HEAP_ZERO_MEMORY)
+ }
+
+ #[inline]
+ unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+ if layout.align() <= MIN_ALIGN {
+ let err = c::HeapFree(c::GetProcessHeap(), 0, ptr as c::LPVOID);
+ debug_assert!(err != 0, "Failed to free heap memory: {}",
+ c::GetLastError());
+ } else {
+ let header = get_header(ptr);
+ let err = c::HeapFree(c::GetProcessHeap(), 0, header.0 as c::LPVOID);
+ debug_assert!(err != 0, "Failed to free heap memory: {}",
+ c::GetLastError());
+ }
+ }
+
+ #[inline]
+ unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+ if layout.align() <= MIN_ALIGN {
+ c::HeapReAlloc(c::GetProcessHeap(), 0, ptr as c::LPVOID, new_size) as *mut u8
+ } else {
+ realloc_fallback(self, ptr, layout, new_size)
+ }
+ }
+}
pub const STACK_SIZE_PARAM_IS_A_RESERVATION: DWORD = 0x00010000;
+pub const HEAP_ZERO_MEMORY: DWORD = 0x00000008;
+
#[repr(C)]
#[cfg(not(target_pointer_width = "64"))]
pub struct WSADATA {
#[link_name = "SystemFunction036"]
pub fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: ULONG) -> BOOLEAN;
+
+ pub fn GetProcessHeap() -> HANDLE;
+ pub fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
+ pub fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID;
+ pub fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
}
// Functions that aren't available on every version of Windows that we support,
#[macro_use] pub mod compat;
+pub mod alloc;
pub mod args;
#[cfg(feature = "backtrace")]
pub mod backtrace;
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(dead_code)]
+
+use alloc::{GlobalAlloc, Layout, System};
+use cmp;
+use ptr;
+
+// The minimum alignment guaranteed by the architecture. This value is used to
+// add fast paths for low alignment values.
+#[cfg(all(any(target_arch = "x86",
+ target_arch = "arm",
+ target_arch = "mips",
+ target_arch = "powerpc",
+ target_arch = "powerpc64",
+ target_arch = "asmjs",
+ target_arch = "wasm32")))]
+pub const MIN_ALIGN: usize = 8;
+#[cfg(all(any(target_arch = "x86_64",
+ target_arch = "aarch64",
+ target_arch = "mips64",
+ target_arch = "s390x",
+ target_arch = "sparc64")))]
+pub const MIN_ALIGN: usize = 16;
+
+pub unsafe fn realloc_fallback(
+ alloc: &System,
+ ptr: *mut u8,
+ old_layout: Layout,
+ new_size: usize,
+) -> *mut u8 {
+ // Docs for GlobalAlloc::realloc require this to be valid:
+ let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align());
+
+ let new_ptr = GlobalAlloc::alloc(alloc, new_layout);
+ if !new_ptr.is_null() {
+ let size = cmp::min(old_layout.size(), new_size);
+ ptr::copy_nonoverlapping(ptr, new_ptr, size);
+ GlobalAlloc::dealloc(alloc, ptr, old_layout);
+ }
+ new_ptr
+}
})
}
+pub mod alloc;
pub mod at_exit_imp;
#[cfg(feature = "backtrace")]
pub mod backtrace;
use ptr::P;
use rustc_data_structures::indexed_vec;
use rustc_data_structures::indexed_vec::Idx;
+#[cfg(target_arch = "x86_64")]
+use rustc_data_structures::static_assert;
use rustc_target::spec::abi::Abi;
use source_map::{dummy_spanned, respan, Spanned};
use symbol::{keywords, Symbol};
pub attrs: ThinVec<Attribute>,
}
+// `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
+#[cfg(target_arch = "x86_64")]
+static_assert!(MEM_SIZE_OF_EXPR: std::mem::size_of::<Expr>() == 88);
+
impl Expr {
/// Whether this expression would be valid somewhere that expects a value, for example, an `if`
/// condition.
/// A unary operation (For example: `!x`, `*x`)
Unary(UnOp, P<Expr>),
/// A literal (For example: `1`, `"foo"`)
- Lit(P<Lit>),
+ Lit(Lit),
/// A cast (`foo as f64`)
Cast(P<Expr>, P<Ty>),
Type(P<Expr>, P<Ty>),
pub fn raw_expr(sp: Span) -> P<ast::Expr> {
P(ast::Expr {
id: ast::DUMMY_NODE_ID,
- node: ast::ExprKind::Lit(P(source_map::respan(sp, ast::LitKind::Bool(false)))),
+ node: ast::ExprKind::Lit(source_map::respan(sp, ast::LitKind::Bool(false))),
span: sp,
attrs: ThinVec::new(),
})
}
fn expr_lit(&self, sp: Span, lit: ast::LitKind) -> P<ast::Expr> {
- self.expr(sp, ast::ExprKind::Lit(P(respan(sp, lit))))
+ self.expr(sp, ast::ExprKind::Lit(respan(sp, lit)))
}
fn expr_usize(&self, span: Span, i: usize) -> P<ast::Expr> {
self.expr_lit(span, ast::LitKind::Int(i as u128,
// FIXME: This is wrong
P(ast::Expr {
id: ast::DUMMY_NODE_ID,
- node: ast::ExprKind::Lit(P(self.clone())),
+ node: ast::ExprKind::Lit(self.clone()),
span: DUMMY_SP,
attrs: ThinVec::new(),
}).to_tokens(cx)
let lit = ast::LitKind::Int(val as u128, ast::LitIntType::Signed($tag));
let lit = P(ast::Expr {
id: ast::DUMMY_NODE_ID,
- node: ast::ExprKind::Lit(P(dummy_spanned(lit))),
+ node: ast::ExprKind::Lit(dummy_spanned(lit)),
span: DUMMY_SP,
attrs: ThinVec::new(),
});
/// Either a sequence of token trees or a single one. This is used as the representation of the
/// sequence of tokens that make up a matcher.
#[derive(Clone)]
-enum TokenTreeOrTokenTreeSlice<'a> {
+enum TokenTreeOrTokenTreeSlice<'tt> {
Tt(TokenTree),
- TtSeq(&'a [TokenTree]),
+ TtSeq(&'tt [TokenTree]),
}
-impl<'a> TokenTreeOrTokenTreeSlice<'a> {
+impl<'tt> TokenTreeOrTokenTreeSlice<'tt> {
/// Returns the number of constituent top-level token trees of `self` (top-level in that it
/// will not recursively descend into subtrees).
fn len(&self) -> usize {
/// This is used by `inner_parse_loop` to keep track of delimited submatchers that we have
/// descended into.
#[derive(Clone)]
-struct MatcherTtFrame<'a> {
+struct MatcherTtFrame<'tt> {
/// The "parent" matcher that we are descending into.
- elts: TokenTreeOrTokenTreeSlice<'a>,
+ elts: TokenTreeOrTokenTreeSlice<'tt>,
/// The position of the "dot" in `elts` at the time we descended.
idx: usize,
}
type NamedMatchVec = SmallVec<[NamedMatch; 4]>;
-/// Represents a single "position" (aka "matcher position", aka "item"), as described in the module
-/// documentation.
+/// Represents a single "position" (aka "matcher position", aka "item"), as
+/// described in the module documentation.
+///
+/// Here:
+///
+/// - `'root` represents the lifetime of the stack slot that holds the root
+/// `MatcherPos`. As described in `MatcherPosHandle`, the root `MatcherPos`
+/// structure is stored on the stack, but subsequent instances are put into
+/// the heap.
+/// - `'tt` represents the lifetime of the token trees that this matcher
+/// position refers to.
+///
+/// It is important to distinguish these two lifetimes because we have a
+/// `SmallVec<TokenTreeOrTokenTreeSlice<'tt>>` below, and the destructor of
+/// that is considered to possibly access the data from its elements (it lacks
+/// a `#[may_dangle]` attribute). As a result, the compiler needs to know that
+/// all the elements in that `SmallVec` strictly outlive the root stack slot
+/// lifetime. By separating `'tt` from `'root`, we can show that.
#[derive(Clone)]
-struct MatcherPos<'a> {
+struct MatcherPos<'root, 'tt: 'root> {
/// The token or sequence of tokens that make up the matcher
- top_elts: TokenTreeOrTokenTreeSlice<'a>,
+ top_elts: TokenTreeOrTokenTreeSlice<'tt>,
+
/// The position of the "dot" in this matcher
idx: usize,
+
/// The first span of source source that the beginning of this matcher corresponds to. In other
/// words, the token in the source whose span is `sp_open` is matched against the first token of
/// the matcher.
/// in this matcher.
match_hi: usize,
- // Specifically used if we are matching a repetition. If we aren't both should be `None`.
+ // The following fields are used if we are matching a repetition. If we aren't, they should be
+ // `None`.
+
/// The KleeneOp of this sequence if we are in a repetition.
seq_op: Option<quoted::KleeneOp>,
- /// The separator if we are in a repetition
+
+ /// The separator if we are in a repetition.
sep: Option<Token>,
+
/// The "parent" matcher position if we are in a repetition. That is, the matcher position just
/// before we enter the sequence.
- up: Option<MatcherPosHandle<'a>>,
+ up: Option<MatcherPosHandle<'root, 'tt>>,
- // Specifically used to "unzip" token trees. By "unzip", we mean to unwrap the delimiters from
- // a delimited token tree (e.g. something wrapped in `(` `)`) or to get the contents of a doc
- // comment...
+ /// Specifically used to "unzip" token trees. By "unzip", we mean to unwrap the delimiters from
+ /// a delimited token tree (e.g. something wrapped in `(` `)`) or to get the contents of a doc
+ /// comment...
+ ///
/// When matching against matchers with nested delimited submatchers (e.g. `pat ( pat ( .. )
/// pat ) pat`), we need to keep track of the matchers we are descending into. This stack does
/// that where the bottom of the stack is the outermost matcher.
- // Also, throughout the comments, this "descent" is often referred to as "unzipping"...
- stack: Vec<MatcherTtFrame<'a>>,
+ /// Also, throughout the comments, this "descent" is often referred to as "unzipping"...
+ stack: SmallVec<[MatcherTtFrame<'tt>; 1]>,
}
-impl<'a> MatcherPos<'a> {
+impl<'root, 'tt> MatcherPos<'root, 'tt> {
/// Add `m` as a named match for the `idx`-th metavar.
fn push_match(&mut self, idx: usize, m: NamedMatch) {
let matches = Rc::make_mut(&mut self.matches[idx]);
// Therefore, the initial MatcherPos is always allocated on the stack,
// subsequent ones (of which there aren't that many) are allocated on the heap,
// and this type is used to encapsulate both cases.
-enum MatcherPosHandle<'a> {
- Ref(&'a mut MatcherPos<'a>),
- Box(Box<MatcherPos<'a>>),
+enum MatcherPosHandle<'root, 'tt: 'root> {
+ Ref(&'root mut MatcherPos<'root, 'tt>),
+ Box(Box<MatcherPos<'root, 'tt>>),
}
-impl<'a> Clone for MatcherPosHandle<'a> {
+impl<'root, 'tt> Clone for MatcherPosHandle<'root, 'tt> {
// This always produces a new Box.
fn clone(&self) -> Self {
MatcherPosHandle::Box(match *self {
}
}
-impl<'a> Deref for MatcherPosHandle<'a> {
- type Target = MatcherPos<'a>;
+impl<'root, 'tt> Deref for MatcherPosHandle<'root, 'tt> {
+ type Target = MatcherPos<'root, 'tt>;
fn deref(&self) -> &Self::Target {
match *self {
MatcherPosHandle::Ref(ref r) => r,
}
}
-impl<'a> DerefMut for MatcherPosHandle<'a> {
- fn deref_mut(&mut self) -> &mut MatcherPos<'a> {
+impl<'root, 'tt> DerefMut for MatcherPosHandle<'root, 'tt> {
+ fn deref_mut(&mut self) -> &mut MatcherPos<'root, 'tt> {
match *self {
MatcherPosHandle::Ref(ref mut r) => r,
MatcherPosHandle::Box(ref mut b) => b,
/// Generate the top-level matcher position in which the "dot" is before the first token of the
/// matcher `ms` and we are going to start matching at the span `open` in the source.
-fn initial_matcher_pos(ms: &[TokenTree], open: Span) -> MatcherPos {
+fn initial_matcher_pos<'root, 'tt>(ms: &'tt [TokenTree], open: Span) -> MatcherPos<'root, 'tt> {
let match_idx_hi = count_names(ms);
let matches = create_matches(match_idx_hi);
MatcherPos {
match_hi: match_idx_hi,
// Haven't descended into any delimiters, so empty stack
- stack: vec![],
+ stack: smallvec![],
// Haven't descended into any sequences, so both of these are `None`.
seq_op: None,
/// # Returns
///
/// A `ParseResult`. Note that matches are kept track of through the items generated.
-fn inner_parse_loop<'a>(
+fn inner_parse_loop<'root, 'tt>(
sess: &ParseSess,
- cur_items: &mut SmallVec<[MatcherPosHandle<'a>; 1]>,
- next_items: &mut Vec<MatcherPosHandle<'a>>,
- eof_items: &mut SmallVec<[MatcherPosHandle<'a>; 1]>,
- bb_items: &mut SmallVec<[MatcherPosHandle<'a>; 1]>,
+ cur_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>,
+ next_items: &mut Vec<MatcherPosHandle<'root, 'tt>>,
+ eof_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>,
+ bb_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>,
token: &Token,
span: syntax_pos::Span,
) -> ParseResult<()> {
let matches = create_matches(item.matches.len());
cur_items.push(MatcherPosHandle::Box(Box::new(MatcherPos {
- stack: vec![],
+ stack: smallvec![],
sep: seq.separator.clone(),
seq_op: Some(seq.op),
idx: 0,
let minus_lo = self.span;
let minus_present = self.eat(&token::BinOp(token::Minus));
let lo = self.span;
- let literal = P(self.parse_lit()?);
+ let literal = self.parse_lit()?;
let hi = self.prev_span;
let expr = self.mk_expr(lo.to(hi), ExprKind::Lit(literal), ThinVec::new());
-Subproject commit 2717444753318e461e0c3b30dacd03ffbac96903
+Subproject commit 7f23313edff8beccb3fe44b815714269c5124c15
LLVMRustSetLastError(toString(MOrErr.takeError()).c_str());
return LLVMRustResult::Failure;
}
-#if LLVM_VERSION_GE(5, 0)
MOrErr->MemberName = sys::path::filename(MOrErr->MemberName);
-#endif
Members.push_back(std::move(*MOrErr));
} else {
Expected<NewArchiveMember> MOrErr =
#include "llvm/Transforms/IPO/FunctionImport.h"
#include "llvm/Transforms/Utils/FunctionImportUtils.h"
#include "llvm/LTO/LTO.h"
-#if LLVM_VERSION_LE(4, 0)
-#include "llvm/Object/ModuleSummaryIndexObjectFile.h"
-#endif
#include "llvm-c/Transforms/PassManagerBuilder.h"
}
extern "C"
-bool LLVMRustPassManagerBuilderPopulateThinLTOPassManager(
+void LLVMRustPassManagerBuilderPopulateThinLTOPassManager(
LLVMPassManagerBuilderRef PMBR,
LLVMPassManagerRef PMR
) {
unwrap(PMBR)->populateThinLTOPassManager(*unwrap(PMR));
- return true;
}
#ifdef LLVM_COMPONENT_X86
LLVMPassManagerBuilderRef PMBR, LLVMRustCodeGenOptLevel OptLevel,
bool MergeFunctions, bool SLPVectorize, bool LoopVectorize, bool PrepareForThinLTO,
const char* PGOGenPath, const char* PGOUsePath) {
-#if LLVM_RUSTLLVM
+#if LLVM_VERSION_GE(7, 0)
unwrap(PMBR)->MergeFunctions = MergeFunctions;
#endif
unwrap(PMBR)->SLPVectorize = SLPVectorize;
Ret->ModuleMap[module->identifier] = mem_buffer;
-#if LLVM_VERSION_GE(5, 0)
if (Error Err = readModuleSummaryIndex(mem_buffer, Ret->Index, i)) {
LLVMRustSetLastError(toString(std::move(Err)).c_str());
return nullptr;
}
-#else
- Expected<std::unique_ptr<object::ModuleSummaryIndexObjectFile>> ObjOrErr =
- object::ModuleSummaryIndexObjectFile::create(mem_buffer);
- if (!ObjOrErr) {
- LLVMRustSetLastError(toString(ObjOrErr.takeError()).c_str());
- return nullptr;
- }
- auto Index = (*ObjOrErr)->takeIndex();
- Ret->Index.mergeFrom(std::move(Index), i);
-#endif
}
// Collect for each module the list of function it defines (GUID -> Summary)
// combined index
//
// This is copied from `lib/LTO/ThinLTOCodeGenerator.cpp`
-#if LLVM_VERSION_GE(5, 0)
#if LLVM_VERSION_GE(7, 0)
auto deadIsPrevailing = [&](GlobalValue::GUID G) {
return PrevailingType::Unknown;
Ret->ImportLists,
Ret->ExportLists
);
-#else
- auto DeadSymbols = computeDeadSymbols(Ret->Index, Ret->GUIDPreservedSymbols);
- ComputeCrossModuleImport(
- Ret->Index,
- Ret->ModuleToDefinedGVSummaries,
- Ret->ImportLists,
- Ret->ExportLists,
- &DeadSymbols
- );
-#endif
// Resolve LinkOnce/Weak symbols, this has to be computed early be cause it
// impacts the caching.
StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR;
DenseMap<GlobalValue::GUID, const GlobalValueSummary *> PrevailingCopy;
for (auto &I : Ret->Index) {
-#if LLVM_VERSION_GE(5, 0)
if (I.second.SummaryList.size() > 1)
PrevailingCopy[I.first] = getFirstDefinitionForLinker(I.second.SummaryList);
-#else
- if (I.second.size() > 1)
- PrevailingCopy[I.first] = getFirstDefinitionForLinker(I.second);
-#endif
}
auto isPrevailing = [&](GlobalValue::GUID GUID, const GlobalValueSummary *S) {
const auto &Prevailing = PrevailingCopy.find(GUID);
// linkage will stay as external, and internal will stay as internal.
std::set<GlobalValue::GUID> ExportedGUIDs;
for (auto &List : Ret->Index) {
-#if LLVM_VERSION_GE(5, 0)
for (auto &GVS: List.second.SummaryList) {
-#else
- for (auto &GVS: List.second) {
-#endif
if (GlobalValue::isLocalLinkage(GVS->linkage()))
continue;
auto GUID = GVS->getOriginalName();
-#if LLVM_VERSION_GE(5, 0)
if (GVS->flags().Live)
-#else
- if (!DeadSymbols.count(GUID))
-#endif
ExportedGUIDs.insert(GUID);
}
}
// except according to those terms.
#include "rustllvm.h"
+#include "llvm/IR/CallSite.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Bitcode/BitcodeWriterPass.h"
#include "llvm/Support/Signals.h"
-
-#include "llvm/IR/CallSite.h"
-
-#if LLVM_VERSION_GE(5, 0)
#include "llvm/ADT/Optional.h"
-#else
-#include <cstdlib>
-#endif
#include <iostream>
LLVMRustAttribute RustAttr) {
CallSite Call = CallSite(unwrap<Instruction>(Instr));
Attribute Attr = Attribute::get(Call->getContext(), fromRust(RustAttr));
-#if LLVM_VERSION_GE(5, 0)
Call.addAttribute(Index, Attr);
-#else
- AttrBuilder B(Attr);
- Call.setAttributes(Call.getAttributes().addAttributes(
- Call->getContext(), Index,
- AttributeSet::get(Call->getContext(), Index, B)));
-#endif
}
extern "C" void LLVMRustAddAlignmentCallSiteAttr(LLVMValueRef Instr,
CallSite Call = CallSite(unwrap<Instruction>(Instr));
AttrBuilder B;
B.addAlignmentAttr(Bytes);
-#if LLVM_VERSION_GE(5, 0)
Call.setAttributes(Call.getAttributes().addAttributes(
Call->getContext(), Index, B));
-#else
- Call.setAttributes(Call.getAttributes().addAttributes(
- Call->getContext(), Index,
- AttributeSet::get(Call->getContext(), Index, B)));
-#endif
}
extern "C" void LLVMRustAddDereferenceableCallSiteAttr(LLVMValueRef Instr,
CallSite Call = CallSite(unwrap<Instruction>(Instr));
AttrBuilder B;
B.addDereferenceableAttr(Bytes);
-#if LLVM_VERSION_GE(5, 0)
Call.setAttributes(Call.getAttributes().addAttributes(
Call->getContext(), Index, B));
-#else
- Call.setAttributes(Call.getAttributes().addAttributes(
- Call->getContext(), Index,
- AttributeSet::get(Call->getContext(), Index, B)));
-#endif
}
extern "C" void LLVMRustAddDereferenceableOrNullCallSiteAttr(LLVMValueRef Instr,
CallSite Call = CallSite(unwrap<Instruction>(Instr));
AttrBuilder B;
B.addDereferenceableOrNullAttr(Bytes);
-#if LLVM_VERSION_GE(5, 0)
Call.setAttributes(Call.getAttributes().addAttributes(
Call->getContext(), Index, B));
-#else
- Call.setAttributes(Call.getAttributes().addAttributes(
- Call->getContext(), Index,
- AttributeSet::get(Call->getContext(), Index, B)));
-#endif
}
extern "C" void LLVMRustAddFunctionAttribute(LLVMValueRef Fn, unsigned Index,
Function *A = unwrap<Function>(Fn);
Attribute Attr = Attribute::get(A->getContext(), fromRust(RustAttr));
AttrBuilder B(Attr);
-#if LLVM_VERSION_GE(5, 0)
A->addAttributes(Index, B);
-#else
- A->addAttributes(Index, AttributeSet::get(A->getContext(), Index, B));
-#endif
}
extern "C" void LLVMRustAddAlignmentAttr(LLVMValueRef Fn,
Function *A = unwrap<Function>(Fn);
AttrBuilder B;
B.addAlignmentAttr(Bytes);
-#if LLVM_VERSION_GE(5, 0)
A->addAttributes(Index, B);
-#else
- A->addAttributes(Index, AttributeSet::get(A->getContext(), Index, B));
-#endif
}
extern "C" void LLVMRustAddDereferenceableAttr(LLVMValueRef Fn, unsigned Index,
Function *A = unwrap<Function>(Fn);
AttrBuilder B;
B.addDereferenceableAttr(Bytes);
-#if LLVM_VERSION_GE(5, 0)
A->addAttributes(Index, B);
-#else
- A->addAttributes(Index, AttributeSet::get(A->getContext(), Index, B));
-#endif
}
extern "C" void LLVMRustAddDereferenceableOrNullAttr(LLVMValueRef Fn,
Function *A = unwrap<Function>(Fn);
AttrBuilder B;
B.addDereferenceableOrNullAttr(Bytes);
-#if LLVM_VERSION_GE(5, 0)
A->addAttributes(Index, B);
-#else
- A->addAttributes(Index, AttributeSet::get(A->getContext(), Index, B));
-#endif
}
extern "C" void LLVMRustAddFunctionAttrStringValue(LLVMValueRef Fn,
Function *F = unwrap<Function>(Fn);
AttrBuilder B;
B.addAttribute(Name, Value);
-#if LLVM_VERSION_GE(5, 0)
F->addAttributes(Index, B);
-#else
- F->addAttributes(Index, AttributeSet::get(F->getContext(), Index, B));
-#endif
}
extern "C" void LLVMRustRemoveFunctionAttributes(LLVMValueRef Fn,
Attribute Attr = Attribute::get(F->getContext(), fromRust(RustAttr));
AttrBuilder B(Attr);
auto PAL = F->getAttributes();
-#if LLVM_VERSION_GE(5, 0)
auto PALNew = PAL.removeAttributes(F->getContext(), Index, B);
-#else
- const AttributeSet PALNew = PAL.removeAttributes(
- F->getContext(), Index, AttributeSet::get(F->getContext(), Index, B));
-#endif
F->setAttributes(PALNew);
}
CrossThread,
};
-#if LLVM_VERSION_GE(5, 0)
static SyncScope::ID fromRust(LLVMRustSynchronizationScope Scope) {
switch (Scope) {
case LLVMRustSynchronizationScope::SingleThread:
report_fatal_error("bad SynchronizationScope.");
}
}
-#else
-static SynchronizationScope fromRust(LLVMRustSynchronizationScope Scope) {
- switch (Scope) {
- case LLVMRustSynchronizationScope::SingleThread:
- return SingleThread;
- case LLVMRustSynchronizationScope::CrossThread:
- return CrossThread;
- default:
- report_fatal_error("bad SynchronizationScope.");
- }
-}
-#endif
extern "C" LLVMValueRef
LLVMRustBuildAtomicFence(LLVMBuilderRef B, LLVMAtomicOrdering Order,
typedef DIBuilder *LLVMRustDIBuilderRef;
-#if LLVM_VERSION_LT(5, 0)
-typedef struct LLVMOpaqueMetadata *LLVMMetadataRef;
-
-namespace llvm {
-DEFINE_ISA_CONVERSION_FUNCTIONS(Metadata, LLVMMetadataRef)
-
-inline Metadata **unwrap(LLVMMetadataRef *Vals) {
- return reinterpret_cast<Metadata **>(Vals);
-}
-}
-#endif
-
template <typename DIT> DIT *unwrapDIPtr(LLVMMetadataRef Ref) {
return (DIT *)(Ref ? unwrap<MDNode>(Ref) : nullptr);
}
if (isSet(Flags & LLVMRustDIFlags::FlagRValueReference)) {
Result |= DINode::DIFlags::FlagRValueReference;
}
-#if LLVM_VERSION_LE(4, 0)
- if (isSet(Flags & LLVMRustDIFlags::FlagExternalTypeRef)) {
- Result |= DINode::DIFlags::FlagExternalTypeRef;
- }
-#endif
if (isSet(Flags & LLVMRustDIFlags::FlagIntroducedVirtual)) {
Result |= DINode::DIFlags::FlagIntroducedVirtual;
}
uint64_t SizeInBits, uint32_t AlignInBits, const char *Name) {
return wrap(Builder->createPointerType(unwrapDI<DIType>(PointeeTy),
SizeInBits, AlignInBits,
-#if LLVM_VERSION_GE(5, 0)
/* DWARFAddressSpace */ None,
-#endif
Name));
}
LLVMMetadataRef Scope, const char *Name,
LLVMMetadataRef File, unsigned LineNo) {
return wrap(Builder->createNameSpace(
- unwrapDI<DIDescriptor>(Scope), Name
-#if LLVM_VERSION_LT(5, 0)
- ,
- unwrapDI<DIFile>(File), LineNo
-#endif
- ,
+ unwrapDI<DIDescriptor>(Scope), Name,
false // ExportSymbols (only relevant for C++ anonymous namespaces)
));
}
}
extern "C" int64_t LLVMRustDIBuilderCreateOpPlusUconst() {
-#if LLVM_VERSION_GE(5, 0)
return dwarf::DW_OP_plus_uconst;
-#else
- // older LLVM used `plus` to behave like `plus_uconst`.
- return dwarf::DW_OP_plus;
-#endif
}
extern "C" void LLVMRustWriteTypeToString(LLVMTypeRef Ty, RustStringRef Str) {
*FunctionOut = wrap(&Opt->getFunction());
RawRustStringOstream FilenameOS(FilenameOut);
-#if LLVM_VERSION_GE(5,0)
DiagnosticLocation loc = Opt->getLocation();
if (loc.isValid()) {
*Line = loc.getLine();
*Column = loc.getColumn();
FilenameOS << loc.getFilename();
}
-#else
- const DebugLoc &loc = Opt->getDebugLoc();
- if (loc) {
- *Line = loc.getLine();
- *Column = loc.getCol();
- FilenameOS << cast<DIScope>(loc.getScope())->getFilename();
- }
-#endif
RawRustStringOstream MessageOS(MessageOut);
MessageOS << Opt->getMsg();
unwrap(Fn), makeArrayRef(unwrap(Args), NumArgs), Bundles, Name));
}
+extern "C" LLVMValueRef LLVMRustBuildMemCpy(LLVMBuilderRef B,
+ LLVMValueRef Dst, unsigned DstAlign,
+ LLVMValueRef Src, unsigned SrcAlign,
+ LLVMValueRef Size, bool IsVolatile) {
+#if LLVM_VERSION_GE(7, 0)
+ return wrap(unwrap(B)->CreateMemCpy(
+ unwrap(Dst), DstAlign,
+ unwrap(Src), SrcAlign,
+ unwrap(Size), IsVolatile));
+#else
+ unsigned Align = std::min(DstAlign, SrcAlign);
+ return wrap(unwrap(B)->CreateMemCpy(
+ unwrap(Dst), unwrap(Src),
+ unwrap(Size), Align, IsVolatile));
+#endif
+}
+
+extern "C" LLVMValueRef LLVMRustBuildMemMove(LLVMBuilderRef B,
+ LLVMValueRef Dst, unsigned DstAlign,
+ LLVMValueRef Src, unsigned SrcAlign,
+ LLVMValueRef Size, bool IsVolatile) {
+#if LLVM_VERSION_GE(7, 0)
+ return wrap(unwrap(B)->CreateMemMove(
+ unwrap(Dst), DstAlign,
+ unwrap(Src), SrcAlign,
+ unwrap(Size), IsVolatile));
+#else
+ unsigned Align = std::min(DstAlign, SrcAlign);
+ return wrap(unwrap(B)->CreateMemMove(
+ unwrap(Dst), unwrap(Src),
+ unwrap(Size), Align, IsVolatile));
+#endif
+}
+
extern "C" LLVMValueRef
LLVMRustBuildInvoke(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args,
unsigned NumArgs, LLVMBasicBlockRef Then,
}
// Vector reductions:
-#if LLVM_VERSION_GE(5, 0)
extern "C" LLVMValueRef
LLVMRustBuildVectorReduceFAdd(LLVMBuilderRef B, LLVMValueRef Acc, LLVMValueRef Src) {
return wrap(unwrap(B)->CreateFAddReduce(unwrap(Acc),unwrap(Src)));
return wrap(unwrap(B)->CreateFPMaxReduce(unwrap(Src), NoNaN));
}
-#else
-
-extern "C" LLVMValueRef
-LLVMRustBuildVectorReduceFAdd(LLVMBuilderRef, LLVMValueRef, LLVMValueRef) {
- return nullptr;
-}
-extern "C" LLVMValueRef
-LLVMRustBuildVectorReduceFMul(LLVMBuilderRef, LLVMValueRef, LLVMValueRef) {
- return nullptr;
-}
-extern "C" LLVMValueRef
-LLVMRustBuildVectorReduceAdd(LLVMBuilderRef, LLVMValueRef) {
- return nullptr;
-}
-extern "C" LLVMValueRef
-LLVMRustBuildVectorReduceMul(LLVMBuilderRef, LLVMValueRef) {
- return nullptr;
-}
-extern "C" LLVMValueRef
-LLVMRustBuildVectorReduceAnd(LLVMBuilderRef, LLVMValueRef) {
- return nullptr;
-}
-extern "C" LLVMValueRef
-LLVMRustBuildVectorReduceOr(LLVMBuilderRef, LLVMValueRef) {
- return nullptr;
-}
-extern "C" LLVMValueRef
-LLVMRustBuildVectorReduceXor(LLVMBuilderRef, LLVMValueRef) {
- return nullptr;
-}
-extern "C" LLVMValueRef
-LLVMRustBuildVectorReduceMin(LLVMBuilderRef, LLVMValueRef, bool) {
- return nullptr;
-}
-extern "C" LLVMValueRef
-LLVMRustBuildVectorReduceMax(LLVMBuilderRef, LLVMValueRef, bool) {
- return nullptr;
-}
-extern "C" LLVMValueRef
-LLVMRustBuildVectorReduceFMin(LLVMBuilderRef, LLVMValueRef, bool) {
- return nullptr;
-}
-extern "C" LLVMValueRef
-LLVMRustBuildVectorReduceFMax(LLVMBuilderRef, LLVMValueRef, bool) {
- return nullptr;
-}
-#endif
-
#if LLVM_VERSION_GE(6, 0)
extern "C" LLVMValueRef
LLVMRustBuildMinNum(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS) {
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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 depends on a patch that was committed to upstream LLVM
+// before 7.0, then backported to the Rust LLVM fork. It tests that
+// optimized enum debug info accurately reflects the enum layout.
+
+// ignore-tidy-linelength
+// ignore-windows
+// min-system-llvm-version 7.0
+
+// compile-flags: -g -C no-prepopulate-passes
+
+// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_variant_part,{{.*}}size: 32,{{.*}}
+// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "Placeholder",{{.*}}extraData: i64 4294967295{{[,)].*}}
+// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "Error",{{.*}}extraData: i64 0{{[,)].*}}
+
+#![feature(never_type)]
+#![feature(nll)]
+
+#[derive(Copy, Clone)]
+pub struct Entity {
+ private: std::num::NonZeroU32,
+}
+
+#[derive(Copy, Clone, PartialEq, Eq)]
+pub struct Declaration;
+
+impl TypeFamily for Declaration {
+ type Base = Base;
+ type Placeholder = !;
+
+ fn intern_base_data(_: BaseKind<Self>) {}
+}
+
+#[derive(Copy, Clone)]
+pub struct Base;
+
+pub trait TypeFamily: Copy + 'static {
+ type Base: Copy;
+ type Placeholder: Copy;
+
+ fn intern_base_data(_: BaseKind<Self>);
+}
+
+#[derive(Copy, Clone)]
+pub enum BaseKind<F: TypeFamily> {
+ Named(Entity),
+ Placeholder(F::Placeholder),
+ Error,
+}
+
+pub fn main() {
+ let x = BaseKind::Error::<Declaration>;
+ let y = 7;
+}
pub fn call_pkd1(f: fn() -> Array) -> BigPacked1 {
// CHECK: [[ALLOCA:%[_a-z0-9]+]] = alloca %Array
// CHECK: call void %{{.*}}(%Array* noalias nocapture sret dereferenceable(32) [[ALLOCA]])
-// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 1 %{{.*}}, i8* align 1 %{{.*}}, i{{[0-9]+}} 32, i1 false)
+// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 1 %{{.*}}, i8* align 4 %{{.*}}, i{{[0-9]+}} 32, i1 false)
// check that calls whose destination is a field of a packed struct
// go through an alloca rather than calling the function with an
// unaligned destination.
pub fn call_pkd2(f: fn() -> Array) -> BigPacked2 {
// CHECK: [[ALLOCA:%[_a-z0-9]+]] = alloca %Array
// CHECK: call void %{{.*}}(%Array* noalias nocapture sret dereferenceable(32) [[ALLOCA]])
-// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 2 %{{.*}}, i8* align 2 %{{.*}}, i{{[0-9]+}} 32, i1 false)
+// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 2 %{{.*}}, i8* align 4 %{{.*}}, i{{[0-9]+}} 32, i1 false)
// check that calls whose destination is a field of a packed struct
// go through an alloca rather than calling the function with an
// unaligned destination.
// CHECK: store i32 %0, i32* [[TMP]]
// CHECK: [[Y8:%[0-9]+]] = bitcast [4 x i8]* %y to i8*
// CHECK: [[TMP8:%[0-9]+]] = bitcast i32* [[TMP]] to i8*
-// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 1 [[Y8]], i8* align 1 [[TMP8]], i{{[0-9]+}} 4, i1 false)
+// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 1 [[Y8]], i8* align 4 [[TMP8]], i{{[0-9]+}} 4, i1 false)
*x = y;
}
// CHECK: store i32 %0, i32* [[TMP]]
// CHECK: [[Y8:%[0-9]+]] = bitcast %Bytes* %y to i8*
// CHECK: [[TMP8:%[0-9]+]] = bitcast i32* [[TMP]] to i8*
-// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 1 [[Y8]], i8* align 1 [[TMP8]], i{{[0-9]+}} 4, i1 false)
+// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 1 [[Y8]], i8* align 4 [[TMP8]], i{{[0-9]+}} 4, i1 false)
*x = y;
}
--- /dev/null
+// compile-flags: -Z span_free_formats -Z mir-opt-level=3
+
+#[inline]
+fn test(x: &dyn X) -> bool {
+ x.y()
+}
+
+fn test2(x: &dyn X) -> bool {
+ test(x)
+}
+
+trait X {
+ fn y(&self) -> bool {
+ false
+ }
+}
+
+impl X for () {
+ fn y(&self) -> bool {
+ true
+ }
+}
+
+fn main() {
+ println!("Should be true: {}", test2(&()));
+}
+
+// END RUST SOURCE
+// START rustc.test2.Inline.after.mir
+// ...
+// bb0: {
+// ...
+// _0 = const X::y(move _2) -> bb1;
+// }
+// ...
+// END rustc.test2.Inline.after.mir
if self.0 == 1 {
panic!("panic 1");
} else {
- eprint!("drop {}", self.0);
+ eprintln!("drop {}", self.0);
}
}
}
fn main() {
panic::set_hook(Box::new(|i| {
- eprint!("greetings from the panic handler");
+ eprintln!("greetings from the panic handler");
}));
panic!("foobar");
}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+trait Foo: Iterator<Item = i32> {}
+trait Bar: Foo {}
+
+fn main() {
+ let _: &dyn Bar;
+}
assert_eq!(BE_U32, b(55u32).to_be());
assert_eq!(LE_U32, b(55u32).to_le());
- #[cfg(not(target_arch = "asmjs"))]
+ #[cfg(not(target_os = "emscripten"))]
{
const BE_U128: u128 = 999999u128.to_be();
const LE_I128: i128 = (-999999i128).to_le();
// expose is still present.
#![feature(mpsc_select)]
+#![allow(deprecated)]
use std::sync::mpsc::{channel, Sender, Receiver};
use std::thread;
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+trait Foo: Fn(i32) -> i32 + Send {}
+
+impl<T: ?Sized + Fn(i32) -> i32 + Send> Foo for T {}
+
+fn wants_foo(f: Box<Foo>) -> i32 {
+ f(42)
+}
+
+fn main() {
+ let f = Box::new(|x| x);
+ assert_eq!(wants_foo(f), 42);
+}
+++ /dev/null
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(trait_alias)]
-
-trait Foo = PartialEq<i32> + Send;
-trait Bar = Foo + Sync;
-
-trait I32Iterator = Iterator<Item = i32>;
-
-pub fn main() {
- let a: &dyn Bar = &123;
- assert!(*a == 123);
- let b = Box::new(456) as Box<dyn Foo>;
- assert!(*b == 456);
-
- // FIXME(alexreg): associated type should be gotten from trait alias definition
- // let c: &dyn I32Iterator = &vec![123].into_iter();
- // assert_eq!(c.next(), Some(123));
-}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(trait_alias)]
+
+trait Foo = PartialEq<i32> + Send;
+trait Bar = Foo + Sync;
+
+trait I32Iterator = Iterator<Item = i32>;
+
+pub fn main() {
+ let a: &dyn Bar = &123;
+ assert!(*a == 123);
+ let b = Box::new(456) as Box<dyn Foo>;
+ assert!(*b == 456);
+
+ let c: &mut dyn I32Iterator = &mut vec![123].into_iter();
+ assert_eq!(c.next(), Some(123));
+}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+pub mod asdf {
+ pub struct SomeStruct;
+}
+
+pub trait SomeTrait {}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+pub struct SomethingElse;
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:use_crate.rs
+// aux-build:use_crate_2.rs
+// build-aux-docs
+// edition:2018
+// compile-flags:--extern use_crate --extern use_crate_2 -Z unstable-options
+
+// During the buildup to Rust 2018, rustdoc would eagerly inline `pub use some_crate;` as if it
+// were a module, so we changed it to make `pub use`ing crate roots remain as a `pub use` statement
+// in docs... unless you added `#[doc(inline)]`.
+
+#![crate_name = "local"]
+
+// @!has-dir local/use_crate
+// @has local/index.html
+// @has - '//code' 'pub use use_crate'
+pub use use_crate;
+
+// @has-dir local/asdf
+// @has local/asdf/index.html
+// @has local/index.html '//a/@href' 'asdf/index.html'
+pub use use_crate::asdf;
+
+// @has-dir local/use_crate_2
+// @has local/use_crate_2/index.html
+// @has local/index.html '//a/@href' 'use_crate_2/index.html'
+#[doc(inline)]
+pub use use_crate_2;
extern crate src_links_external;
// @has foo/bar/index.html '//a/@href' '../../src/src_links_external/src-links-external.rs.html#11'
+#[doc(inline)]
pub use src_links_external as bar;
// @has foo/bar/struct.Foo.html '//a/@href' '../../src/src_links_external/src-links-external.rs.html#11'
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(trait_alias)]
+
+trait I32Iterator = Iterator<Item = i32>;
+
+fn main() {
+ let _: &I32Iterator<Item = u32> = &vec![42].into_iter();
+}
--- /dev/null
+error[E0271]: type mismatch resolving `<std::vec::IntoIter<u32> as std::iter::Iterator>::Item == i32`
+ --> $DIR/associated-types-overridden-binding-2.rs:16:39
+ |
+LL | let _: &I32Iterator<Item = u32> = &vec![42].into_iter();
+ | ^^^^^^^^^^^^^^^^^^^^^ expected u32, found i32
+ |
+ = note: expected type `u32`
+ found type `i32`
+ = note: required for the cast to the object type `dyn I32Iterator<Item=u32, Item=i32>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0271`.
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(trait_alias)]
+
+trait Foo: Iterator<Item = i32> {}
+trait Bar: Foo<Item = u32> {}
+
+trait I32Iterator = Iterator<Item = i32>;
+trait U32Iterator = I32Iterator<Item = u32>;
+
+fn main() {
+ let _: &I32Iterator<Item = u32>;
+}
--- /dev/null
+error[E0284]: type annotations required: cannot resolve `<Self as std::iter::Iterator>::Item == i32`
+ --> $DIR/associated-types-overridden-binding.rs:14:1
+ |
+LL | trait Bar: Foo<Item = u32> {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: required by `Foo`
+ --> $DIR/associated-types-overridden-binding.rs:13:1
+ |
+LL | trait Foo: Iterator<Item = i32> {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0284`.
--- /dev/null
+error[E0382]: use of moved value: `a`
+ --> $DIR/borrowck-box-insensitivity.rs:37:9
+ |
+LL | let _x = a.x;
+ | -- value moved here
+LL | //[ast]~^ value moved here
+LL | let _y = a.y; //[ast]~ ERROR use of moved
+ | ^^ value used here after move
+ |
+ = note: move occurs because `a.x` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+ --> $DIR/borrowck-box-insensitivity.rs:46:9
+ |
+LL | let _x = a.x;
+ | -- value moved here
+LL | //[ast]~^ value moved here
+LL | let _y = a.y; //[ast]~ ERROR use of moved
+ | ^^ value used here after move
+ |
+ = note: move occurs because `a.x` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+ --> $DIR/borrowck-box-insensitivity.rs:55:15
+ |
+LL | let _x = a.x;
+ | -- value moved here
+LL | //[ast]~^ value moved here
+LL | let _y = &a.y; //[ast]~ ERROR use of moved
+ | ^^^ value used here after move
+ |
+ = note: move occurs because `a.x` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
+
+error[E0505]: cannot move out of `a.y` because it is borrowed
+ --> $DIR/borrowck-box-insensitivity.rs:63:9
+ |
+LL | let _x = &a.x;
+ | --- borrow of `a.x` occurs here
+LL | let _y = a.y;
+ | ^^ move out of `a.y` occurs here
+
+error[E0503]: cannot use `a.y` because it was mutably borrowed
+ --> $DIR/borrowck-box-insensitivity.rs:71:9
+ |
+LL | let _x = &mut a.x;
+ | --- borrow of `a.x` occurs here
+LL | let _y = a.y; //[ast]~ ERROR cannot use
+ | ^^ use of borrowed `a.x`
+
+error[E0505]: cannot move out of `a.y` because it is borrowed
+ --> $DIR/borrowck-box-insensitivity.rs:77:9
+ |
+LL | let _x = &mut a.x;
+ | --- borrow of `a.x` occurs here
+LL | let _y = a.y;
+ | ^^ move out of `a.y` occurs here
+
+error[E0502]: cannot borrow `a` (via `a.y`) as immutable because `a` is also borrowed as mutable (via `a.x`)
+ --> $DIR/borrowck-box-insensitivity.rs:85:15
+ |
+LL | let _x = &mut a.x;
+ | --- mutable borrow occurs here (via `a.x`)
+LL | let _y = &a.y; //[ast]~ ERROR cannot borrow
+ | ^^^ immutable borrow occurs here (via `a.y`)
+...
+LL | }
+ | - mutable borrow ends here
+
+error[E0502]: cannot borrow `a` (via `a.y`) as mutable because `a` is also borrowed as immutable (via `a.x`)
+ --> $DIR/borrowck-box-insensitivity.rs:92:19
+ |
+LL | let _x = &a.x;
+ | --- immutable borrow occurs here (via `a.x`)
+LL | let _y = &mut a.y; //[ast]~ ERROR cannot borrow
+ | ^^^ mutable borrow occurs here (via `a.y`)
+...
+LL | }
+ | - immutable borrow ends here
+
+error[E0382]: use of collaterally moved value: `a.y`
+ --> $DIR/borrowck-box-insensitivity.rs:100:9
+ |
+LL | let _x = a.x.x;
+ | -- value moved here
+LL | //[ast]~^ value moved here
+LL | let _y = a.y; //[ast]~ ERROR use of collaterally moved
+ | ^^ value used here after move
+ |
+ = note: move occurs because `a.x.x` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
+
+error[E0382]: use of collaterally moved value: `a.y`
+ --> $DIR/borrowck-box-insensitivity.rs:108:9
+ |
+LL | let _x = a.x.x;
+ | -- value moved here
+LL | //[ast]~^ value moved here
+LL | let _y = a.y; //[ast]~ ERROR use of collaterally moved
+ | ^^ value used here after move
+ |
+ = note: move occurs because `a.x.x` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
+
+error[E0382]: use of collaterally moved value: `a.y`
+ --> $DIR/borrowck-box-insensitivity.rs:116:15
+ |
+LL | let _x = a.x.x;
+ | -- value moved here
+LL | //[ast]~^ value moved here
+LL | let _y = &a.y; //[ast]~ ERROR use of collaterally moved
+ | ^^^ value used here after move
+ |
+ = note: move occurs because `a.x.x` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
+
+error[E0505]: cannot move out of `a.y` because it is borrowed
+ --> $DIR/borrowck-box-insensitivity.rs:124:9
+ |
+LL | let _x = &a.x.x;
+ | ----- borrow of `a.x.x` occurs here
+LL | //[ast]~^ borrow of `a.x.x` occurs here
+LL | let _y = a.y;
+ | ^^ move out of `a.y` occurs here
+
+error[E0503]: cannot use `a.y` because it was mutably borrowed
+ --> $DIR/borrowck-box-insensitivity.rs:132:9
+ |
+LL | let _x = &mut a.x.x;
+ | ----- borrow of `a.x.x` occurs here
+LL | let _y = a.y; //[ast]~ ERROR cannot use
+ | ^^ use of borrowed `a.x.x`
+
+error[E0505]: cannot move out of `a.y` because it is borrowed
+ --> $DIR/borrowck-box-insensitivity.rs:138:9
+ |
+LL | let _x = &mut a.x.x;
+ | ----- borrow of `a.x.x` occurs here
+LL | let _y = a.y;
+ | ^^ move out of `a.y` occurs here
+
+error[E0502]: cannot borrow `a.y` as immutable because `a.x.x` is also borrowed as mutable
+ --> $DIR/borrowck-box-insensitivity.rs:147:15
+ |
+LL | let _x = &mut a.x.x;
+ | ----- mutable borrow occurs here
+LL | //[ast]~^ mutable borrow occurs here
+LL | let _y = &a.y; //[ast]~ ERROR cannot borrow
+ | ^^^ immutable borrow occurs here
+...
+LL | }
+ | - mutable borrow ends here
+
+error[E0502]: cannot borrow `a.y` as mutable because `a.x.x` is also borrowed as immutable
+ --> $DIR/borrowck-box-insensitivity.rs:155:19
+ |
+LL | let _x = &a.x.x;
+ | ----- immutable borrow occurs here
+LL | //[ast]~^ immutable borrow occurs here
+LL | let _y = &mut a.y; //[ast]~ ERROR cannot borrow
+ | ^^^ mutable borrow occurs here
+...
+LL | }
+ | - immutable borrow ends here
+
+error: aborting due to 16 previous errors
+
+Some errors occurred: E0382, E0502, E0503, E0505.
+For more information about an error, try `rustc --explain E0382`.
--- /dev/null
+error: compilation successful
+ --> $DIR/borrowck-box-insensitivity.rs:160:1
+ |
+LL | / fn main() { //[mir]~ ERROR compilation successful
+LL | | copy_after_move();
+LL | | move_after_move();
+LL | | borrow_after_move();
+... |
+LL | | mut_borrow_after_borrow_nested();
+LL | | }
+ | |_^
+
+error: aborting due to previous error
+
-// 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.
+// This test is an artifact of the old policy that `Box<T>` should not
+// be treated specially by the AST-borrowck.
//
-// 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.
+// NLL goes back to treating `Box<T>` specially (namely, knowing that
+// it uniquely owns the data it holds). See rust-lang/rfcs#130.
+// revisions: ast mir
+//[ast] compile-flags: -Z borrowck=ast
+//[mir] compile-flags: -Z borrowck=mir
+// ignore-compare-mode-nll
#![feature(box_syntax, rustc_attrs)]
struct A {
fn copy_after_move() {
let a: Box<_> = box A { x: box 0, y: 1 };
let _x = a.x;
- //~^ value moved here
- let _y = a.y; //~ ERROR use of moved
- //~^ move occurs because `a.x` has type `std::boxed::Box<isize>`
- //~| value used here after move
+ //[ast]~^ value moved here
+ let _y = a.y; //[ast]~ ERROR use of moved
+ //[ast]~^ move occurs because `a.x` has type `std::boxed::Box<isize>`
+ //[ast]~| value used here after move
}
fn move_after_move() {
let a: Box<_> = box B { x: box 0, y: box 1 };
let _x = a.x;
- //~^ value moved here
- let _y = a.y; //~ ERROR use of moved
- //~^ move occurs because `a.x` has type `std::boxed::Box<isize>`
- //~| value used here after move
+ //[ast]~^ value moved here
+ let _y = a.y; //[ast]~ ERROR use of moved
+ //[ast]~^ move occurs because `a.x` has type `std::boxed::Box<isize>`
+ //[ast]~| value used here after move
}
fn borrow_after_move() {
let a: Box<_> = box A { x: box 0, y: 1 };
let _x = a.x;
- //~^ value moved here
- let _y = &a.y; //~ ERROR use of moved
- //~^ move occurs because `a.x` has type `std::boxed::Box<isize>`
- //~| value used here after move
+ //[ast]~^ value moved here
+ let _y = &a.y; //[ast]~ ERROR use of moved
+ //[ast]~^ move occurs because `a.x` has type `std::boxed::Box<isize>`
+ //[ast]~| value used here after move
}
fn move_after_borrow() {
let a: Box<_> = box B { x: box 0, y: box 1 };
let _x = &a.x;
let _y = a.y;
- //~^ ERROR cannot move
- //~| move out of
+ //[ast]~^ ERROR cannot move
+ //[ast]~| move out of
+ use_imm(_x);
}
-
fn copy_after_mut_borrow() {
let mut a: Box<_> = box A { x: box 0, y: 1 };
let _x = &mut a.x;
- let _y = a.y; //~ ERROR cannot use
+ let _y = a.y; //[ast]~ ERROR cannot use
+ use_mut(_x);
}
-
fn move_after_mut_borrow() {
let mut a: Box<_> = box B { x: box 0, y: box 1 };
let _x = &mut a.x;
let _y = a.y;
- //~^ ERROR cannot move
- //~| move out of
+ //[ast]~^ ERROR cannot move
+ //[ast]~| move out of
+ use_mut(_x);
}
-
fn borrow_after_mut_borrow() {
let mut a: Box<_> = box A { x: box 0, y: 1 };
let _x = &mut a.x;
- let _y = &a.y; //~ ERROR cannot borrow
- //~^ immutable borrow occurs here (via `a.y`)
+ let _y = &a.y; //[ast]~ ERROR cannot borrow
+ //[ast]~^ immutable borrow occurs here (via `a.y`)
+ use_mut(_x);
}
-
fn mut_borrow_after_borrow() {
let mut a: Box<_> = box A { x: box 0, y: 1 };
let _x = &a.x;
- let _y = &mut a.y; //~ ERROR cannot borrow
- //~^ mutable borrow occurs here (via `a.y`)
+ let _y = &mut a.y; //[ast]~ ERROR cannot borrow
+ //[ast]~^ mutable borrow occurs here (via `a.y`)
+ use_imm(_x);
}
-
fn copy_after_move_nested() {
let a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 };
let _x = a.x.x;
- //~^ value moved here
- let _y = a.y; //~ ERROR use of collaterally moved
- //~| value used here after move
+ //[ast]~^ value moved here
+ let _y = a.y; //[ast]~ ERROR use of collaterally moved
+ //[ast]~| value used here after move
}
fn move_after_move_nested() {
let a: Box<_> = box D { x: box A { x: box 0, y: 1 }, y: box 2 };
let _x = a.x.x;
- //~^ value moved here
- let _y = a.y; //~ ERROR use of collaterally moved
- //~| value used here after move
+ //[ast]~^ value moved here
+ let _y = a.y; //[ast]~ ERROR use of collaterally moved
+ //[ast]~| value used here after move
}
fn borrow_after_move_nested() {
let a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 };
let _x = a.x.x;
- //~^ value moved here
- let _y = &a.y; //~ ERROR use of collaterally moved
- //~| value used here after move
+ //[ast]~^ value moved here
+ let _y = &a.y; //[ast]~ ERROR use of collaterally moved
+ //[ast]~| value used here after move
}
fn move_after_borrow_nested() {
let a: Box<_> = box D { x: box A { x: box 0, y: 1 }, y: box 2 };
let _x = &a.x.x;
- //~^ borrow of `a.x.x` occurs here
+ //[ast]~^ borrow of `a.x.x` occurs here
let _y = a.y;
- //~^ ERROR cannot move
- //~| move out of
+ //[ast]~^ ERROR cannot move
+ //[ast]~| move out of
+ use_imm(_x);
}
-
fn copy_after_mut_borrow_nested() {
let mut a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 };
let _x = &mut a.x.x;
- let _y = a.y; //~ ERROR cannot use
+ let _y = a.y; //[ast]~ ERROR cannot use
+ use_mut(_x);
}
-
fn move_after_mut_borrow_nested() {
let mut a: Box<_> = box D { x: box A { x: box 0, y: 1 }, y: box 2 };
let _x = &mut a.x.x;
let _y = a.y;
- //~^ ERROR cannot move
- //~| move out of
+ //[ast]~^ ERROR cannot move
+ //[ast]~| move out of
+ use_mut(_x);
}
-
fn borrow_after_mut_borrow_nested() {
let mut a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 };
let _x = &mut a.x.x;
- //~^ mutable borrow occurs here
- let _y = &a.y; //~ ERROR cannot borrow
- //~^ immutable borrow occurs here
+ //[ast]~^ mutable borrow occurs here
+ let _y = &a.y; //[ast]~ ERROR cannot borrow
+ //[ast]~^ immutable borrow occurs here
+ use_mut(_x);
}
-
fn mut_borrow_after_borrow_nested() {
let mut a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 };
let _x = &a.x.x;
- //~^ immutable borrow occurs here
- let _y = &mut a.y; //~ ERROR cannot borrow
- //~^ mutable borrow occurs here
+ //[ast]~^ immutable borrow occurs here
+ let _y = &mut a.y; //[ast]~ ERROR cannot borrow
+ //[ast]~^ mutable borrow occurs here
+ use_imm(_x);
}
-
#[rustc_error]
-fn main() {
+fn main() { //[mir]~ ERROR compilation successful
copy_after_move();
move_after_move();
borrow_after_move();
borrow_after_mut_borrow_nested();
mut_borrow_after_borrow_nested();
}
+
+fn use_mut<T>(_: &mut T) { }
+fn use_imm<T>(_: &T) { }
+++ /dev/null
-error[E0382]: use of moved value: `a`
- --> $DIR/borrowck-box-insensitivity.rs:37:9
- |
-LL | let _x = a.x;
- | -- value moved here
-LL | //~^ value moved here
-LL | let _y = a.y; //~ ERROR use of moved
- | ^^ value used here after move
- |
- = note: move occurs because `a.x` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
-
-error[E0382]: use of moved value: `a`
- --> $DIR/borrowck-box-insensitivity.rs:46:9
- |
-LL | let _x = a.x;
- | -- value moved here
-LL | //~^ value moved here
-LL | let _y = a.y; //~ ERROR use of moved
- | ^^ value used here after move
- |
- = note: move occurs because `a.x` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
-
-error[E0382]: use of moved value: `a`
- --> $DIR/borrowck-box-insensitivity.rs:55:15
- |
-LL | let _x = a.x;
- | -- value moved here
-LL | //~^ value moved here
-LL | let _y = &a.y; //~ ERROR use of moved
- | ^^^ value used here after move
- |
- = note: move occurs because `a.x` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
-
-error[E0505]: cannot move out of `a.y` because it is borrowed
- --> $DIR/borrowck-box-insensitivity.rs:63:9
- |
-LL | let _x = &a.x;
- | --- borrow of `a.x` occurs here
-LL | let _y = a.y;
- | ^^ move out of `a.y` occurs here
-
-error[E0503]: cannot use `a.y` because it was mutably borrowed
- --> $DIR/borrowck-box-insensitivity.rs:71:9
- |
-LL | let _x = &mut a.x;
- | --- borrow of `a.x` occurs here
-LL | let _y = a.y; //~ ERROR cannot use
- | ^^ use of borrowed `a.x`
-
-error[E0505]: cannot move out of `a.y` because it is borrowed
- --> $DIR/borrowck-box-insensitivity.rs:77:9
- |
-LL | let _x = &mut a.x;
- | --- borrow of `a.x` occurs here
-LL | let _y = a.y;
- | ^^ move out of `a.y` occurs here
-
-error[E0502]: cannot borrow `a` (via `a.y`) as immutable because `a` is also borrowed as mutable (via `a.x`)
- --> $DIR/borrowck-box-insensitivity.rs:85:15
- |
-LL | let _x = &mut a.x;
- | --- mutable borrow occurs here (via `a.x`)
-LL | let _y = &a.y; //~ ERROR cannot borrow
- | ^^^ immutable borrow occurs here (via `a.y`)
-LL | //~^ immutable borrow occurs here (via `a.y`)
-LL | }
- | - mutable borrow ends here
-
-error[E0502]: cannot borrow `a` (via `a.y`) as mutable because `a` is also borrowed as immutable (via `a.x`)
- --> $DIR/borrowck-box-insensitivity.rs:92:19
- |
-LL | let _x = &a.x;
- | --- immutable borrow occurs here (via `a.x`)
-LL | let _y = &mut a.y; //~ ERROR cannot borrow
- | ^^^ mutable borrow occurs here (via `a.y`)
-LL | //~^ mutable borrow occurs here (via `a.y`)
-LL | }
- | - immutable borrow ends here
-
-error[E0382]: use of collaterally moved value: `a.y`
- --> $DIR/borrowck-box-insensitivity.rs:100:9
- |
-LL | let _x = a.x.x;
- | -- value moved here
-LL | //~^ value moved here
-LL | let _y = a.y; //~ ERROR use of collaterally moved
- | ^^ value used here after move
- |
- = note: move occurs because `a.x.x` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
-
-error[E0382]: use of collaterally moved value: `a.y`
- --> $DIR/borrowck-box-insensitivity.rs:108:9
- |
-LL | let _x = a.x.x;
- | -- value moved here
-LL | //~^ value moved here
-LL | let _y = a.y; //~ ERROR use of collaterally moved
- | ^^ value used here after move
- |
- = note: move occurs because `a.x.x` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
-
-error[E0382]: use of collaterally moved value: `a.y`
- --> $DIR/borrowck-box-insensitivity.rs:116:15
- |
-LL | let _x = a.x.x;
- | -- value moved here
-LL | //~^ value moved here
-LL | let _y = &a.y; //~ ERROR use of collaterally moved
- | ^^^ value used here after move
- |
- = note: move occurs because `a.x.x` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
-
-error[E0505]: cannot move out of `a.y` because it is borrowed
- --> $DIR/borrowck-box-insensitivity.rs:124:9
- |
-LL | let _x = &a.x.x;
- | ----- borrow of `a.x.x` occurs here
-LL | //~^ borrow of `a.x.x` occurs here
-LL | let _y = a.y;
- | ^^ move out of `a.y` occurs here
-
-error[E0503]: cannot use `a.y` because it was mutably borrowed
- --> $DIR/borrowck-box-insensitivity.rs:132:9
- |
-LL | let _x = &mut a.x.x;
- | ----- borrow of `a.x.x` occurs here
-LL | let _y = a.y; //~ ERROR cannot use
- | ^^ use of borrowed `a.x.x`
-
-error[E0505]: cannot move out of `a.y` because it is borrowed
- --> $DIR/borrowck-box-insensitivity.rs:138:9
- |
-LL | let _x = &mut a.x.x;
- | ----- borrow of `a.x.x` occurs here
-LL | let _y = a.y;
- | ^^ move out of `a.y` occurs here
-
-error[E0502]: cannot borrow `a.y` as immutable because `a.x.x` is also borrowed as mutable
- --> $DIR/borrowck-box-insensitivity.rs:147:15
- |
-LL | let _x = &mut a.x.x;
- | ----- mutable borrow occurs here
-LL | //~^ mutable borrow occurs here
-LL | let _y = &a.y; //~ ERROR cannot borrow
- | ^^^ immutable borrow occurs here
-LL | //~^ immutable borrow occurs here
-LL | }
- | - mutable borrow ends here
-
-error[E0502]: cannot borrow `a.y` as mutable because `a.x.x` is also borrowed as immutable
- --> $DIR/borrowck-box-insensitivity.rs:155:19
- |
-LL | let _x = &a.x.x;
- | ----- immutable borrow occurs here
-LL | //~^ immutable borrow occurs here
-LL | let _y = &mut a.y; //~ ERROR cannot borrow
- | ^^^ mutable borrow occurs here
-LL | //~^ mutable borrow occurs here
-LL | }
- | - immutable borrow ends here
-
-error: aborting due to 16 previous errors
-
-Some errors occurred: E0382, E0502, E0503, E0505.
-For more information about an error, try `rustc --explain E0382`.
|
= note: move occurs because `u` has type `U`, which does not implement the `Copy` trait
-error[E0382]: use of moved value: `u`
- --> $DIR/borrowck-union-move-assign.rs:33:21
- |
-LL | let a = u.a;
- | --- value moved here
-LL | u.a = A;
-LL | let a = u.a; // OK
- | ^^^ value used here after move
- |
- = note: move occurs because `u` has type `U`, which does not implement the `Copy` trait
-
-error[E0382]: use of moved value: `u`
- --> $DIR/borrowck-union-move-assign.rs:39:21
- |
-LL | let a = u.a;
- | --- value moved here
-LL | u.b = B;
-LL | let a = u.a; // OK
- | ^^^ value used here after move
- |
- = note: move occurs because `u` has type `U`, which does not implement the `Copy` trait
-
-error: aborting due to 3 previous errors
+error: aborting due to previous error
For more information about this error, try `rustc --explain E0382`.
--- /dev/null
+// compile-pass
+
+// rust-lang/rust#55552: The strategy pnkfelix landed in PR #55274
+// (for ensuring that NLL respects user-provided lifetime annotations)
+// did not handle the case where the ascribed type has some expliit
+// wildcards (`_`) mixed in, and it caused an internal compiler error
+// (ICE).
+//
+// This test is just checking that we do not ICE when such things
+// occur.
+
+struct X;
+struct Y;
+struct Z;
+
+struct Pair { x: X, y: Y }
+
+pub fn join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
+where A: FnOnce() -> RA + Send,
+ B: FnOnce() -> RB + Send,
+ RA: Send,
+ RB: Send
+{
+ (oper_a(), oper_b())
+}
+
+fn main() {
+ let ((_x, _y), _z): (_, Z) = join(|| (X, Y), || Z);
+
+ let (Pair { x: _x, y: _y }, Z): (_, Z) = join(|| Pair { x: X, y: Y }, || Z);
+}
LL | x.a = 1; //~ ERROR
| ^^^^^^^ use of possibly uninitialized `x`
-error: aborting due to previous error
+error[E0594]: cannot assign to `x.b`, as `x` is not declared as mutable
+ --> $DIR/reassignment_immutable_fields_overlapping.rs:23:5
+ |
+LL | let x: Foo;
+ | - help: consider changing this to be mutable: `mut x`
+LL | x.a = 1; //~ ERROR
+LL | x.b = 22; //~ ERROR
+ | ^^^^^^^^ cannot assign
+
+error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0381`.
+Some errors occurred: E0381, E0594.
+For more information about an error, try `rustc --explain E0381`.
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: conflicting implementation in crate `core`:
- - impl<'_, T> std::marker::Copy for &T
+ - impl<T> std::marker::Copy for &T
where T: ?Sized;
error[E0119]: conflicting implementations of trait `std::marker::Copy` for type `&[NotSync]`:
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: conflicting implementation in crate `core`:
- - impl<'_, T> std::marker::Copy for &T
+ - impl<T> std::marker::Copy for &T
where T: ?Sized;
error[E0206]: the trait `Copy` may not be implemented for this type
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Crate that exports a const fn. Used for testing cross-crate.
+
+#![feature(staged_api, rustc_attrs)]
+#![stable(since="1.0.0", feature = "mep")]
+
+#![crate_type="rlib"]
+
+#[rustc_promotable]
+#[stable(since="1.0.0", feature = "mep")]
+#[inline]
+pub const fn foo() -> usize { 22 }
+
+#[stable(since="1.0.0", feature = "mep")]
+pub struct Foo(usize);
+
+impl Foo {
+ #[stable(since="1.0.0", feature = "mep")]
+ #[inline]
+ #[rustc_promotable]
+ pub const fn foo() -> usize { 22 }
+}
// compile-pass
-#![feature(duration_getters)]
-
use std::time::Duration;
fn main() {
static FOO: Foo = Foo(UnsafeCell::new(42));
+fn foo() {}
+
static BAR: () = unsafe {
*FOO.0.get() = 5;
- //~^ ERROR calls in statics are limited to constant functions, tuple structs and tuple variants
-
+ //~^ ERROR statements in statics are unstable (see issue #48821)
// This error is caused by a separate bug that the feature gate error is reported
// even though the feature gate "const_let" is active.
- //~| statements in statics are unstable (see issue #48821)
+
+ foo();
+ //~^ ERROR calls in statics are limited to constant functions, tuple structs and tuple variants
};
fn main() {
-error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
- --> $DIR/mod-static-with-const-fn.rs:27:6
- |
-LL | *FOO.0.get() = 5;
- | ^^^^^^^^^^^
-
error[E0658]: statements in statics are unstable (see issue #48821)
- --> $DIR/mod-static-with-const-fn.rs:27:5
+ --> $DIR/mod-static-with-const-fn.rs:29:5
|
LL | *FOO.0.get() = 5;
| ^^^^^^^^^^^^^^^^
|
= help: add #![feature(const_let)] to the crate attributes to enable
+error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
+ --> $DIR/mod-static-with-const-fn.rs:34:5
+ |
+LL | foo();
+ | ^^^^^
+
error: aborting due to 2 previous errors
Some errors occurred: E0015, E0658.
--- /dev/null
+fn main() {
+ [0; 3][3u64 as usize]; //~ ERROR the len is 3 but the index is 3
+}
--- /dev/null
+error: index out of bounds: the len is 3 but the index is 3
+ --> $DIR/const-prop-ice.rs:2:5
+ |
+LL | [0; 3][3u64 as usize]; //~ ERROR the len is 3 but the index is 3
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: #[deny(const_err)] on by default
+
+error: aborting due to previous error
+
--- /dev/null
+fn main() {
+ enum Enum { One=1 }
+ let xs=[0;1 as usize];
+ println!("{}", xs[Enum::One as usize]); //~ ERROR the len is 1 but the index is 1
+}
--- /dev/null
+error: index out of bounds: the len is 1 but the index is 1
+ --> $DIR/const-prop-ice2.rs:4:20
+ |
+LL | println!("{}", xs[Enum::One as usize]); //~ ERROR the len is 1 but the index is 1
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: #[deny(const_err)] on by default
+
+error: aborting due to previous error
+
--- /dev/null
+// compile-pass
+// aux-build:promotable_const_fn_lib.rs
+
+#![feature(nll)]
+
+extern crate promotable_const_fn_lib;
+
+use promotable_const_fn_lib::{foo, Foo};
+
+fn main() {
+ let x: &'static usize = &foo();
+ let x: &'static usize = &Foo::foo();
+}
--- /dev/null
+// compile-pass
+
+#![feature(nll)]
+
+fn main() {
+ let x: &'static u8 = &u8::max_value();
+ let x: &'static u16 = &u16::max_value();
+ let x: &'static u32 = &u32::max_value();
+ let x: &'static u64 = &u64::max_value();
+ let x: &'static u128 = &u128::max_value();
+ let x: &'static usize = &usize::max_value();
+ let x: &'static u8 = &u8::min_value();
+ let x: &'static u16 = &u16::min_value();
+ let x: &'static u32 = &u32::min_value();
+ let x: &'static u64 = &u64::min_value();
+ let x: &'static u128 = &u128::min_value();
+ let x: &'static usize = &usize::min_value();
+ let x: &'static i8 = &i8::max_value();
+ let x: &'static i16 = &i16::max_value();
+ let x: &'static i32 = &i32::max_value();
+ let x: &'static i64 = &i64::max_value();
+ let x: &'static i128 = &i128::max_value();
+ let x: &'static isize = &isize::max_value();
+ let x: &'static i8 = &i8::min_value();
+ let x: &'static i16 = &i16::min_value();
+ let x: &'static i32 = &i32::min_value();
+ let x: &'static i64 = &i64::min_value();
+ let x: &'static i128 = &i128::min_value();
+ let x: &'static isize = &isize::min_value();
+}
--- /dev/null
+use std::cell::*;
+
+// not ok, because this would create a silent constant with interior mutability.
+// the rules could be relaxed in the future
+static FOO: Wrap<*mut u32> = Wrap(Cell::new(42).as_ptr());
+//~^ ERROR cannot borrow a constant which may contain interior mutability
+
+static FOO3: Wrap<Cell<u32>> = Wrap(Cell::new(42));
+// ok
+static FOO4: Wrap<*mut u32> = Wrap(FOO3.0.as_ptr());
+
+// not ok, because the `as_ptr` call takes a reference to a type with interior mutability
+// which is not allowed in constants
+const FOO2: *mut u32 = Cell::new(42).as_ptr();
+//~^ ERROR cannot borrow a constant which may contain interior mutability
+
+struct IMSafeTrustMe(UnsafeCell<u32>);
+unsafe impl Send for IMSafeTrustMe {}
+unsafe impl Sync for IMSafeTrustMe {}
+
+static BAR: IMSafeTrustMe = IMSafeTrustMe(UnsafeCell::new(5));
+
+
+struct Wrap<T>(T);
+unsafe impl<T> Send for Wrap<T> {}
+unsafe impl<T> Sync for Wrap<T> {}
+
+static BAR_PTR: Wrap<*mut u32> = Wrap(BAR.0.get());
+
+fn main() {}
--- /dev/null
+error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
+ --> $DIR/cell.rs:5:35
+ |
+LL | static FOO: Wrap<*mut u32> = Wrap(Cell::new(42).as_ptr());
+ | ^^^^^^^^^^^^^
+
+error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
+ --> $DIR/cell.rs:14:24
+ |
+LL | const FOO2: *mut u32 = Cell::new(42).as_ptr();
+ | ^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0492`.
--- /dev/null
+// run-pass
+
+static X: bool = 'a'.is_ascii();
+static Y: bool = 'ä'.is_ascii();
+
+fn main() {
+ assert!(X);
+ assert!(!Y);
+}
--- /dev/null
+// run-pass
+
+const I: std::iter::Empty<u32> = std::iter::empty();
+
+fn main() {
+ for i in I {
+ panic!("magical value creation: {}", i);
+ }
+}
--- /dev/null
+// compile-pass
+
+struct Wrap<T>(T);
+unsafe impl<T> Send for Wrap<T> {}
+unsafe impl<T> Sync for Wrap<T> {}
+
+static FOO: Wrap<*const u32> = Wrap([42, 44, 46].as_ptr());
+static BAR: Wrap<*const u8> = Wrap("hello".as_ptr());
+
+fn main() {}
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= note: conflicting implementation in crate `core`:
- - impl<'_, T> std::ops::Deref for &T
+ - impl<T> std::ops::Deref for &T
where T: ?Sized;
error[E0210]: type parameter `Foo` must be used as the type parameter for some local type (e.g. `MyStruct<Foo>`)
type Foo = Trait; //~ ERROR E0191
-fn main() {
-}
+fn main() {}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+trait Foo: Iterator<Item = i32, Item = i32> {}
+
+type Unit = ();
+
+fn test() -> Box<Iterator<Item = (), Item = Unit>> {
+ Box::new(None.into_iter())
+}
+
+fn main() {
+ let _: &Iterator<Item = i32, Item = i32>;
+ test();
+}
--- /dev/null
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+ --> $DIR/E0719.rs:11:33
+ |
+LL | trait Foo: Iterator<Item = i32, Item = i32> {}
+ | ---------- ^^^^^^^^^^ re-bound here
+ | |
+ | `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
+ --> $DIR/E0719.rs:15:38
+ |
+LL | fn test() -> Box<Iterator<Item = (), Item = Unit>> {
+ | --------- ^^^^^^^^^^^ re-bound here
+ | |
+ | `Item` bound here first
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0719`.
--- /dev/null
+// Check extern items cannot be const + `rustfix` suggests using
+// extern static.
+//
+// #54388: an unused reference to an undefined static may or may not
+// compile. To sidestep this by using one that *is* defined.
+
+// run-rustfix
+// ignore-wasm32 no external library to link to.
+// compile-flags: -g -Z continue-parse-after-error
+#![feature(libc)]
+extern crate libc;
+
+#[link(name = "rust_test_helpers", kind = "static")]
+extern "C" {
+ static rust_dbg_static_mut: libc::c_int; //~ ERROR extern items cannot be `const`
+}
+
+fn main() {
+ // We suggest turning the (illegal) extern `const` into an extern `static`,
+ // but this also requires `unsafe` (a deny-by-default lint at comment time,
+ // future error; Issue #36247)
+ unsafe {
+ let _x = rust_dbg_static_mut;
+ }
+}
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
+// Check extern items cannot be const + `rustfix` suggests using
+// extern static.
//
-// 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.
+// #54388: an unused reference to an undefined static may or may not
+// compile. To sidestep this by using one that *is* defined.
-// FIXME(#54388): re-enable rustfix later, when this test has consistent output across targets
-// compile-flags: -Z continue-parse-after-error
+// run-rustfix
+// ignore-wasm32 no external library to link to.
+// compile-flags: -g -Z continue-parse-after-error
+#![feature(libc)]
+extern crate libc;
+#[link(name = "rust_test_helpers", kind = "static")]
extern "C" {
- const C: u8; //~ ERROR extern items cannot be `const`
+ const rust_dbg_static_mut: libc::c_int; //~ ERROR extern items cannot be `const`
}
fn main() {
// but this also requires `unsafe` (a deny-by-default lint at comment time,
// future error; Issue #36247)
unsafe {
- let _x = C;
+ let _x = rust_dbg_static_mut;
}
}
error: extern items cannot be `const`
--> $DIR/extern-const.rs:15:5
|
-LL | const C: u8; //~ ERROR extern items cannot be `const`
+LL | const rust_dbg_static_mut: libc::c_int; //~ ERROR extern items cannot be `const`
| ^^^^^ help: try using a static value: `static`
error: aborting due to previous error
--- /dev/null
+// edition:2018
+
+#[no_implicit_prelude]
+mod bar {
+ fn f() {
+ ::std::print!(""); // OK
+ print!(); //~ ERROR cannot find macro `print!` in this scope
+ }
+}
+
+fn main() {}
--- /dev/null
+error: cannot find macro `print!` in this scope
+ --> $DIR/no_implicit_prelude-2018.rs:7:9
+ |
+LL | print!(); //~ ERROR cannot find macro `print!` in this scope
+ | ^^^^^
+ |
+ = help: have you added the `#[macro_use]` on the module/import?
+
+error: aborting due to previous error
+
Vec::new(); //~ ERROR failed to resolve
().clone() //~ ERROR no method named `clone` found
}
- fn f() { ::foo::m!(); }
+ fn f() {
+ ::foo::m!();
+ println!(); // OK on 2015 edition (at least for now)
+ }
}
fn main() {}
--- /dev/null
+// This used to ICE because it creates an `impl Trait` that captures a
+// hidden empty region.
+
+#![feature(conservative_impl_trait)]
+
+fn server() -> impl FilterBase2 { //~ ERROR [E0700]
+ segment2(|| { loop { } }).map2(|| "")
+}
+
+trait FilterBase2 {
+ fn map2<F>(self, _fn: F) -> Map2<F> where Self: Sized { loop { } }
+}
+
+struct Map2<F> { _func: F }
+
+impl<F> FilterBase2 for Map2<F> { }
+
+fn segment2<F>(_fn: F) -> Map2<F> where F: Fn() -> Result<(), ()> {
+ loop { }
+}
+
+fn main() { server(); }
--- /dev/null
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+ --> $DIR/issue-55608-captures-empty-region.rs:6:16
+ |
+LL | fn server() -> impl FilterBase2 { //~ ERROR [E0700]
+ | ^^^^^^^^^^^^^^^^
+ |
+ = note: hidden type `Map2<[closure@$DIR/issue-55608-captures-empty-region.rs:7:36: 7:41]>` captures an empty lifetime
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0700`.
// Test that the compiler will catch invalid inline assembly constraints.
+// ignore-emscripten
+
#![feature(asm)]
extern "C" {
error[E0668]: malformed inline assembly
- --> $DIR/inline-asm-bad-constraint.rs:29:9
+ --> $DIR/inline-asm-bad-constraint.rs:31:9
|
LL | asm!("" :"={rax"(rax)) //~ ERROR E0668
| ^^^^^^^^^^^^^^^^^^^^^^
error[E0668]: malformed inline assembly
- --> $DIR/inline-asm-bad-constraint.rs:37:9
+ --> $DIR/inline-asm-bad-constraint.rs:39:9
|
LL | asm!("callq $0" : : "0"(foo)) //~ ERROR E0668
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0668]: malformed inline assembly
- --> $DIR/inline-asm-bad-constraint.rs:44:9
+ --> $DIR/inline-asm-bad-constraint.rs:46:9
|
LL | asm!("addb $1, $0" : "={rax}"((0i32, rax))); //~ ERROR E0668
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Test that the compiler will catch passing invalid values to inline assembly
// operands.
+// ignore-emscripten
+
#![feature(asm)]
#[repr(C)]
error[E0669]: invalid value for constraint in inline assembly
- --> $DIR/inline-asm-bad-operand.rs:29:24
+ --> $DIR/inline-asm-bad-operand.rs:31:24
|
LL | asm!("" :: "r"("")); //~ ERROR E0669
| ^^
error[E0669]: invalid value for constraint in inline assembly
- --> $DIR/inline-asm-bad-operand.rs:34:32
+ --> $DIR/inline-asm-bad-operand.rs:36:32
|
LL | asm!("ret" : : "{rdi}"(target)); //~ ERROR E0669
| ^^^^^^
error[E0669]: invalid value for constraint in inline assembly
- --> $DIR/inline-asm-bad-operand.rs:41:29
+ --> $DIR/inline-asm-bad-operand.rs:43:29
|
LL | unsafe { asm!("" :: "i"(hello)) }; //~ ERROR E0669
| ^^^^^
error[E0669]: invalid value for constraint in inline assembly
- --> $DIR/inline-asm-bad-operand.rs:49:38
+ --> $DIR/inline-asm-bad-operand.rs:51:38
|
LL | asm!("movups $1, %xmm0"::"m"(arr)); //~ ERROR E0669
| ^^^
error[E0669]: invalid value for constraint in inline assembly
- --> $DIR/inline-asm-bad-operand.rs:56:32
+ --> $DIR/inline-asm-bad-operand.rs:58:32
|
LL | asm!("mov sp, $0"::"r"(addr)); //~ ERROR E0669
| ^^^^
error[E0669]: invalid value for constraint in inline assembly
- --> $DIR/inline-asm-bad-operand.rs:63:32
+ --> $DIR/inline-asm-bad-operand.rs:65:32
|
LL | asm!("mov sp, $0"::"r"(addr), //~ ERROR E0669
| ^^^^
error[E0669]: invalid value for constraint in inline assembly
- --> $DIR/inline-asm-bad-operand.rs:64:32
+ --> $DIR/inline-asm-bad-operand.rs:66:32
|
LL | "r"("hello e0669")); //~ ERROR E0669
| ^^^^^^^^^^^^^
+++ /dev/null
-// compile-pass
-
-#![crate_type = "lib"]
-#![feature(linkage)]
-
-// MergeFunctions will merge these via an anonymous internal
-// backing function, which must be named if ThinLTO buffers are used
-
-#[linkage = "weak"]
-pub fn fn1(a: u32, b: u32, c: u32) -> u32 {
- a + b + c
-}
-
-#[linkage = "weak"]
-pub fn fn2(a: u32, b: u32, c: u32) -> u32 {
- a + b + c
-}
-error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<T as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next`
+error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<T as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: std::marker::Sized`
--> $DIR/issue-23122-2.rs:17:15
|
LL | impl<T: Next> Next for GetNext<T> {
| ^^^^
|
= help: consider adding a `#![recursion_limit="128"]` attribute to your crate
+ = note: required because of the requirements on the impl of `Next` for `GetNext<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<T as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>`
error: aborting due to previous error
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
// compile-pass
+// ignore-emscripten no i128 support
#![feature(nll)]
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-pass
+
+#![crate_type = "lib"]
+#![feature(linkage)]
+
+// MergeFunctions will merge these via an anonymous internal
+// backing function, which must be named if ThinLTO buffers are used
+
+#[linkage = "weak"]
+pub fn fn1(a: u32, b: u32, c: u32) -> u32 {
+ a + b + c
+}
+
+#[linkage = "weak"]
+pub fn fn2(a: u32, b: u32, c: u32) -> u32 {
+ a + b + c
+}
--- /dev/null
+pub trait EdgeTrait<N> {
+ fn target(&self) -> N;
+}
+
+pub trait Graph<'a> {
+ type Node;
+ type Edge: EdgeTrait<Self::Node>;
+ type NodesIter: Iterator<Item = Self::Node> + 'a;
+ type EdgesIter: Iterator<Item = Self::Edge> + 'a;
+
+ fn nodes(&'a self) -> Self::NodesIter;
+ fn out_edges(&'a self, u: &Self::Node) -> Self::EdgesIter;
+ fn in_edges(&'a self, u: &Self::Node) -> Self::EdgesIter;
+
+ fn out_neighbors(&'a self, u: &Self::Node) -> Box<Iterator<Item = Self::Node>> {
+ Box::new(self.out_edges(u).map(|e| e.target()))
+ }
+
+ fn in_neighbors(&'a self, u: &Self::Node) -> Box<Iterator<Item = Self::Node>> {
+ Box::new(self.in_edges(u).map(|e| e.target()))
+ }
+}
--- /dev/null
+error[E0601]: `main` function not found in crate `issue_55796`
+ |
+ = note: consider adding a `main` function to `$DIR/issue-55796.rs`
+
+error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
+ --> $DIR/issue-55796.rs:16:9
+ |
+LL | Box::new(self.out_edges(u).map(|e| e.target()))
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: first, the lifetime cannot outlive the lifetime 'a as defined on the trait at 5:17...
+ --> $DIR/issue-55796.rs:5:17
+ |
+LL | pub trait Graph<'a> {
+ | ^^
+note: ...so that the type `std::iter::Map<<Self as Graph<'a>>::EdgesIter, [closure@$DIR/issue-55796.rs:16:40: 16:54]>` will meet its required lifetime bounds
+ --> $DIR/issue-55796.rs:16:9
+ |
+LL | Box::new(self.out_edges(u).map(|e| e.target()))
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: but, the lifetime must be valid for the static lifetime...
+ = note: ...so that the expression is assignable:
+ expected std::boxed::Box<(dyn std::iter::Iterator<Item=<Self as Graph<'a>>::Node> + 'static)>
+ found std::boxed::Box<dyn std::iter::Iterator<Item=<Self as Graph<'a>>::Node>>
+
+error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
+ --> $DIR/issue-55796.rs:20:9
+ |
+LL | Box::new(self.in_edges(u).map(|e| e.target()))
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: first, the lifetime cannot outlive the lifetime 'a as defined on the trait at 5:17...
+ --> $DIR/issue-55796.rs:5:17
+ |
+LL | pub trait Graph<'a> {
+ | ^^
+note: ...so that the type `std::iter::Map<<Self as Graph<'a>>::EdgesIter, [closure@$DIR/issue-55796.rs:20:39: 20:53]>` will meet its required lifetime bounds
+ --> $DIR/issue-55796.rs:20:9
+ |
+LL | Box::new(self.in_edges(u).map(|e| e.target()))
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: but, the lifetime must be valid for the static lifetime...
+ = note: ...so that the expression is assignable:
+ expected std::boxed::Box<(dyn std::iter::Iterator<Item=<Self as Graph<'a>>::Node> + 'static)>
+ found std::boxed::Box<dyn std::iter::Iterator<Item=<Self as Graph<'a>>::Node>>
+
+error: aborting due to 3 previous errors
+
+Some errors occurred: E0495, E0601.
+For more information about an error, try `rustc --explain E0495`.
+++ /dev/null
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// compile-pass
-
-use std::iter::Iterator;
-
-type Unit = ();
-
-fn test() -> Box<Iterator<Item = (), Item = Unit>> {
- Box::new(None.into_iter())
-}
-
-fn main() {
- test();
-}
+++ /dev/null
-warning: associated type binding `Item` specified more than once
- --> $DIR/issue-50589-multiple-associated-types.rs:17:39
- |
-LL | fn test() -> Box<Iterator<Item = (), Item = Unit>> {
- | --------- ^^^^^^^^^^^ used more than once
- | |
- | first use of `Item`
- |
- = note: #[warn(duplicate_associated_type_bindings)] on by default
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #50589 <https://github.com/rust-lang/rust/issues/50589>
-
-warning: associated type binding `Item` specified more than once
- --> $DIR/issue-50589-multiple-associated-types.rs:17:39
- |
-LL | fn test() -> Box<Iterator<Item = (), Item = Unit>> {
- | --------- ^^^^^^^^^^^ used more than once
- | |
- | first use of `Item`
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #50589 <https://github.com/rust-lang/rust/issues/50589>
-
+++ /dev/null
-error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:59:14
- |
-LL | let x = |mut y: isize| 10; //[lexical]~ ERROR: variable does not need to be mutable
- | ----^
- | |
- | help: remove this `mut`
- |
-note: lint level defined here
- --> $DIR/lint-unused-mut-variables.rs:19:9
- |
-LL | #![deny(unused_mut)]
- | ^^^^^^^^^^
-
-error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:24:9
- |
-LL | let mut a = 3; //[lexical]~ ERROR: variable does not need to be mutable
- | ----^
- | |
- | help: remove this `mut`
-
-error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:26:9
- |
-LL | let mut a = 2; //[lexical]~ ERROR: variable does not need to be mutable
- | ----^
- | |
- | help: remove this `mut`
-
-error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:28:9
- |
-LL | let mut b = 3; //[lexical]~ ERROR: variable does not need to be mutable
- | ----^
- | |
- | help: remove this `mut`
-
-error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:30:9
- |
-LL | let mut a = vec![3]; //[lexical]~ ERROR: variable does not need to be mutable
- | ----^
- | |
- | help: remove this `mut`
-
-error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:32:10
- |
-LL | let (mut a, b) = (1, 2); //[lexical]~ ERROR: variable does not need to be mutable
- | ----^
- | |
- | help: remove this `mut`
-
-error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:34:9
- |
-LL | let mut a; //[lexical]~ ERROR: variable does not need to be mutable
- | ----^
- | |
- | help: remove this `mut`
-
-error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:38:9
- |
-LL | let mut b; //[lexical]~ ERROR: variable does not need to be mutable
- | ----^
- | |
- | help: remove this `mut`
-
-error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:47:9
- |
-LL | mut x => {} //[lexical]~ ERROR: variable does not need to be mutable
- | ----^
- | |
- | help: remove this `mut`
-
-error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:51:8
- |
-LL | (mut x, 1) | //[lexical]~ ERROR: variable does not need to be mutable
- | ----^
- | |
- | help: remove this `mut`
-
-error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:64:9
- |
-LL | let mut a = &mut 5; //[lexical]~ ERROR: variable does not need to be mutable
- | ----^
- | |
- | help: remove this `mut`
-
-error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:69:9
- |
-LL | let mut b = (&mut a,); //[lexical]~ ERROR: variable does not need to be mutable
- | ----^
- | |
- | help: remove this `mut`
-
-error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:72:9
- |
-LL | let mut x = &mut 1; //[lexical]~ ERROR: variable does not need to be mutable
- | ----^
- | |
- | help: remove this `mut`
-
-error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:84:9
- |
-LL | let mut v : &mut Vec<()> = &mut vec![]; //[lexical]~ ERROR: variable does not need to be mutable
- | ----^
- | |
- | help: remove this `mut`
-
-error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:61:13
- |
-LL | fn what(mut foo: isize) {} //[lexical]~ ERROR: variable does not need to be mutable
- | ----^^^
- | |
- | help: remove this `mut`
-
-error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:79:20
- |
-LL | fn mut_ref_arg(mut arg : &mut [u8]) -> &mut [u8] {
- | ----^^^
- | |
- | help: remove this `mut`
-
-error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:143:9
- |
-LL | let mut b = vec![2]; //[lexical]~ ERROR: variable does not need to be mutable
- | ----^
- | |
- | help: remove this `mut`
- |
-note: lint level defined here
- --> $DIR/lint-unused-mut-variables.rs:139:8
- |
-LL | #[deny(unused_mut)]
- | ^^^^^^^^^^
-
-error: aborting due to 17 previous errors
-
+++ /dev/null
-error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:59:14
- |
-LL | let x = |mut y: isize| 10; //[lexical]~ ERROR: variable does not need to be mutable
- | ----^
- | |
- | help: remove this `mut`
- |
-note: lint level defined here
- --> $DIR/lint-unused-mut-variables.rs:19:9
- |
-LL | #![deny(unused_mut)]
- | ^^^^^^^^^^
-
-error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:24:9
- |
-LL | let mut a = 3; //[lexical]~ ERROR: variable does not need to be mutable
- | ----^
- | |
- | help: remove this `mut`
-
-error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:26:9
- |
-LL | let mut a = 2; //[lexical]~ ERROR: variable does not need to be mutable
- | ----^
- | |
- | help: remove this `mut`
-
-error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:28:9
- |
-LL | let mut b = 3; //[lexical]~ ERROR: variable does not need to be mutable
- | ----^
- | |
- | help: remove this `mut`
-
-error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:30:9
- |
-LL | let mut a = vec![3]; //[lexical]~ ERROR: variable does not need to be mutable
- | ----^
- | |
- | help: remove this `mut`
-
-error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:32:10
- |
-LL | let (mut a, b) = (1, 2); //[lexical]~ ERROR: variable does not need to be mutable
- | ----^
- | |
- | help: remove this `mut`
-
-error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:34:9
- |
-LL | let mut a; //[lexical]~ ERROR: variable does not need to be mutable
- | ----^
- | |
- | help: remove this `mut`
-
-error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:38:9
- |
-LL | let mut b; //[lexical]~ ERROR: variable does not need to be mutable
- | ----^
- | |
- | help: remove this `mut`
-
-error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:47:9
- |
-LL | mut x => {} //[lexical]~ ERROR: variable does not need to be mutable
- | ----^
- | |
- | help: remove this `mut`
-
-error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:51:8
- |
-LL | (mut x, 1) | //[lexical]~ ERROR: variable does not need to be mutable
- | ----^
- | |
- | help: remove this `mut`
-
-error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:64:9
- |
-LL | let mut a = &mut 5; //[lexical]~ ERROR: variable does not need to be mutable
- | ----^
- | |
- | help: remove this `mut`
-
-error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:69:9
- |
-LL | let mut b = (&mut a,); //[lexical]~ ERROR: variable does not need to be mutable
- | ----^
- | |
- | help: remove this `mut`
-
-error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:72:9
- |
-LL | let mut x = &mut 1; //[lexical]~ ERROR: variable does not need to be mutable
- | ----^
- | |
- | help: remove this `mut`
-
-error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:84:9
- |
-LL | let mut v : &mut Vec<()> = &mut vec![]; //[lexical]~ ERROR: variable does not need to be mutable
- | ----^
- | |
- | help: remove this `mut`
-
-error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:61:13
- |
-LL | fn what(mut foo: isize) {} //[lexical]~ ERROR: variable does not need to be mutable
- | ----^^^
- | |
- | help: remove this `mut`
-
-error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:79:20
- |
-LL | fn mut_ref_arg(mut arg : &mut [u8]) -> &mut [u8] {
- | ----^^^
- | |
- | help: remove this `mut`
-
-error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:143:9
- |
-LL | let mut b = vec![2]; //[lexical]~ ERROR: variable does not need to be mutable
- | ----^
- | |
- | help: remove this `mut`
- |
-note: lint level defined here
- --> $DIR/lint-unused-mut-variables.rs:139:8
- |
-LL | #[deny(unused_mut)]
- | ^^^^^^^^^^
-
-error: aborting due to 17 previous errors
-
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// revisions: lexical nll
-#![cfg_attr(nll, feature(nll))]
+
+
// Exercise the unused_mut attribute in some positive and negative cases
fn main() {
// negative cases
- let mut a = 3; //[lexical]~ ERROR: variable does not need to be mutable
- //[nll]~^ ERROR: variable does not need to be mutable
- let mut a = 2; //[lexical]~ ERROR: variable does not need to be mutable
- //[nll]~^ ERROR: variable does not need to be mutable
- let mut b = 3; //[lexical]~ ERROR: variable does not need to be mutable
- //[nll]~^ ERROR: variable does not need to be mutable
- let mut a = vec![3]; //[lexical]~ ERROR: variable does not need to be mutable
- //[nll]~^ ERROR: variable does not need to be mutable
- let (mut a, b) = (1, 2); //[lexical]~ ERROR: variable does not need to be mutable
- //[nll]~^ ERROR: variable does not need to be mutable
- let mut a; //[lexical]~ ERROR: variable does not need to be mutable
- //[nll]~^ ERROR: variable does not need to be mutable
+ let mut a = 3; //~ ERROR: variable does not need to be mutable
+
+ let mut a = 2; //~ ERROR: variable does not need to be mutable
+
+ let mut b = 3; //~ ERROR: variable does not need to be mutable
+
+ let mut a = vec![3]; //~ ERROR: variable does not need to be mutable
+
+ let (mut a, b) = (1, 2); //~ ERROR: variable does not need to be mutable
+
+ let mut a; //~ ERROR: variable does not need to be mutable
+
a = 3;
- let mut b; //[lexical]~ ERROR: variable does not need to be mutable
- //[nll]~^ ERROR: variable does not need to be mutable
+ let mut b; //~ ERROR: variable does not need to be mutable
+
if true {
b = 3;
} else {
}
match 30 {
- mut x => {} //[lexical]~ ERROR: variable does not need to be mutable
- //[nll]~^ ERROR: variable does not need to be mutable
+ mut x => {} //~ ERROR: variable does not need to be mutable
+
}
match (30, 2) {
- (mut x, 1) | //[lexical]~ ERROR: variable does not need to be mutable
- //[nll]~^ ERROR: variable does not need to be mutable
+ (mut x, 1) | //~ ERROR: variable does not need to be mutable
+
(mut x, 2) |
(mut x, 3) => {
}
_ => {}
}
- let x = |mut y: isize| 10; //[lexical]~ ERROR: variable does not need to be mutable
- //[nll]~^ ERROR: variable does not need to be mutable
- fn what(mut foo: isize) {} //[lexical]~ ERROR: variable does not need to be mutable
- //[nll]~^ ERROR: variable does not need to be mutable
+ let x = |mut y: isize| 10; //~ ERROR: variable does not need to be mutable
+
+ fn what(mut foo: isize) {} //~ ERROR: variable does not need to be mutable
+
+
+ let mut a = &mut 5; //~ ERROR: variable does not need to be mutable
- let mut a = &mut 5; //[lexical]~ ERROR: variable does not need to be mutable
- //[nll]~^ ERROR: variable does not need to be mutable
*a = 4;
let mut a = 5;
- let mut b = (&mut a,); //[lexical]~ ERROR: variable does not need to be mutable
- *b.0 = 4; //[nll]~^ ERROR: variable does not need to be mutable
+ let mut b = (&mut a,); //~ ERROR: variable does not need to be mutable
+ *b.0 = 4;
+
+ let mut x = &mut 1; //~ ERROR: variable does not need to be mutable
- let mut x = &mut 1; //[lexical]~ ERROR: variable does not need to be mutable
- //[nll]~^ ERROR: variable does not need to be mutable
let mut f = || {
*x += 1;
};
f();
fn mut_ref_arg(mut arg : &mut [u8]) -> &mut [u8] {
- &mut arg[..] //[lexical]~^ ERROR: variable does not need to be mutable
- //[nll]~^^ ERROR: variable does not need to be mutable
+ &mut arg[..] //~^ ERROR: variable does not need to be mutable
+
}
- let mut v : &mut Vec<()> = &mut vec![]; //[lexical]~ ERROR: variable does not need to be mutable
- //[nll]~^ ERROR: variable does not need to be mutable
+ let mut v : &mut Vec<()> = &mut vec![]; //~ ERROR: variable does not need to be mutable
+
v.push(());
// positive cases
fn bar() {
#[allow(unused_mut)]
let mut a = 3;
- let mut b = vec![2]; //[lexical]~ ERROR: variable does not need to be mutable
- //[nll]~^ ERROR: variable does not need to be mutable
+ let mut b = vec![2]; //~ ERROR: variable does not need to be mutable
+
}
--- /dev/null
+error: variable does not need to be mutable
+ --> $DIR/lint-unused-mut-variables.rs:59:14
+ |
+LL | let x = |mut y: isize| 10; //~ ERROR: variable does not need to be mutable
+ | ----^
+ | |
+ | help: remove this `mut`
+ |
+note: lint level defined here
+ --> $DIR/lint-unused-mut-variables.rs:19:9
+ |
+LL | #![deny(unused_mut)]
+ | ^^^^^^^^^^
+
+error: variable does not need to be mutable
+ --> $DIR/lint-unused-mut-variables.rs:24:9
+ |
+LL | let mut a = 3; //~ ERROR: variable does not need to be mutable
+ | ----^
+ | |
+ | help: remove this `mut`
+
+error: variable does not need to be mutable
+ --> $DIR/lint-unused-mut-variables.rs:26:9
+ |
+LL | let mut a = 2; //~ ERROR: variable does not need to be mutable
+ | ----^
+ | |
+ | help: remove this `mut`
+
+error: variable does not need to be mutable
+ --> $DIR/lint-unused-mut-variables.rs:28:9
+ |
+LL | let mut b = 3; //~ ERROR: variable does not need to be mutable
+ | ----^
+ | |
+ | help: remove this `mut`
+
+error: variable does not need to be mutable
+ --> $DIR/lint-unused-mut-variables.rs:30:9
+ |
+LL | let mut a = vec![3]; //~ ERROR: variable does not need to be mutable
+ | ----^
+ | |
+ | help: remove this `mut`
+
+error: variable does not need to be mutable
+ --> $DIR/lint-unused-mut-variables.rs:32:10
+ |
+LL | let (mut a, b) = (1, 2); //~ ERROR: variable does not need to be mutable
+ | ----^
+ | |
+ | help: remove this `mut`
+
+error: variable does not need to be mutable
+ --> $DIR/lint-unused-mut-variables.rs:34:9
+ |
+LL | let mut a; //~ ERROR: variable does not need to be mutable
+ | ----^
+ | |
+ | help: remove this `mut`
+
+error: variable does not need to be mutable
+ --> $DIR/lint-unused-mut-variables.rs:38:9
+ |
+LL | let mut b; //~ ERROR: variable does not need to be mutable
+ | ----^
+ | |
+ | help: remove this `mut`
+
+error: variable does not need to be mutable
+ --> $DIR/lint-unused-mut-variables.rs:47:9
+ |
+LL | mut x => {} //~ ERROR: variable does not need to be mutable
+ | ----^
+ | |
+ | help: remove this `mut`
+
+error: variable does not need to be mutable
+ --> $DIR/lint-unused-mut-variables.rs:51:8
+ |
+LL | (mut x, 1) | //~ ERROR: variable does not need to be mutable
+ | ----^
+ | |
+ | help: remove this `mut`
+
+error: variable does not need to be mutable
+ --> $DIR/lint-unused-mut-variables.rs:64:9
+ |
+LL | let mut a = &mut 5; //~ ERROR: variable does not need to be mutable
+ | ----^
+ | |
+ | help: remove this `mut`
+
+error: variable does not need to be mutable
+ --> $DIR/lint-unused-mut-variables.rs:69:9
+ |
+LL | let mut b = (&mut a,); //~ ERROR: variable does not need to be mutable
+ | ----^
+ | |
+ | help: remove this `mut`
+
+error: variable does not need to be mutable
+ --> $DIR/lint-unused-mut-variables.rs:72:9
+ |
+LL | let mut x = &mut 1; //~ ERROR: variable does not need to be mutable
+ | ----^
+ | |
+ | help: remove this `mut`
+
+error: variable does not need to be mutable
+ --> $DIR/lint-unused-mut-variables.rs:84:9
+ |
+LL | let mut v : &mut Vec<()> = &mut vec![]; //~ ERROR: variable does not need to be mutable
+ | ----^
+ | |
+ | help: remove this `mut`
+
+error: variable does not need to be mutable
+ --> $DIR/lint-unused-mut-variables.rs:61:13
+ |
+LL | fn what(mut foo: isize) {} //~ ERROR: variable does not need to be mutable
+ | ----^^^
+ | |
+ | help: remove this `mut`
+
+error: variable does not need to be mutable
+ --> $DIR/lint-unused-mut-variables.rs:79:20
+ |
+LL | fn mut_ref_arg(mut arg : &mut [u8]) -> &mut [u8] {
+ | ----^^^
+ | |
+ | help: remove this `mut`
+
+error: variable does not need to be mutable
+ --> $DIR/lint-unused-mut-variables.rs:143:9
+ |
+LL | let mut b = vec![2]; //~ ERROR: variable does not need to be mutable
+ | ----^
+ | |
+ | help: remove this `mut`
+ |
+note: lint level defined here
+ --> $DIR/lint-unused-mut-variables.rs:139:8
+ |
+LL | #[deny(unused_mut)]
+ | ^^^^^^^^^^
+
+error: aborting due to 17 previous errors
+
--- /dev/null
+use std::path::Path;
+
+fn main() {
+ let path = Path::new("foo");
+ match path {
+ Path::new("foo") => println!("foo"),
+ //~^ ERROR expected tuple struct/variant
+ Path::new("bar") => println!("bar"),
+ //~^ ERROR expected tuple struct/variant
+ _ => (),
+ }
+}
--- /dev/null
+error[E0164]: expected tuple struct/variant, found method `<Path>::new`
+ --> $DIR/match-fn-call.rs:6:9
+ |
+LL | Path::new("foo") => println!("foo"),
+ | ^^^^^^^^^^^^^^^^ not a tuple variant or struct
+
+error[E0164]: expected tuple struct/variant, found method `<Path>::new`
+ --> $DIR/match-fn-call.rs:8:9
+ |
+LL | Path::new("bar") => println!("bar"),
+ | ^^^^^^^^^^^^^^^^ not a tuple variant or struct
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0164`.
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-pass
+
+#![feature(nll)]
+#![allow(unreachable_code)]
+#![deny(unused_mut)]
+
+pub fn foo() {
+ return;
+
+ let mut v = 0;
+ assert_eq!(v, 0);
+ v = 1;
+ assert_eq!(v, 1);
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(nll)]
+
+struct Bar;
+
+struct Foo<'s> {
+ bar: &'s mut Bar,
+}
+
+impl Foo<'_> {
+ fn new(bar: &mut Bar) -> Self {
+ Foo { bar }
+ }
+}
+
+fn main() { }
--- /dev/null
+error: unsatisfied lifetime constraints
+ --> $DIR/issue-55394.rs:21:9
+ |
+LL | fn new(bar: &mut Bar) -> Self {
+ | - ---- return type is Foo<'2>
+ | |
+ | let's call the lifetime of this reference `'1`
+LL | Foo { bar }
+ | ^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
+
+error: aborting due to previous error
+
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-pass
+
+#![feature(untagged_unions)]
+
+struct A;
+struct B;
+
+union U {
+ a: A,
+ b: B,
+}
+
+fn main() {
+ unsafe {
+ {
+ let mut u = U { a: A };
+ let a = u.a;
+ u.a = A;
+ let a = u.a; // OK
+ }
+ {
+ let mut u = U { a: A };
+ let a = u.a;
+ u.b = B;
+ let a = u.a; // OK
+ }
+ }
+}
use core::ops::RangeBounds;
-#[cfg(not(target_arch = "wasm32"))]
+#[cfg(any(not(target_arch = "wasm32"), target_os = "emscripten"))]
#[lang = "eh_personality"]
extern fn eh_personality() {}
+++ /dev/null
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <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 should fail since identity is not stable as a const fn yet.
-
-#![feature(convert_id)]
-
-fn main() {
- const _FOO: u8 = ::std::convert::identity(42u8);
-}
+++ /dev/null
-error: `std::convert::identity` is not yet stable as a const fn
- --> $DIR/convert-id-const-no-gate.rs:16:22
- |
-LL | const _FOO: u8 = ::std::convert::identity(42u8);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: in Nightly builds, add `#![feature(const_convert_id)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// This test should pass since we've opted into 'identity' as an
-// unstable const fn.
+// This test should pass since 'identity' is const fn.
// compile-pass
-#![feature(convert_id, const_convert_id)]
+#![feature(convert_id)]
fn main() {
const _FOO: u8 = ::std::convert::identity(42u8);
--- /dev/null
+// run-pass
+
+// This file checks that `PhantomData` is considered structurally matchable.
+
+use std::marker::PhantomData;
+
+fn main() {
+ let mut count = 0;
+
+ // A type which is not structurally matchable:
+ struct NotSM;
+
+ // And one that is:
+ #[derive(PartialEq, Eq)]
+ struct SM;
+
+ // Check that SM is #[structural_match]:
+ const CSM: SM = SM;
+ match SM {
+ CSM => count += 1,
+ };
+
+ // Check that PhantomData<T> is #[structural_match] even if T is not.
+ const CPD1: PhantomData<NotSM> = PhantomData;
+ match PhantomData {
+ CPD1 => count += 1,
+ };
+
+ // Check that PhantomData<T> is #[structural_match] when T is.
+ const CPD2: PhantomData<SM> = PhantomData;
+ match PhantomData {
+ CPD2 => count += 1,
+ };
+
+ // Check that a type which has a PhantomData is `#[structural_match]`.
+ #[derive(PartialEq, Eq, Default)]
+ struct Foo {
+ alpha: PhantomData<NotSM>,
+ beta: PhantomData<SM>,
+ }
+
+ const CFOO: Foo = Foo {
+ alpha: PhantomData,
+ beta: PhantomData,
+ };
+
+ match Foo::default() {
+ CFOO => count += 1,
+ };
+
+ // Final count must be 4 now if all
+ assert_eq!(count, 4);
+}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(trait_alias)]
+
+trait EqAlias = Eq;
+trait IteratorAlias = Iterator;
+
+fn main() {
+ let _: &dyn EqAlias = &123;
+ let _: &dyn IteratorAlias = &vec![123].into_iter();
+}
--- /dev/null
+error[E0038]: the trait `EqAlias` cannot be made into an object
+ --> $DIR/trait-alias-object.rs:17:13
+ |
+LL | let _: &dyn EqAlias = &123;
+ | ^^^^^^^^^^^ the trait `EqAlias` cannot be made into an object
+ |
+ = note: the trait cannot use `Self` as a type parameter in the supertraits or where-clauses
+
+error[E0191]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified
+ --> $DIR/trait-alias-object.rs:18:13
+ |
+LL | let _: &dyn IteratorAlias = &vec![123].into_iter();
+ | ^^^^^^^^^^^^^^^^^ missing associated type `Item` value
+
+error: aborting due to 2 previous errors
+
+Some errors occurred: E0038, E0191.
+For more information about an error, try `rustc --explain E0038`.
+++ /dev/null
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(trait_alias)]
-
-trait EqAlias = Eq;
-trait IteratorAlias = Iterator;
-
-fn main() {
- let _: &dyn EqAlias = &123;
- let _: &dyn IteratorAlias = &vec![123].into_iter();
-}
+++ /dev/null
-error[E0038]: the trait `EqAlias` cannot be made into an object
- --> $DIR/trait-alias-objects.rs:17:13
- |
-LL | let _: &dyn EqAlias = &123;
- | ^^^^^^^^^^^ the trait `EqAlias` cannot be made into an object
- |
- = note: the trait cannot use `Self` as a type parameter in the supertraits or where-clauses
-
-error[E0191]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified
- --> $DIR/trait-alias-objects.rs:18:13
- |
-LL | let _: &dyn IteratorAlias = &vec![123].into_iter();
- | ^^^^^^^^^^^^^^^^^ missing associated type `Item` value
-
-error: aborting due to 2 previous errors
-
-Some errors occurred: E0038, E0191.
-For more information about an error, try `rustc --explain E0038`.
--- /dev/null
+// compile-pass
+
+// rust-lang/rust#55810: types for a binding in a match arm can be
+// inferred from arms that come later in the match.
+
+struct S;
+
+impl S {
+ fn method(&self) -> bool {
+ unimplemented!()
+ }
+}
+
+fn get<T>() -> T {
+ unimplemented!()
+}
+
+fn main() {
+ match get() {
+ x if x.method() => {}
+ &S => {}
+ }
+}
-Subproject commit 1fa30882067703202d13ad0bd53d630bc2c1de66
+Subproject commit 241fac0e3933063fa48a1a01f5d577e40af12e4d
} else {
self.fatal("no NodeJS binary found (--nodejs)");
}
- }
-
- // If this is otherwise wasm , then run tests under nodejs with our
+ // If this is otherwise wasm, then run tests under nodejs with our
// shim
- if self.config.target.contains("wasm32") {
+ } else if self.config.target.contains("wasm32") {
if let Some(ref p) = self.config.nodejs {
args.push(p.clone());
} else {
[features]
-all-static = ['openssl/vendored', 'curl-sys/static-curl']
+all-static = ['openssl/vendored', 'curl-sys/static-curl', 'curl-sys/force-system-lib-on-osx']
//!
//! - core may not have platform-specific code
//! - libcompiler_builtins may have platform-specific code
-//! - liballoc_system may have platform-specific code
//! - libpanic_abort may have platform-specific code
//! - libpanic_unwind may have platform-specific code
//! - libunwind may have platform-specific code
// Paths that may contain platform-specific code
const EXCEPTION_PATHS: &[&str] = &[
// std crates
- "src/liballoc_system",
"src/libcompiler_builtins",
"src/liblibc",
"src/libpanic_abort",