# bootstrap)
#codegen-backends = ["llvm"]
+# Flag indicating whether `libstd` calls an imported function to hande basic IO
+# when targetting WebAssembly. Enable this to debug tests for the `wasm32-unknown-unknown`
+# target, as without this option the test output will not be captured.
+#wasm-syscall = false
+
# =============================================================================
# Options for specific targets
#
[[package]]
name = "rls"
-version = "0.124.0"
+version = "0.125.0"
dependencies = [
"cargo 0.26.0",
"env_logger 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-rustc 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-vfs 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustfmt-nightly 0.3.6",
+ "rustfmt-nightly 0.3.8",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "rustc-ap-rustc_cratesio_shim"
-version = "12.0.0"
+version = "29.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "rustc-ap-rustc_data_structures"
-version = "12.0.0"
+version = "29.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot_core 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-serialize 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-ap-rustc_errors"
-version = "12.0.0"
+version = "29.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "rustc-ap-rustc_data_structures 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-serialize 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-syntax_pos 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_data_structures 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax_pos 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-ap-serialize"
-version = "12.0.0"
+version = "29.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rustc-ap-syntax"
-version = "12.0.0"
+version = "29.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_cratesio_shim 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_data_structures 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_errors 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-serialize 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-syntax_pos 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_cratesio_shim 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_data_structures 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_errors 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax_pos 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-ap-syntax_pos"
-version = "12.0.0"
+version = "29.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "rustc-ap-rustc_data_structures 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-serialize 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_data_structures 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustfmt-nightly"
-version = "0.3.6"
+version = "0.3.8"
dependencies = [
"cargo_metadata 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"derive-new 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_errors 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-syntax 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_errors 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
"checksum rls-rustc 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "85cfb9dde19e313da3e47738008f8a472e470cc42d910b71595a9238494701f2"
"checksum rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a"
"checksum rls-vfs 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ffd34691a510938bb67fe0444fb363103c73ffb31c121d1e16bc92d8945ea8ff"
-"checksum rustc-ap-rustc_cratesio_shim 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f1a51c10af5abd5d698b7e3487e869e6d15f6feb04cbedb5c792e2824f9d845e"
-"checksum rustc-ap-rustc_data_structures 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1aa227490501072780d57f74b1164d361833ff8e172f817da0da2cdf2e4280cc"
-"checksum rustc-ap-rustc_errors 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "21ff6c6e13ac4fc04b7d4d398828b024c4b6577045cb3175b33d35fea35ff6d0"
-"checksum rustc-ap-serialize 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6b4e7f51e298675c2bf830f7265621a8936fb09e63b825b58144cbaac969e604"
-"checksum rustc-ap-syntax 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8bf5639869ba2f7fa581939cd217cb71a85506b82ad0ea520614fb0dceb2386c"
-"checksum rustc-ap-syntax_pos 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1c020cdb7379e1c733ae0a311ae47c748337ba584d2dd7b7f53baaae78de6f8b"
+"checksum rustc-ap-rustc_cratesio_shim 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ad5e562044ea78a6764dd75ae8afe4b21fde49f4548024b5fdf6345c21fb524"
+"checksum rustc-ap-rustc_data_structures 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c0d65325492aba7db72899e3edbab34d39af98c42ab7c7e450c9a288ffe4ad"
+"checksum rustc-ap-rustc_errors 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "87d4ab2e06a671b5b5c5b0359dac346f164c99d059dce6a22feb08f2f56bd182"
+"checksum rustc-ap-serialize 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e0745fa445ff41c4b6699936cf35ce3ca49502377dd7b3929c829594772c3a7b"
+"checksum rustc-ap-syntax 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "82efedabe30f393161e11214a9130edfa01ad476372d1c6f3fec1f8d30488c9d"
+"checksum rustc-ap-syntax_pos 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db9de2e927e280c75b8efab9c5f591ad31082d5d2c4c562c68fdba2ee77286b0"
"checksum rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e"
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
"checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7"
self.ensure(Libdir { compiler, target })
}
+ pub fn sysroot_codegen_backends(&self, compiler: Compiler) -> PathBuf {
+ self.sysroot_libdir(compiler, compiler.host)
+ .with_file_name("codegen-backends")
+ }
+
/// Returns the compiler's libdir where it stores the dynamic libraries that
/// it itself links against.
///
//
// Here we're looking for the output dylib of the `CodegenBackend` step and
// we're copying that into the `codegen-backends` folder.
- let libdir = builder.sysroot_libdir(target_compiler, target);
- let dst = libdir.join("codegen-backends");
+ let dst = builder.sysroot_codegen_backends(target_compiler);
t!(fs::create_dir_all(&dst));
for backend in builder.config.rust_codegen_backends.iter() {
pub debug_jemalloc: bool,
pub use_jemalloc: bool,
pub backtrace: bool, // support for RUST_BACKTRACE
+ pub wasm_syscall: bool,
// misc
pub low_priority: bool,
test_miri: Option<bool>,
save_toolstates: Option<String>,
codegen_backends: Option<Vec<String>>,
+ wasm_syscall: Option<bool>,
}
/// TOML representation of how each build target is configured.
set(&mut config.rust_dist_src, rust.dist_src);
set(&mut config.quiet_tests, rust.quiet_tests);
set(&mut config.test_miri, rust.test_miri);
+ set(&mut config.wasm_syscall, rust.wasm_syscall);
config.rustc_parallel_queries = rust.experimental_parallel_queries.unwrap_or(false);
config.rustc_default_linker = rust.default_linker.clone();
config.musl_root = rust.musl_root.clone().map(PathBuf::from);
}
// Copy over the codegen backends
- let backends_src = builder.sysroot_libdir(compiler, host)
- .join("codegen-backends");
- let backends_dst = image.join("lib/rustlib")
- .join(&*host)
- .join("lib/codegen-backends");
+ let backends_src = builder.sysroot_codegen_backends(compiler);
+ let backends_rel = backends_src.strip_prefix(&src).unwrap();
+ let backends_dst = image.join(&backends_rel);
t!(fs::create_dir_all(&backends_dst));
cp_r(&backends_src, &backends_dst);
if self.config.profiler {
features.push_str(" profiler");
}
+ if self.config.wasm_syscall {
+ features.push_str(" wasm_syscall");
+ }
features
}
cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)),
build.config.nodejs.as_ref().expect("nodejs not configured"));
} else if target.starts_with("wasm32") {
+ // Warn about running tests without the `wasm_syscall` feature enabled.
+ // The javascript shim implements the syscall interface so that test
+ // output can be correctly reported.
+ if !build.config.wasm_syscall {
+ println!("Libstd was built without `wasm_syscall` feature enabled: \
+ test output may not be visible.");
+ }
+
// On the wasm32-unknown-unknown target we're using LTO which is
// incompatible with `-C prefer-dynamic`, so disable that here
cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");
p
}
-#[lang = "exchange_free"]
-unsafe fn deallocate(ptr: *mut u8, _size: usize, _align: usize) {
- libc::free(ptr as *mut libc::c_void)
-}
-
#[lang = "box_free"]
unsafe fn box_free<T: ?Sized>(ptr: *mut T) {
- deallocate(ptr as *mut u8, ::core::mem::size_of_val(&*ptr), ::core::mem::align_of_val(&*ptr));
+ libc::free(ptr as *mut libc::c_void)
}
#[start]
-fn main(argc: isize, argv: *const *const u8) -> isize {
- let x = box 1;
+fn main(_argc: isize, _argv: *const *const u8) -> isize {
+ let _x = box 1;
0
}
#[lang = "eh_personality"] extern fn rust_eh_personality() {}
#[lang = "panic_fmt"] extern fn rust_begin_panic() -> ! { unsafe { intrinsics::abort() } }
-# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
-# #[no_mangle] pub extern fn rust_eh_register_frames () {}
-# #[no_mangle] pub extern fn rust_eh_unregister_frames () {}
+#[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
+#[no_mangle] pub extern fn rust_eh_register_frames () {}
+#[no_mangle] pub extern fn rust_eh_unregister_frames () {}
```
Note the use of `abort`: the `exchange_malloc` lang item is assumed to
Lang items are loaded lazily by the compiler; e.g. if one never uses
`Box` then there is no need to define functions for `exchange_malloc`
-and `exchange_free`. `rustc` will emit an error when an item is needed
+and `box_free`. `rustc` will emit an error when an item is needed
but not found in the current crate or any that it depends on.
Most lang items are defined by `libcore`, but if you're trying to build
- `phantom_data`: `libcore/marker.rs`
- `freeze`: `libcore/marker.rs`
- `debug_trait`: `libcore/fmt/mod.rs`
- - `non_zero`: `libcore/nonzero.rs`
\ No newline at end of file
+ - `non_zero`: `libcore/nonzero.rs`
let memory = null;
+function viewstruct(data, fields) {
+ return new Uint32Array(memory.buffer).subarray(data/4, data/4 + fields);
+}
+
function copystr(a, b) {
- if (memory === null) {
- return null
- }
- let view = new Uint8Array(memory.buffer).slice(a, a + b);
+ let view = new Uint8Array(memory.buffer).subarray(a, a + b);
return String.fromCharCode.apply(null, view);
}
+function syscall_write([fd, ptr, len]) {
+ let s = copystr(ptr, len);
+ switch (fd) {
+ case 1: process.stdout.write(s); break;
+ case 2: process.stderr.write(s); break;
+ }
+}
+
+function syscall_exit([code]) {
+ process.exit(code);
+}
+
+function syscall_args(params) {
+ let [ptr, len] = params;
+
+ // Calculate total required buffer size
+ let totalLen = -1;
+ for (let i = 2; i < process.argv.length; ++i) {
+ totalLen += Buffer.byteLength(process.argv[i]) + 1;
+ }
+ if (totalLen < 0) { totalLen = 0; }
+ params[2] = totalLen;
+
+ // If buffer is large enough, copy data
+ if (len >= totalLen) {
+ let view = new Uint8Array(memory.buffer);
+ for (let i = 2; i < process.argv.length; ++i) {
+ let value = process.argv[i];
+ Buffer.from(value).copy(view, ptr);
+ ptr += Buffer.byteLength(process.argv[i]) + 1;
+ }
+ }
+}
+
+function syscall_getenv(params) {
+ let [keyPtr, keyLen, valuePtr, valueLen] = params;
+
+ let key = copystr(keyPtr, keyLen);
+ let value = process.env[key];
+
+ if (value == null) {
+ params[4] = 0xFFFFFFFF;
+ } else {
+ let view = new Uint8Array(memory.buffer);
+ let totalLen = Buffer.byteLength(value);
+ params[4] = totalLen;
+ if (valueLen >= totalLen) {
+ Buffer.from(value).copy(view, valuePtr);
+ }
+ }
+}
+
+function syscall_time(params) {
+ let t = Date.now();
+ let secs = Math.floor(t / 1000);
+ let millis = t % 1000;
+ params[1] = Math.floor(secs / 0x100000000);
+ params[2] = secs % 0x100000000;
+ params[3] = Math.floor(millis * 1000000);
+}
+
let imports = {};
imports.env = {
// These are generated by LLVM itself for various intrinsic calls. Hopefully
log10: Math.log10,
log10f: Math.log10,
- // These are called in src/libstd/sys/wasm/stdio.rs and are used when
- // debugging is enabled.
- rust_wasm_write_stdout: function(a, b) {
- let s = copystr(a, b);
- if (s !== null) {
- process.stdout.write(s);
- }
- },
- rust_wasm_write_stderr: function(a, b) {
- let s = copystr(a, b);
- if (s !== null) {
- process.stderr.write(s);
- }
- },
-
- // These are called in src/libstd/sys/wasm/args.rs and are used when
- // debugging is enabled.
- rust_wasm_args_count: function() {
- if (memory === null)
- return 0;
- return process.argv.length - 2;
- },
- rust_wasm_args_arg_size: function(i) {
- return Buffer.byteLength(process.argv[i + 2]);
- },
- rust_wasm_args_arg_fill: function(idx, ptr) {
- let arg = process.argv[idx + 2];
- let view = new Uint8Array(memory.buffer);
- Buffer.from(arg).copy(view, ptr);
- },
-
- // These are called in src/libstd/sys/wasm/os.rs and are used when
- // debugging is enabled.
- rust_wasm_getenv_len: function(a, b) {
- let key = copystr(a, b);
- if (key === null) {
- return -1;
+ rust_wasm_syscall: function(index, data) {
+ switch (index) {
+ case 1: syscall_write(viewstruct(data, 3)); return true;
+ case 2: syscall_exit(viewstruct(data, 1)); return true;
+ case 3: syscall_args(viewstruct(data, 3)); return true;
+ case 4: syscall_getenv(viewstruct(data, 5)); return true;
+ case 6: syscall_time(viewstruct(data, 4)); return true;
+ default:
+ console.log("Unsupported syscall: " + index);
+ return false;
}
- if (!(key in process.env)) {
- return -1;
- }
- return Buffer.byteLength(process.env[key]);
- },
- rust_wasm_getenv_data: function(a, b, ptr) {
- let key = copystr(a, b);
- let value = process.env[key];
- let view = new Uint8Array(memory.buffer);
- Buffer.from(value).copy(view, ptr);
- },
-};
-
-let module_imports = WebAssembly.Module.imports(m);
-
-for (var i = 0; i < module_imports.length; i++) {
- let imp = module_imports[i];
- if (imp.module != 'env') {
- continue
}
- if (imp.name == 'memory' && imp.kind == 'memory') {
- memory = new WebAssembly.Memory({initial: 20});
- imports.env.memory = memory;
- }
-}
+};
let instance = new WebAssembly.Instance(m, imports);
+memory = instance.exports.memory;
+try {
+ instance.exports.main();
+} catch (e) {
+ console.error(e);
+ process.exit(101);
+}
#[stable(feature = "rust1", since = "1.0.0")]
impl Debug for bool {
+ #[inline]
fn fmt(&self, f: &mut Formatter) -> Result {
Display::fmt(self, f)
}
#[stable(feature = "rust1", since = "1.0.0")]
impl Debug for () {
+ #[inline]
fn fmt(&self, f: &mut Formatter) -> Result {
f.pad("()")
}
($T:ident) => {
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Debug for $T {
+ #[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self, f)
}
/// ptr::copy_nonoverlapping(y, x, 1);
/// ptr::copy_nonoverlapping(&t, y, 1);
///
- /// // y and t now point to the same thing, but we need to completely forget `tmp`
+ /// // y and t now point to the same thing, but we need to completely forget `t`
/// // because it's no longer relevant.
/// mem::forget(t);
/// }
use iter_private::TrustedRandomAccess;
use ops::Try;
use usize;
+use intrinsics;
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::iterator::Iterator;
(f(inner_hint.0), inner_hint.1.map(f))
}
}
+
+ #[inline]
+ fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
+ if self.first_take {
+ self.first_take = false;
+ let first = self.iter.next();
+ if n == 0 {
+ return first;
+ }
+ n -= 1;
+ }
+ // n and self.step are indices, we need to add 1 to get the amount of elements
+ // When calling `.nth`, we need to subtract 1 again to convert back to an index
+ // step + 1 can't overflow because `.step_by` sets `self.step` to `step - 1`
+ let mut step = self.step + 1;
+ // n + 1 could overflow
+ // thus, if n is usize::MAX, instead of adding one, we call .nth(step)
+ if n == usize::MAX {
+ self.iter.nth(step - 1);
+ } else {
+ n += 1;
+ }
+
+ // overflow handling
+ loop {
+ let mul = n.checked_mul(step);
+ if unsafe { intrinsics::likely(mul.is_some()) } {
+ return self.iter.nth(mul.unwrap() - 1);
+ }
+ let div_n = usize::MAX / n;
+ let div_step = usize::MAX / step;
+ let nth_n = div_n * n;
+ let nth_step = div_step * step;
+ let nth = if nth_n > nth_step {
+ step -= div_n;
+ nth_n
+ } else {
+ n -= div_step;
+ nth_step
+ };
+ self.iter.nth(nth - 1);
+ }
+ }
}
// StepBy can only make the iterator shorter, so the len will still fit.
pub mod str;
pub mod hash;
pub mod fmt;
+pub mod time;
// note: does not need to be public
mod char_private;
/// Type | size_of::\<Type>()
/// ---- | ---------------
/// () | 0
+/// bool | 1
/// u8 | 1
/// u16 | 2
/// u32 | 4
/// Converts to degrees, assuming the number is in radians.
#[inline]
fn to_degrees(self) -> f32 {
- self * (180.0f32 / consts::PI)
+ // Use a constant for better precision.
+ const PIS_IN_180: f32 = 57.2957795130823208767981548141051703_f32;
+ self * PIS_IN_180
}
/// Converts to radians, assuming the number is in degrees.
/// Converts to degrees, assuming the number is in radians.
#[inline]
fn to_degrees(self) -> f64 {
+ // The division here is correctly rounded with respect to the true
+ // value of 180/π. (This differs from f32, where a constant must be
+ // used to ensure a correctly rounded result.)
self * (180.0f64 / consts::PI)
}
assert_eq!(it.next(), None);
}
+#[test]
+fn test_iterator_step_by_nth() {
+ let mut it = (0..16).step_by(5);
+ assert_eq!(it.nth(0), Some(0));
+ assert_eq!(it.nth(0), Some(5));
+ assert_eq!(it.nth(0), Some(10));
+ assert_eq!(it.nth(0), Some(15));
+ assert_eq!(it.nth(0), None);
+
+ let it = (0..18).step_by(5);
+ assert_eq!(it.clone().nth(0), Some(0));
+ assert_eq!(it.clone().nth(1), Some(5));
+ assert_eq!(it.clone().nth(2), Some(10));
+ assert_eq!(it.clone().nth(3), Some(15));
+ assert_eq!(it.clone().nth(4), None);
+ assert_eq!(it.clone().nth(42), None);
+}
+
+#[test]
+fn test_iterator_step_by_nth_overflow() {
+ #[cfg(target_pointer_width = "8")]
+ type Bigger = u16;
+ #[cfg(target_pointer_width = "16")]
+ type Bigger = u32;
+ #[cfg(target_pointer_width = "32")]
+ type Bigger = u64;
+ #[cfg(target_pointer_width = "64")]
+ type Bigger = u128;
+
+ #[derive(Clone)]
+ struct Test(Bigger);
+ impl<'a> Iterator for &'a mut Test {
+ type Item = i32;
+ fn next(&mut self) -> Option<Self::Item> { Some(21) }
+ fn nth(&mut self, n: usize) -> Option<Self::Item> {
+ self.0 += n as Bigger + 1;
+ Some(42)
+ }
+ }
+
+ let mut it = Test(0);
+ let root = usize::MAX >> (::std::mem::size_of::<usize>() * 8 / 2);
+ let n = root + 20;
+ (&mut it).step_by(n).nth(n);
+ assert_eq!(it.0, n as Bigger * n as Bigger);
+
+ // large step
+ let mut it = Test(0);
+ (&mut it).step_by(usize::MAX).nth(5);
+ assert_eq!(it.0, (usize::MAX as Bigger) * 5);
+
+ // n + 1 overflows
+ let mut it = Test(0);
+ (&mut it).step_by(2).nth(usize::MAX);
+ assert_eq!(it.0, (usize::MAX as Bigger) * 2);
+
+ // n + 1 overflows
+ let mut it = Test(0);
+ (&mut it).step_by(1).nth(usize::MAX);
+ assert_eq!(it.0, (usize::MAX as Bigger) * 1);
+}
+
#[test]
#[should_panic]
fn test_iterator_step_by_zero() {
--- /dev/null
+// Copyright 2012-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.
+#![stable(feature = "duration_core", since = "1.24.0")]
+
+//! Temporal quantification.
+//!
+//! Example:
+//!
+//! ```
+//! use std::time::Duration;
+//!
+//! let five_seconds = Duration::new(5, 0);
+//! // both declarations are equivalent
+//! assert_eq!(Duration::new(5, 0), Duration::from_secs(5));
+//! ```
+
+use iter::Sum;
+use ops::{Add, Sub, Mul, Div, AddAssign, SubAssign, MulAssign, DivAssign};
+
+const NANOS_PER_SEC: u32 = 1_000_000_000;
+const NANOS_PER_MILLI: u32 = 1_000_000;
+const NANOS_PER_MICRO: u32 = 1_000;
+const MILLIS_PER_SEC: u64 = 1_000;
+const MICROS_PER_SEC: u64 = 1_000_000;
+
+/// A `Duration` type to represent a span of time, typically used for system
+/// timeouts.
+///
+/// Each `Duration` is composed of a whole number of seconds and a fractional part
+/// represented in nanoseconds. If the underlying system does not support
+/// nanosecond-level precision, APIs binding a system timeout will typically round up
+/// the number of nanoseconds.
+///
+/// `Duration`s implement many common traits, including [`Add`], [`Sub`], and other
+/// [`ops`] traits.
+///
+/// [`Add`]: ../../std/ops/trait.Add.html
+/// [`Sub`]: ../../std/ops/trait.Sub.html
+/// [`ops`]: ../../std/ops/index.html
+///
+/// # Examples
+///
+/// ```
+/// use std::time::Duration;
+///
+/// let five_seconds = Duration::new(5, 0);
+/// let five_seconds_and_five_nanos = five_seconds + Duration::new(0, 5);
+///
+/// assert_eq!(five_seconds_and_five_nanos.as_secs(), 5);
+/// assert_eq!(five_seconds_and_five_nanos.subsec_nanos(), 5);
+///
+/// let ten_millis = Duration::from_millis(10);
+/// ```
+#[stable(feature = "duration_core", since = "1.24.0")]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)]
+pub struct Duration {
+ secs: u64,
+ nanos: u32, // Always 0 <= nanos < NANOS_PER_SEC
+}
+
+impl Duration {
+ /// Creates a new `Duration` from the specified number of whole seconds and
+ /// additional nanoseconds.
+ ///
+ /// If the number of nanoseconds is greater than 1 billion (the number of
+ /// nanoseconds in a second), then it will carry over into the seconds provided.
+ ///
+ /// # Panics
+ ///
+ /// This constructor will panic if the carry from the nanoseconds overflows
+ /// the seconds counter.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::time::Duration;
+ ///
+ /// let five_seconds = Duration::new(5, 0);
+ /// ```
+ #[stable(feature = "duration", since = "1.3.0")]
+ #[inline]
+ pub fn new(secs: u64, nanos: u32) -> Duration {
+ let secs = secs.checked_add((nanos / NANOS_PER_SEC) as u64)
+ .expect("overflow in Duration::new");
+ let nanos = nanos % NANOS_PER_SEC;
+ Duration { secs: secs, nanos: nanos }
+ }
+
+ /// Creates a new `Duration` from the specified number of whole seconds.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::time::Duration;
+ ///
+ /// let duration = Duration::from_secs(5);
+ ///
+ /// assert_eq!(5, duration.as_secs());
+ /// assert_eq!(0, duration.subsec_nanos());
+ /// ```
+ #[stable(feature = "duration", since = "1.3.0")]
+ #[inline]
+ pub const fn from_secs(secs: u64) -> Duration {
+ Duration { secs: secs, nanos: 0 }
+ }
+
+ /// Creates a new `Duration` from the specified number of milliseconds.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::time::Duration;
+ ///
+ /// let duration = Duration::from_millis(2569);
+ ///
+ /// assert_eq!(2, duration.as_secs());
+ /// assert_eq!(569_000_000, duration.subsec_nanos());
+ /// ```
+ #[stable(feature = "duration", since = "1.3.0")]
+ #[inline]
+ pub const fn from_millis(millis: u64) -> Duration {
+ Duration {
+ secs: millis / MILLIS_PER_SEC,
+ nanos: ((millis % MILLIS_PER_SEC) as u32) * NANOS_PER_MILLI,
+ }
+ }
+
+ /// Creates a new `Duration` from the specified number of microseconds.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(duration_from_micros)]
+ /// use std::time::Duration;
+ ///
+ /// let duration = Duration::from_micros(1_000_002);
+ ///
+ /// assert_eq!(1, duration.as_secs());
+ /// assert_eq!(2000, duration.subsec_nanos());
+ /// ```
+ #[unstable(feature = "duration_from_micros", issue = "44400")]
+ #[inline]
+ pub const fn from_micros(micros: u64) -> Duration {
+ Duration {
+ secs: micros / MICROS_PER_SEC,
+ nanos: ((micros % MICROS_PER_SEC) as u32) * NANOS_PER_MICRO,
+ }
+ }
+
+ /// Creates a new `Duration` from the specified number of nanoseconds.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(duration_extras)]
+ /// use std::time::Duration;
+ ///
+ /// let duration = Duration::from_nanos(1_000_000_123);
+ ///
+ /// assert_eq!(1, duration.as_secs());
+ /// assert_eq!(123, duration.subsec_nanos());
+ /// ```
+ #[unstable(feature = "duration_extras", issue = "46507")]
+ #[inline]
+ pub const fn from_nanos(nanos: u64) -> Duration {
+ Duration {
+ secs: nanos / (NANOS_PER_SEC as u64),
+ nanos: (nanos % (NANOS_PER_SEC as u64)) as u32,
+ }
+ }
+
+ /// Returns the number of _whole_ seconds contained by this `Duration`.
+ ///
+ /// The returned value does not include the fractional (nanosecond) part of the
+ /// duration, which can be obtained using [`subsec_nanos`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::time::Duration;
+ ///
+ /// let duration = Duration::new(5, 730023852);
+ /// assert_eq!(duration.as_secs(), 5);
+ /// ```
+ ///
+ /// To determine the total number of seconds represented by the `Duration`,
+ /// use `as_secs` in combination with [`subsec_nanos`]:
+ ///
+ /// ```
+ /// use std::time::Duration;
+ ///
+ /// let duration = Duration::new(5, 730023852);
+ ///
+ /// assert_eq!(5.730023852,
+ /// duration.as_secs() as f64
+ /// + duration.subsec_nanos() as f64 * 1e-9);
+ /// ```
+ ///
+ /// [`subsec_nanos`]: #method.subsec_nanos
+ #[stable(feature = "duration", since = "1.3.0")]
+ #[inline]
+ pub fn as_secs(&self) -> u64 { self.secs }
+
+ /// Returns the fractional part of this `Duration`, in milliseconds.
+ ///
+ /// This method does **not** return the length of the duration when
+ /// represented by milliseconds. The returned number always represents a
+ /// fractional portion of a second (i.e. it is less than one thousand).
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(duration_extras)]
+ /// use std::time::Duration;
+ ///
+ /// let duration = Duration::from_millis(5432);
+ /// assert_eq!(duration.as_secs(), 5);
+ /// assert_eq!(duration.subsec_millis(), 432);
+ /// ```
+ #[unstable(feature = "duration_extras", issue = "46507")]
+ #[inline]
+ pub fn subsec_millis(&self) -> u32 { self.nanos / NANOS_PER_MILLI }
+
+ /// Returns the fractional part of this `Duration`, in microseconds.
+ ///
+ /// This method does **not** return the length of the duration when
+ /// represented by microseconds. The returned number always represents a
+ /// fractional portion of a second (i.e. it is less than one million).
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(duration_extras, duration_from_micros)]
+ /// use std::time::Duration;
+ ///
+ /// let duration = Duration::from_micros(1_234_567);
+ /// assert_eq!(duration.as_secs(), 1);
+ /// assert_eq!(duration.subsec_micros(), 234_567);
+ /// ```
+ #[unstable(feature = "duration_extras", issue = "46507")]
+ #[inline]
+ pub fn subsec_micros(&self) -> u32 { self.nanos / NANOS_PER_MICRO }
+
+ /// Returns the fractional part of this `Duration`, in nanoseconds.
+ ///
+ /// This method does **not** return the length of the duration when
+ /// represented by nanoseconds. The returned number always represents a
+ /// fractional portion of a second (i.e. it is less than one billion).
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::time::Duration;
+ ///
+ /// let duration = Duration::from_millis(5010);
+ /// assert_eq!(duration.as_secs(), 5);
+ /// assert_eq!(duration.subsec_nanos(), 10_000_000);
+ /// ```
+ #[stable(feature = "duration", since = "1.3.0")]
+ #[inline]
+ pub fn subsec_nanos(&self) -> u32 { self.nanos }
+
+ /// Checked `Duration` addition. Computes `self + other`, returning [`None`]
+ /// if overflow occurred.
+ ///
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// use std::time::Duration;
+ ///
+ /// assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), Some(Duration::new(0, 1)));
+ /// assert_eq!(Duration::new(1, 0).checked_add(Duration::new(std::u64::MAX, 0)), None);
+ /// ```
+ #[stable(feature = "duration_checked_ops", since = "1.16.0")]
+ #[inline]
+ pub fn checked_add(self, rhs: Duration) -> Option<Duration> {
+ if let Some(mut secs) = self.secs.checked_add(rhs.secs) {
+ let mut nanos = self.nanos + rhs.nanos;
+ if nanos >= NANOS_PER_SEC {
+ nanos -= NANOS_PER_SEC;
+ if let Some(new_secs) = secs.checked_add(1) {
+ secs = new_secs;
+ } else {
+ return None;
+ }
+ }
+ debug_assert!(nanos < NANOS_PER_SEC);
+ Some(Duration {
+ secs,
+ nanos,
+ })
+ } else {
+ None
+ }
+ }
+
+ /// Checked `Duration` subtraction. Computes `self - other`, returning [`None`]
+ /// if the result would be negative or if overflow occurred.
+ ///
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// use std::time::Duration;
+ ///
+ /// assert_eq!(Duration::new(0, 1).checked_sub(Duration::new(0, 0)), Some(Duration::new(0, 1)));
+ /// assert_eq!(Duration::new(0, 0).checked_sub(Duration::new(0, 1)), None);
+ /// ```
+ #[stable(feature = "duration_checked_ops", since = "1.16.0")]
+ #[inline]
+ pub fn checked_sub(self, rhs: Duration) -> Option<Duration> {
+ if let Some(mut secs) = self.secs.checked_sub(rhs.secs) {
+ let nanos = if self.nanos >= rhs.nanos {
+ self.nanos - rhs.nanos
+ } else {
+ if let Some(sub_secs) = secs.checked_sub(1) {
+ secs = sub_secs;
+ self.nanos + NANOS_PER_SEC - rhs.nanos
+ } else {
+ return None;
+ }
+ };
+ debug_assert!(nanos < NANOS_PER_SEC);
+ Some(Duration { secs: secs, nanos: nanos })
+ } else {
+ None
+ }
+ }
+
+ /// Checked `Duration` multiplication. Computes `self * other`, returning
+ /// [`None`] if overflow occurred.
+ ///
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// use std::time::Duration;
+ ///
+ /// assert_eq!(Duration::new(0, 500_000_001).checked_mul(2), Some(Duration::new(1, 2)));
+ /// assert_eq!(Duration::new(std::u64::MAX - 1, 0).checked_mul(2), None);
+ /// ```
+ #[stable(feature = "duration_checked_ops", since = "1.16.0")]
+ #[inline]
+ pub fn checked_mul(self, rhs: u32) -> Option<Duration> {
+ // Multiply nanoseconds as u64, because it cannot overflow that way.
+ let total_nanos = self.nanos as u64 * rhs as u64;
+ let extra_secs = total_nanos / (NANOS_PER_SEC as u64);
+ let nanos = (total_nanos % (NANOS_PER_SEC as u64)) as u32;
+ if let Some(secs) = self.secs
+ .checked_mul(rhs as u64)
+ .and_then(|s| s.checked_add(extra_secs)) {
+ debug_assert!(nanos < NANOS_PER_SEC);
+ Some(Duration {
+ secs,
+ nanos,
+ })
+ } else {
+ None
+ }
+ }
+
+ /// Checked `Duration` division. Computes `self / other`, returning [`None`]
+ /// if `other == 0`.
+ ///
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// use std::time::Duration;
+ ///
+ /// assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0)));
+ /// assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000)));
+ /// assert_eq!(Duration::new(2, 0).checked_div(0), None);
+ /// ```
+ #[stable(feature = "duration_checked_ops", since = "1.16.0")]
+ #[inline]
+ pub fn checked_div(self, rhs: u32) -> Option<Duration> {
+ if rhs != 0 {
+ let secs = self.secs / (rhs as u64);
+ let carry = self.secs - secs * (rhs as u64);
+ let extra_nanos = carry * (NANOS_PER_SEC as u64) / (rhs as u64);
+ let nanos = self.nanos / rhs + (extra_nanos as u32);
+ debug_assert!(nanos < NANOS_PER_SEC);
+ Some(Duration { secs: secs, nanos: nanos })
+ } else {
+ None
+ }
+ }
+}
+
+#[stable(feature = "duration", since = "1.3.0")]
+impl Add for Duration {
+ type Output = Duration;
+
+ fn add(self, rhs: Duration) -> Duration {
+ self.checked_add(rhs).expect("overflow when adding durations")
+ }
+}
+
+#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
+impl AddAssign for Duration {
+ fn add_assign(&mut self, rhs: Duration) {
+ *self = *self + rhs;
+ }
+}
+
+#[stable(feature = "duration", since = "1.3.0")]
+impl Sub for Duration {
+ type Output = Duration;
+
+ fn sub(self, rhs: Duration) -> Duration {
+ self.checked_sub(rhs).expect("overflow when subtracting durations")
+ }
+}
+
+#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
+impl SubAssign for Duration {
+ fn sub_assign(&mut self, rhs: Duration) {
+ *self = *self - rhs;
+ }
+}
+
+#[stable(feature = "duration", since = "1.3.0")]
+impl Mul<u32> for Duration {
+ type Output = Duration;
+
+ fn mul(self, rhs: u32) -> Duration {
+ self.checked_mul(rhs).expect("overflow when multiplying duration by scalar")
+ }
+}
+
+#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
+impl MulAssign<u32> for Duration {
+ fn mul_assign(&mut self, rhs: u32) {
+ *self = *self * rhs;
+ }
+}
+
+#[stable(feature = "duration", since = "1.3.0")]
+impl Div<u32> for Duration {
+ type Output = Duration;
+
+ fn div(self, rhs: u32) -> Duration {
+ self.checked_div(rhs).expect("divide by zero error when dividing duration by scalar")
+ }
+}
+
+#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
+impl DivAssign<u32> for Duration {
+ fn div_assign(&mut self, rhs: u32) {
+ *self = *self / rhs;
+ }
+}
+
+#[stable(feature = "duration_sum", since = "1.16.0")]
+impl Sum for Duration {
+ fn sum<I: Iterator<Item=Duration>>(iter: I) -> Duration {
+ iter.fold(Duration::new(0, 0), |a, b| a + b)
+ }
+}
+
+#[stable(feature = "duration_sum", since = "1.16.0")]
+impl<'a> Sum<&'a Duration> for Duration {
+ fn sum<I: Iterator<Item=&'a Duration>>(iter: I) -> Duration {
+ iter.fold(Duration::new(0, 0), |a, b| a + *b)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::Duration;
+
+ #[test]
+ fn creation() {
+ assert!(Duration::from_secs(1) != Duration::from_secs(0));
+ assert_eq!(Duration::from_secs(1) + Duration::from_secs(2),
+ Duration::from_secs(3));
+ assert_eq!(Duration::from_millis(10) + Duration::from_secs(4),
+ Duration::new(4, 10 * 1_000_000));
+ assert_eq!(Duration::from_millis(4000), Duration::new(4, 0));
+ }
+
+ #[test]
+ fn secs() {
+ assert_eq!(Duration::new(0, 0).as_secs(), 0);
+ assert_eq!(Duration::from_secs(1).as_secs(), 1);
+ assert_eq!(Duration::from_millis(999).as_secs(), 0);
+ assert_eq!(Duration::from_millis(1001).as_secs(), 1);
+ }
+
+ #[test]
+ fn nanos() {
+ assert_eq!(Duration::new(0, 0).subsec_nanos(), 0);
+ assert_eq!(Duration::new(0, 5).subsec_nanos(), 5);
+ assert_eq!(Duration::new(0, 1_000_000_001).subsec_nanos(), 1);
+ assert_eq!(Duration::from_secs(1).subsec_nanos(), 0);
+ assert_eq!(Duration::from_millis(999).subsec_nanos(), 999 * 1_000_000);
+ assert_eq!(Duration::from_millis(1001).subsec_nanos(), 1 * 1_000_000);
+ }
+
+ #[test]
+ fn add() {
+ assert_eq!(Duration::new(0, 0) + Duration::new(0, 1),
+ Duration::new(0, 1));
+ assert_eq!(Duration::new(0, 500_000_000) + Duration::new(0, 500_000_001),
+ Duration::new(1, 1));
+ }
+
+ #[test]
+ fn checked_add() {
+ assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)),
+ Some(Duration::new(0, 1)));
+ assert_eq!(Duration::new(0, 500_000_000).checked_add(Duration::new(0, 500_000_001)),
+ Some(Duration::new(1, 1)));
+ assert_eq!(Duration::new(1, 0).checked_add(Duration::new(::u64::MAX, 0)), None);
+ }
+
+ #[test]
+ fn sub() {
+ assert_eq!(Duration::new(0, 1) - Duration::new(0, 0),
+ Duration::new(0, 1));
+ assert_eq!(Duration::new(0, 500_000_001) - Duration::new(0, 500_000_000),
+ Duration::new(0, 1));
+ assert_eq!(Duration::new(1, 0) - Duration::new(0, 1),
+ Duration::new(0, 999_999_999));
+ }
+
+ #[test]
+ fn checked_sub() {
+ let zero = Duration::new(0, 0);
+ let one_nano = Duration::new(0, 1);
+ let one_sec = Duration::new(1, 0);
+ assert_eq!(one_nano.checked_sub(zero), Some(Duration::new(0, 1)));
+ assert_eq!(one_sec.checked_sub(one_nano),
+ Some(Duration::new(0, 999_999_999)));
+ assert_eq!(zero.checked_sub(one_nano), None);
+ assert_eq!(zero.checked_sub(one_sec), None);
+ }
+
+ #[test] #[should_panic]
+ fn sub_bad1() {
+ Duration::new(0, 0) - Duration::new(0, 1);
+ }
+
+ #[test] #[should_panic]
+ fn sub_bad2() {
+ Duration::new(0, 0) - Duration::new(1, 0);
+ }
+
+ #[test]
+ fn mul() {
+ assert_eq!(Duration::new(0, 1) * 2, Duration::new(0, 2));
+ assert_eq!(Duration::new(1, 1) * 3, Duration::new(3, 3));
+ assert_eq!(Duration::new(0, 500_000_001) * 4, Duration::new(2, 4));
+ assert_eq!(Duration::new(0, 500_000_001) * 4000,
+ Duration::new(2000, 4000));
+ }
+
+ #[test]
+ fn checked_mul() {
+ assert_eq!(Duration::new(0, 1).checked_mul(2), Some(Duration::new(0, 2)));
+ assert_eq!(Duration::new(1, 1).checked_mul(3), Some(Duration::new(3, 3)));
+ assert_eq!(Duration::new(0, 500_000_001).checked_mul(4), Some(Duration::new(2, 4)));
+ assert_eq!(Duration::new(0, 500_000_001).checked_mul(4000),
+ Some(Duration::new(2000, 4000)));
+ assert_eq!(Duration::new(::u64::MAX - 1, 0).checked_mul(2), None);
+ }
+
+ #[test]
+ fn div() {
+ assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0));
+ assert_eq!(Duration::new(1, 1) / 3, Duration::new(0, 333_333_333));
+ assert_eq!(Duration::new(99, 999_999_000) / 100,
+ Duration::new(0, 999_999_990));
+ }
+
+ #[test]
+ fn checked_div() {
+ assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0)));
+ assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000)));
+ assert_eq!(Duration::new(2, 0).checked_div(0), None);
+ }
+}
#![feature(libc)]
#![feature(panic_runtime)]
#![feature(staged_api)]
+#![feature(rustc_attrs)]
// Rust's "try" function, but if we're aborting on panics we just call the
// function as there's nothing else we need to do here.
#[no_mangle]
+#[rustc_std_internal_symbol]
pub unsafe extern fn __rust_maybe_catch_panic(f: fn(*mut u8),
data: *mut u8,
_data_ptr: *mut usize,
// will kill us with an illegal instruction, which will do a good enough job for
// now hopefully.
#[no_mangle]
+#[rustc_std_internal_symbol]
pub unsafe extern fn __rust_start_panic(_data: usize, _vtable: usize) -> u32 {
abort();
- `'gcx` -- the lifetime of the global arena (see `librustc/ty`).
- generics -- the set of generic type parameters defined on a type or item
- ICE -- internal compiler error. When the compiler crashes.
+- ICH -- incremental compilation hash.
- infcx -- the inference context (see `librustc/infer`)
- MIR -- the **Mid-level IR** that is created after type-checking for use by borrowck and trans.
Defined in the `src/librustc/mir/` module, but much of the code that manipulates it is
[] TargetFeaturesEnabled(DefId),
[] InstanceDefSizeEstimate { instance_def: InstanceDef<'tcx> },
+
+ [] GetSymbolExportLevel(DefId),
+
);
trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug {
ty::ReEarlyBound(_) |
ty::ReFree(_) => {
let scope = region.free_region_binding_scope(self);
- let prefix = match *region {
- ty::ReEarlyBound(ref br) => {
- format!("the lifetime {} as defined on", br.name)
- }
- ty::ReFree(ref fr) => {
- match fr.bound_region {
- ty::BrAnon(idx) => {
- format!("the anonymous lifetime #{} defined on", idx + 1)
- }
- ty::BrFresh(_) => "an anonymous lifetime defined on".to_owned(),
- _ => {
- format!("the lifetime {} as defined on",
- fr.bound_region)
- }
- }
- }
- _ => bug!()
- };
-
let node = self.hir.as_local_node_id(scope)
.unwrap_or(DUMMY_NODE_ID);
let unknown;
&unknown
}
};
- let (msg, opt_span) = explain_span(self, tag, self.hir.span(node));
+ let (prefix, span) = match *region {
+ ty::ReEarlyBound(ref br) => {
+ (format!("the lifetime {} as defined on", br.name),
+ self.sess.codemap().def_span(self.hir.span(node)))
+ }
+ ty::ReFree(ref fr) => {
+ match fr.bound_region {
+ ty::BrAnon(idx) => {
+ (format!("the anonymous lifetime #{} defined on", idx + 1),
+ self.hir.span(node))
+ }
+ ty::BrFresh(_) => ("an anonymous lifetime defined on".to_owned(),
+ self.hir.span(node)),
+ _ => (format!("the lifetime {} as defined on", fr.bound_region),
+ self.sess.codemap().def_span(self.hir.span(node))),
+ }
+ }
+ _ => bug!()
+ };
+ let (msg, opt_span) = explain_span(self, tag, span);
(format!("{} {}", prefix, msg), opt_span)
}
}
};
- let span = cause.span;
+ let span = cause.span(&self.tcx);
diag.span_label(span, terr.to_string());
if let Some((sp, msg)) = secondary_span {
"did you mean `{}(/* fields */)`?",
self.tcx.item_path_str(def_id)
);
- diag.span_label(cause.span, message);
+ diag.span_label(span, message);
}
}
}
trace,
terr);
- let span = trace.cause.span;
+ let span = trace.cause.span(&self.tcx);
let failure_code = trace.cause.as_failure_code(terr);
let mut diag = match failure_code {
FailureCode::Error0317(failure_str) => {
sup_region,
"...");
+ match (&sup_origin, &sub_origin) {
+ (&infer::Subtype(ref sup_trace), &infer::Subtype(ref sub_trace)) => {
+ if let (Some((sup_expected, sup_found)),
+ Some((sub_expected, sub_found))) = (self.values_str(&sup_trace.values),
+ self.values_str(&sub_trace.values)) {
+ if sub_expected == sup_expected && sub_found == sup_found {
+ self.tcx.note_and_explain_region(
+ region_scope_tree,
+ &mut err,
+ "...but the lifetime must also be valid for ",
+ sub_region,
+ "...",
+ );
+ err.note(&format!("...so that the {}:\nexpected {}\n found {}",
+ sup_trace.cause.as_requirement_str(),
+ sup_expected.content(),
+ sup_found.content()));
+ err.emit();
+ return;
+ }
+ }
+ }
+ _ => {}
+ }
+
self.note_region_origin(&mut err, &sup_origin);
self.tcx.note_and_explain_region(region_scope_tree, &mut err,
if let Some((expected, found)) = self.values_str(&trace.values) {
let expected = expected.content();
let found = found.content();
- // FIXME: do we want a "the" here?
- err.span_note(trace.cause.span,
- &format!("...so that {} (expected {}, found {})",
- trace.cause.as_requirement_str(),
- expected,
- found));
+ err.note(&format!("...so that the {}:\nexpected {}\n found {}",
+ trace.cause.as_requirement_str(),
+ expected,
+ found));
} else {
// FIXME: this really should be handled at some earlier stage. Our
// handling of region checking when type errors are present is
#![feature(specialization)]
#![feature(unboxed_closures)]
#![feature(underscore_lifetimes)]
+#![feature(universal_impl_trait)]
#![feature(trace_macros)]
#![feature(catch_expr)]
#![feature(test)]
"raw pointer to an inference variable"
}
+declare_lint! {
+ pub ELIDED_LIFETIME_IN_PATH,
+ Allow,
+ "hidden lifetime parameters are deprecated, try `Foo<'_>`"
+}
+
/// Does nothing as a lint pass, but registers some `Lint`s
/// which are used by other parts of the compiler.
#[derive(Copy, Clone)]
UNUSED_MUT,
COERCE_NEVER,
SINGLE_USE_LIFETIME,
- TYVAR_BEHIND_RAW_POINTER
+ TYVAR_BEHIND_RAW_POINTER,
+ ELIDED_LIFETIME_IN_PATH
+
)
}
}
type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>;
fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
- (self.tcx, self.param_env.reveal_all()).layout_of(ty)
+ self.tcx.layout_of(self.param_env.and(ty))
}
}
}
fn visit_pat(&mut self, pat: &'tcx Pat) {
+ intravisit::walk_pat(self, pat);
+
self.expr_and_pat_count += 1;
- intravisit::walk_pat(self, pat);
+ if pat.id == self.id {
+ self.result = Some(self.expr_and_pat_count);
+ }
}
fn visit_expr(&mut self, expr: &'tcx Expr) {
/// Checks whether the given scope contains a `yield`. If so,
/// returns `Some((span, expr_count))` with the span of a yield we found and
- /// the number of expressions appearing before the `yield` in the body.
+ /// the number of expressions and patterns appearing before the `yield` in the body + 1.
+ /// If there a are multiple yields in a scope, the one with the highest number is returned.
pub fn yield_in_scope(&self, scope: Scope) -> Option<(Span, usize)> {
self.yield_in_scope.get(&scope).cloned()
}
fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
if lifetime_ref.is_elided() {
- self.resolve_elided_lifetimes(slice::from_ref(lifetime_ref));
+ self.resolve_elided_lifetimes(slice::from_ref(lifetime_ref), false);
return;
}
if lifetime_ref.is_static() {
}
if params.lifetimes.iter().all(|l| l.is_elided()) {
- self.resolve_elided_lifetimes(¶ms.lifetimes);
+ self.resolve_elided_lifetimes(¶ms.lifetimes, true);
} else {
for l in ¶ms.lifetimes {
self.visit_lifetime(l);
}
}
- fn resolve_elided_lifetimes(&mut self, lifetime_refs: &'tcx [hir::Lifetime]) {
+ fn resolve_elided_lifetimes(&mut self, lifetime_refs: &'tcx [hir::Lifetime], deprecated: bool) {
if lifetime_refs.is_empty() {
return;
}
let span = lifetime_refs[0].span;
+ let id = lifetime_refs[0].id;
let mut late_depth = 0;
let mut scope = self.scope;
+ if deprecated {
+ self.tcx
+ .struct_span_lint_node(
+ lint::builtin::ELIDED_LIFETIME_IN_PATH,
+ id,
+ span,
+ &format!("hidden lifetime parameters are deprecated, try `Foo<'_>`"))
+ .emit();
+ }
let error = loop {
match *scope {
// Do not assign any resolution, it will be inferred.
dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED],
"in dep-info output, omit targets for tracking dependencies of the dep-info files \
themselves"),
+ approximate_suggestions: bool = (false, parse_bool, [UNTRACKED],
+ "include machine-applicability of suggestions in JSON output"),
unpretty: Option<String> = (None, parse_unpretty, [UNTRACKED],
"Present the input source, unstable (and less-pretty) variants;
valid types are any of the types for `--pretty`, as well as:
let emitter: Box<Emitter> = match (sopts.error_format, emitter_dest) {
(config::ErrorOutputType::HumanReadable(color_config), None) => {
- Box::new(EmitterWriter::stderr(color_config, Some(codemap.clone()), false))
+ Box::new(EmitterWriter::stderr(color_config,
+ Some(codemap.clone()),
+ false,
+ sopts.debugging_opts.teach))
}
(config::ErrorOutputType::HumanReadable(_), Some(dst)) => {
- Box::new(EmitterWriter::new(dst, Some(codemap.clone()), false))
+ Box::new(EmitterWriter::new(dst, Some(codemap.clone()), false, false))
}
(config::ErrorOutputType::Json(pretty), None) => {
- Box::new(JsonEmitter::stderr(Some(registry), codemap.clone(), pretty))
+ Box::new(JsonEmitter::stderr(Some(registry), codemap.clone(),
+ pretty, sopts.debugging_opts.approximate_suggestions))
}
(config::ErrorOutputType::Json(pretty), Some(dst)) => {
- Box::new(JsonEmitter::new(dst, Some(registry), codemap.clone(), pretty))
+ Box::new(JsonEmitter::new(dst, Some(registry), codemap.clone(),
+ pretty, sopts.debugging_opts.approximate_suggestions))
}
(config::ErrorOutputType::Short(color_config), None) => {
- Box::new(EmitterWriter::stderr(color_config, Some(codemap.clone()), true))
+ Box::new(EmitterWriter::stderr(color_config, Some(codemap.clone()), true, false))
}
(config::ErrorOutputType::Short(_), Some(dst)) => {
- Box::new(EmitterWriter::new(dst, Some(codemap.clone()), true))
+ Box::new(EmitterWriter::new(dst, Some(codemap.clone()), true, false))
}
};
pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! {
let emitter: Box<Emitter> = match output {
config::ErrorOutputType::HumanReadable(color_config) => {
- Box::new(EmitterWriter::stderr(color_config, None, false))
+ Box::new(EmitterWriter::stderr(color_config, None, false, false))
}
config::ErrorOutputType::Json(pretty) => Box::new(JsonEmitter::basic(pretty)),
config::ErrorOutputType::Short(color_config) => {
- Box::new(EmitterWriter::stderr(color_config, None, true))
+ Box::new(EmitterWriter::stderr(color_config, None, true, false))
}
};
let handler = errors::Handler::with_emitter(true, false, emitter);
pub fn early_warn(output: config::ErrorOutputType, msg: &str) {
let emitter: Box<Emitter> = match output {
config::ErrorOutputType::HumanReadable(color_config) => {
- Box::new(EmitterWriter::stderr(color_config, None, false))
+ Box::new(EmitterWriter::stderr(color_config, None, false, false))
}
config::ErrorOutputType::Json(pretty) => Box::new(JsonEmitter::basic(pretty)),
config::ErrorOutputType::Short(color_config) => {
- Box::new(EmitterWriter::stderr(color_config, None, true))
+ Box::new(EmitterWriter::stderr(color_config, None, true, false))
}
};
let handler = errors::Handler::with_emitter(true, false, emitter);
use ty::fold::TypeFoldable;
use ty::subst::Subst;
-use infer::{InferCtxt, InferOk};
+use infer::{InferOk};
/// Whether we do the orphan check relative to this crate or
/// to some remote crate.
pub intercrate_ambiguity_causes: Vec<IntercrateAmbiguityCause>,
}
-/// If there are types that satisfy both impls, returns a suitably-freshened
-/// `ImplHeader` with those types substituted
-pub fn overlapping_impls<'cx, 'gcx, 'tcx>(infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
- impl1_def_id: DefId,
- impl2_def_id: DefId,
- intercrate_mode: IntercrateMode)
- -> Option<OverlapResult<'tcx>>
+/// If there are types that satisfy both impls, invokes `on_overlap`
+/// with a suitably-freshened `ImplHeader` with those types
+/// substituted. Otherwise, invokes `no_overlap`.
+pub fn overlapping_impls<'gcx, F1, F2, R>(
+ tcx: TyCtxt<'_, 'gcx, 'gcx>,
+ impl1_def_id: DefId,
+ impl2_def_id: DefId,
+ intercrate_mode: IntercrateMode,
+ on_overlap: F1,
+ no_overlap: F2,
+) -> R
+where
+ F1: FnOnce(OverlapResult<'_>) -> R,
+ F2: FnOnce() -> R,
{
debug!("impl_can_satisfy(\
impl1_def_id={:?}, \
impl2_def_id,
intercrate_mode);
- let selcx = &mut SelectionContext::intercrate(infcx, intercrate_mode);
- overlap(selcx, impl1_def_id, impl2_def_id)
+ let overlaps = tcx.infer_ctxt().enter(|infcx| {
+ let selcx = &mut SelectionContext::intercrate(&infcx, intercrate_mode);
+ overlap(selcx, impl1_def_id, impl2_def_id).is_some()
+ });
+
+ if !overlaps {
+ return no_overlap();
+ }
+
+ // In the case where we detect an error, run the check again, but
+ // this time tracking intercrate ambuiguity causes for better
+ // diagnostics. (These take time and can lead to false errors.)
+ tcx.infer_ctxt().enter(|infcx| {
+ let selcx = &mut SelectionContext::intercrate(&infcx, intercrate_mode);
+ selcx.enable_tracking_intercrate_ambiguity_causes();
+ on_overlap(overlap(selcx, impl1_def_id, impl2_def_id).unwrap())
+ })
}
fn with_fresh_ty_vars<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
return None
}
- Some(OverlapResult {
- impl_header: selcx.infcx().resolve_type_vars_if_possible(&a_impl_header),
- intercrate_ambiguity_causes: selcx.intercrate_ambiguity_causes().to_vec(),
- })
+ let impl_header = selcx.infcx().resolve_type_vars_if_possible(&a_impl_header);
+ let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes();
+ debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes);
+ Some(OverlapResult { impl_header, intercrate_ambiguity_causes })
}
pub fn trait_ref_is_knowable<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
span,
node: hir::ImplItemKind::Method(hir::MethodSig { ref decl, .. }, _),
..
+ }) |
+ hir::map::NodeTraitItem(&hir::TraitItem {
+ span,
+ node: hir::TraitItemKind::Method(hir::MethodSig { ref decl, .. }, _),
+ ..
}) => {
(self.tcx.sess.codemap().def_span(span), decl.inputs.iter()
.map(|arg| match arg.clone().into_inner().node {
err.note("the return type of a function must have a \
statically known size");
}
+ ObligationCauseCode::SizedYieldType => {
+ err.note("the yield type of a generator must have a \
+ statically known size");
+ }
ObligationCauseCode::AssignmentLhsSized => {
err.note("the left-hand-side of an assignment must have a statically known size");
}
pub code: ObligationCauseCode<'tcx>
}
+impl<'tcx> ObligationCause<'tcx> {
+ pub fn span<'a, 'gcx>(&self, tcx: &TyCtxt<'a, 'gcx, 'tcx>) -> Span {
+ match self.code {
+ ObligationCauseCode::CompareImplMethodObligation { .. } |
+ ObligationCauseCode::MainFunctionType |
+ ObligationCauseCode::StartFunctionType => {
+ tcx.sess.codemap().def_span(self.span)
+ }
+ _ => self.span,
+ }
+ }
+}
+
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ObligationCauseCode<'tcx> {
/// Not well classified or should be obvious from span.
VariableType(ast::NodeId),
/// Return type must be Sized
SizedReturnType,
+ /// Yield type must be Sized
+ SizedYieldType,
/// [T,..n] --> T must be Copy
RepeatVec,
inferred_obligations: SnapshotVec<InferredObligationsSnapshotVecDelegate<'tcx>>,
- intercrate_ambiguity_causes: Vec<IntercrateAmbiguityCause>,
+ intercrate_ambiguity_causes: Option<Vec<IntercrateAmbiguityCause>>,
}
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub enum IntercrateAmbiguityCause {
DownstreamCrate {
trait_desc: String,
freshener: infcx.freshener(),
intercrate: None,
inferred_obligations: SnapshotVec::new(),
- intercrate_ambiguity_causes: Vec::new(),
+ intercrate_ambiguity_causes: None,
}
}
freshener: infcx.freshener(),
intercrate: Some(mode),
inferred_obligations: SnapshotVec::new(),
- intercrate_ambiguity_causes: Vec::new(),
+ intercrate_ambiguity_causes: None,
}
}
+ /// Enables tracking of intercrate ambiguity causes. These are
+ /// used in coherence to give improved diagnostics. We don't do
+ /// this until we detect a coherence error because it can lead to
+ /// false overflow results (#47139) and because it costs
+ /// computation time.
+ pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) {
+ assert!(self.intercrate.is_some());
+ assert!(self.intercrate_ambiguity_causes.is_none());
+ self.intercrate_ambiguity_causes = Some(vec![]);
+ debug!("selcx: enable_tracking_intercrate_ambiguity_causes");
+ }
+
+ /// Gets the intercrate ambiguity causes collected since tracking
+ /// was enabled and disables tracking at the same time. If
+ /// tracking is not enabled, just returns an empty vector.
+ pub fn take_intercrate_ambiguity_causes(&mut self) -> Vec<IntercrateAmbiguityCause> {
+ assert!(self.intercrate.is_some());
+ self.intercrate_ambiguity_causes.take().unwrap_or(vec![])
+ }
+
pub fn infcx(&self) -> &'cx InferCtxt<'cx, 'gcx, 'tcx> {
self.infcx
}
self.infcx
}
- pub fn intercrate_ambiguity_causes(&self) -> &[IntercrateAmbiguityCause] {
- &self.intercrate_ambiguity_causes
- }
-
/// Wraps the inference context's in_snapshot s.t. snapshot handling is only from the selection
/// context's self.
fn in_snapshot<R, F>(&mut self, f: F) -> R
debug!("evaluate_stack({:?}) --> unbound argument, intercrate --> ambiguous",
stack.fresh_trait_ref);
// Heuristics: show the diagnostics when there are no candidates in crate.
- if let Ok(candidate_set) = self.assemble_candidates(stack) {
- if !candidate_set.ambiguous && candidate_set.vec.is_empty() {
- let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
- let self_ty = trait_ref.self_ty();
- let cause = IntercrateAmbiguityCause::DownstreamCrate {
- trait_desc: trait_ref.to_string(),
- self_desc: if self_ty.has_concrete_skeleton() {
- Some(self_ty.to_string())
- } else {
- None
- },
- };
- self.intercrate_ambiguity_causes.push(cause);
+ if self.intercrate_ambiguity_causes.is_some() {
+ debug!("evaluate_stack: intercrate_ambiguity_causes is some");
+ if let Ok(candidate_set) = self.assemble_candidates(stack) {
+ if !candidate_set.ambiguous && candidate_set.vec.is_empty() {
+ let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
+ let self_ty = trait_ref.self_ty();
+ let cause = IntercrateAmbiguityCause::DownstreamCrate {
+ trait_desc: trait_ref.to_string(),
+ self_desc: if self_ty.has_concrete_skeleton() {
+ Some(self_ty.to_string())
+ } else {
+ None
+ },
+ };
+ debug!("evaluate_stack: pushing cause = {:?}", cause);
+ self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
+ }
}
}
return EvaluatedToAmbig;
None => {}
Some(conflict) => {
debug!("coherence stage: not knowable");
- // Heuristics: show the diagnostics when there are no candidates in crate.
- let candidate_set = self.assemble_candidates(stack)?;
- if !candidate_set.ambiguous && candidate_set.vec.iter().all(|c| {
- !self.evaluate_candidate(stack, &c).may_apply()
- }) {
- let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
- let self_ty = trait_ref.self_ty();
- let trait_desc = trait_ref.to_string();
- let self_desc = if self_ty.has_concrete_skeleton() {
- Some(self_ty.to_string())
- } else {
- None
- };
- let cause = if let Conflict::Upstream = conflict {
- IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc }
- } else {
- IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc }
- };
- self.intercrate_ambiguity_causes.push(cause);
+ if self.intercrate_ambiguity_causes.is_some() {
+ debug!("evaluate_stack: intercrate_ambiguity_causes is some");
+ // Heuristics: show the diagnostics when there are no candidates in crate.
+ let candidate_set = self.assemble_candidates(stack)?;
+ if !candidate_set.ambiguous && candidate_set.vec.iter().all(|c| {
+ !self.evaluate_candidate(stack, &c).may_apply()
+ }) {
+ let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
+ let self_ty = trait_ref.self_ty();
+ let trait_desc = trait_ref.to_string();
+ let self_desc = if self_ty.has_concrete_skeleton() {
+ Some(self_ty.to_string())
+ } else {
+ None
+ };
+ let cause = if let Conflict::Upstream = conflict {
+ IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc }
+ } else {
+ IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc }
+ };
+ debug!("evaluate_stack: pushing cause = {:?}", cause);
+ self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
+ }
}
return Ok(None);
}
};
let tcx = tcx.global_tcx();
- let (le, ge) = tcx.infer_ctxt().enter(|infcx| {
- let overlap = traits::overlapping_impls(&infcx,
- possible_sibling,
- impl_def_id,
- traits::IntercrateMode::Issue43355);
- if let Some(overlap) = overlap {
+ let (le, ge) = traits::overlapping_impls(
+ tcx,
+ possible_sibling,
+ impl_def_id,
+ traits::IntercrateMode::Issue43355,
+ |overlap| {
if tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) {
return Ok((false, false));
}
} else {
Ok((le, ge))
}
- } else {
- Ok((false, false))
- }
- })?;
+ },
+ || Ok((false, false)),
+ )?;
if le && !ge {
debug!("descending as child of TraitRef {:?}",
return Ok(Inserted::Replaced(possible_sibling));
} else {
if !tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) {
- tcx.infer_ctxt().enter(|infcx| {
- if let Some(overlap) = traits::overlapping_impls(
- &infcx,
- possible_sibling,
- impl_def_id,
- traits::IntercrateMode::Fixed)
- {
- last_lint = Some(overlap_error(overlap));
- }
- });
+ traits::overlapping_impls(
+ tcx,
+ possible_sibling,
+ impl_def_id,
+ traits::IntercrateMode::Fixed,
+ |overlap| last_lint = Some(overlap_error(overlap)),
+ || (),
+ );
}
// no overlap (error bailed already via ?)
super::VariableType(id) => Some(super::VariableType(id)),
super::ReturnType(id) => Some(super::ReturnType(id)),
super::SizedReturnType => Some(super::SizedReturnType),
+ super::SizedYieldType => Some(super::SizedYieldType),
super::RepeatVec => Some(super::RepeatVec),
super::FieldSized(item) => Some(super::FieldSized(item)),
super::ConstSized => Some(super::ConstSized),
super::VariableType(_) |
super::ReturnType(_) |
super::SizedReturnType |
+ super::SizedYieldType |
super::ReturnNoExpression |
super::RepeatVec |
super::FieldSized(_) |
super::VariableType(_) |
super::ReturnType(_) |
super::SizedReturnType |
+ super::SizedYieldType |
super::ReturnNoExpression |
super::RepeatVec |
super::FieldSized(_) |
}
tcx.layout_depth.set(depth+1);
- let layout = LayoutDetails::compute_uncached(tcx, param_env, ty);
+ let cx = LayoutCx { tcx, param_env };
+ let layout = cx.layout_raw_uncached(ty);
tcx.layout_depth.set(depth);
layout
};
}
-impl<'a, 'tcx> LayoutDetails {
- fn compute_uncached(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- ty: Ty<'tcx>)
- -> Result<&'tcx Self, LayoutError<'tcx>> {
- let cx = (tcx, param_env);
- let dl = cx.data_layout();
+#[derive(Copy, Clone)]
+pub struct LayoutCx<'tcx, C> {
+ pub tcx: C,
+ pub param_env: ty::ParamEnv<'tcx>
+}
+
+impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
+ fn layout_raw_uncached(self, ty: Ty<'tcx>)
+ -> Result<&'tcx LayoutDetails, LayoutError<'tcx>> {
+ let tcx = self.tcx;
+ let param_env = self.param_env;
+ let dl = self.data_layout();
let scalar_unit = |value: Primitive| {
let bits = value.size(dl).bits();
assert!(bits <= 128);
}
};
let scalar = |value: Primitive| {
- tcx.intern_layout(LayoutDetails::scalar(cx, scalar_unit(value)))
+ tcx.intern_layout(LayoutDetails::scalar(self, scalar_unit(value)))
};
let scalar_pair = |a: Scalar, b: Scalar| {
let align = a.value.align(dl).max(b.value.align(dl)).max(dl.aggregate_align);
Ok(match ty.sty {
// Basic scalars.
ty::TyBool => {
- tcx.intern_layout(LayoutDetails::scalar(cx, Scalar {
+ tcx.intern_layout(LayoutDetails::scalar(self, Scalar {
value: Int(I8, false),
valid_range: 0..=1
}))
}
ty::TyChar => {
- tcx.intern_layout(LayoutDetails::scalar(cx, Scalar {
+ tcx.intern_layout(LayoutDetails::scalar(self, Scalar {
value: Int(I32, false),
valid_range: 0..=0x10FFFF
}))
ty::TyFnPtr(_) => {
let mut ptr = scalar_unit(Pointer);
ptr.valid_range.start = 1;
- tcx.intern_layout(LayoutDetails::scalar(cx, ptr))
+ tcx.intern_layout(LayoutDetails::scalar(self, ptr))
}
// The never type.
let pointee = tcx.normalize_associated_type_in_env(&pointee, param_env);
if pointee.is_sized(tcx, param_env, DUMMY_SP) {
- return Ok(tcx.intern_layout(LayoutDetails::scalar(cx, data_ptr)));
+ return Ok(tcx.intern_layout(LayoutDetails::scalar(self, data_ptr)));
}
let unsized_part = tcx.struct_tail(pointee);
let metadata = match unsized_part.sty {
ty::TyForeign(..) => {
- return Ok(tcx.intern_layout(LayoutDetails::scalar(cx, data_ptr)));
+ return Ok(tcx.intern_layout(LayoutDetails::scalar(self, data_ptr)));
}
ty::TySlice(_) | ty::TyStr => {
scalar_unit(Int(dl.ptr_sized_integer(), false))
}
}
- let element = cx.layout_of(element)?;
+ let element = self.layout_of(element)?;
let count = count.val.to_const_int().unwrap().to_u64().unwrap();
let size = element.size.checked_mul(count, dl)
.ok_or(LayoutError::SizeOverflow(ty))?;
})
}
ty::TySlice(element) => {
- let element = cx.layout_of(element)?;
+ let element = self.layout_of(element)?;
tcx.intern_layout(LayoutDetails {
variants: Variants::Single { index: 0 },
fields: FieldPlacement::Array {
// Tuples, generators and closures.
ty::TyGenerator(def_id, ref substs, _) => {
let tys = substs.field_tys(def_id, tcx);
- univariant(&tys.map(|ty| cx.layout_of(ty)).collect::<Result<Vec<_>, _>>()?,
+ univariant(&tys.map(|ty| self.layout_of(ty)).collect::<Result<Vec<_>, _>>()?,
&ReprOptions::default(),
StructKind::AlwaysSized)?
}
ty::TyClosure(def_id, ref substs) => {
let tys = substs.upvar_tys(def_id, tcx);
- univariant(&tys.map(|ty| cx.layout_of(ty)).collect::<Result<Vec<_>, _>>()?,
+ univariant(&tys.map(|ty| self.layout_of(ty)).collect::<Result<Vec<_>, _>>()?,
&ReprOptions::default(),
StructKind::AlwaysSized)?
}
StructKind::MaybeUnsized
};
- univariant(&tys.iter().map(|ty| cx.layout_of(ty)).collect::<Result<Vec<_>, _>>()?,
+ univariant(&tys.iter().map(|ty| self.layout_of(ty)).collect::<Result<Vec<_>, _>>()?,
&ReprOptions::default(), kind)?
}
// SIMD vector types.
ty::TyAdt(def, ..) if def.repr.simd() => {
- let element = cx.layout_of(ty.simd_type(tcx))?;
+ let element = self.layout_of(ty.simd_type(tcx))?;
let count = ty.simd_size(tcx) as u64;
assert!(count > 0);
let scalar = match element.abi {
// Cache the field layouts.
let variants = def.variants.iter().map(|v| {
v.fields.iter().map(|field| {
- cx.layout_of(field.ty(tcx, substs))
+ self.layout_of(field.ty(tcx, substs))
}).collect::<Result<Vec<_>, _>>()
}).collect::<Result<Vec<_>, _>>()?;
let mut st = univariant_uninterned(&variants[v], &def.repr, kind)?;
st.variants = Variants::Single { index: v };
// Exclude 0 from the range of a newtype ABI NonZero<T>.
- if Some(def.did) == cx.tcx().lang_items().non_zero() {
+ if Some(def.did) == self.tcx.lang_items().non_zero() {
match st.abi {
Abi::Scalar(ref mut scalar) |
Abi::ScalarPair(ref mut scalar, _) => {
let count = (niche_variants.end - niche_variants.start + 1) as u128;
for (field_index, field) in variants[i].iter().enumerate() {
let (offset, niche, niche_start) =
- match field.find_niche(cx, count)? {
+ match field.find_niche(self, count)? {
Some(niche) => niche,
None => continue
};
/// This is invoked by the `layout_raw` query to record the final
/// layout of each type.
#[inline]
- fn record_layout_for_printing(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- ty: Ty<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- layout: TyLayout<'tcx>) {
+ fn record_layout_for_printing(self, layout: TyLayout<'tcx>) {
// If we are running with `-Zprint-type-sizes`, record layouts for
// dumping later. Ignore layouts that are done with non-empty
// environments or non-monomorphic layouts, as the user only wants
// to see the stuff resulting from the final trans session.
if
- !tcx.sess.opts.debugging_opts.print_type_sizes ||
- ty.has_param_types() ||
- ty.has_self_ty() ||
- !param_env.caller_bounds.is_empty()
+ !self.tcx.sess.opts.debugging_opts.print_type_sizes ||
+ layout.ty.has_param_types() ||
+ layout.ty.has_self_ty() ||
+ !self.param_env.caller_bounds.is_empty()
{
return;
}
- Self::record_layout_for_printing_outlined(tcx, ty, param_env, layout)
+ self.record_layout_for_printing_outlined(layout)
}
- fn record_layout_for_printing_outlined(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- ty: Ty<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- layout: TyLayout<'tcx>) {
- let cx = (tcx, param_env);
+ fn record_layout_for_printing_outlined(self, layout: TyLayout<'tcx>) {
// (delay format until we actually need it)
let record = |kind, opt_discr_size, variants| {
- let type_desc = format!("{:?}", ty);
- tcx.sess.code_stats.borrow_mut().record_type_size(kind,
- type_desc,
- layout.align,
- layout.size,
- opt_discr_size,
- variants);
+ let type_desc = format!("{:?}", layout.ty);
+ self.tcx.sess.code_stats.borrow_mut().record_type_size(kind,
+ type_desc,
+ layout.align,
+ layout.size,
+ opt_discr_size,
+ variants);
};
- let adt_def = match ty.sty {
+ let adt_def = match layout.ty.sty {
ty::TyAdt(ref adt_def, _) => {
- debug!("print-type-size t: `{:?}` process adt", ty);
+ debug!("print-type-size t: `{:?}` process adt", layout.ty);
adt_def
}
ty::TyClosure(..) => {
- debug!("print-type-size t: `{:?}` record closure", ty);
+ debug!("print-type-size t: `{:?}` record closure", layout.ty);
record(DataTypeKind::Closure, None, vec![]);
return;
}
_ => {
- debug!("print-type-size t: `{:?}` skip non-nominal", ty);
+ debug!("print-type-size t: `{:?}` skip non-nominal", layout.ty);
return;
}
};
layout: TyLayout<'tcx>| {
let mut min_size = Size::from_bytes(0);
let field_info: Vec<_> = flds.iter().enumerate().map(|(i, &name)| {
- match layout.field(cx, i) {
+ match layout.field(self, i) {
Err(err) => {
bug!("no layout found for field {}: `{:?}`", name, err);
}
Variants::NicheFilling { .. } |
Variants::Tagged { .. } => {
debug!("print-type-size `{:#?}` adt general variants def {}",
- ty, adt_def.variants.len());
+ layout.ty, adt_def.variants.len());
let variant_infos: Vec<_> =
adt_def.variants.iter().enumerate().map(|(i, variant_def)| {
let fields: Vec<_> =
variant_def.fields.iter().map(|f| f.name).collect();
build_variant_info(Some(variant_def.name),
&fields,
- layout.for_variant(cx, i))
+ layout.for_variant(self, i))
})
.collect();
record(adt_kind.into(), match layout.variants {
- Variants::Tagged { ref discr, .. } => Some(discr.value.size(tcx)),
+ Variants::Tagged { ref discr, .. } => Some(discr.value.size(self)),
_ => None
}, variant_infos);
}
assert!(!ty.has_infer_types());
// First try computing a static layout.
- let err = match (tcx, param_env).layout_of(ty) {
+ let err = match tcx.layout_of(param_env.and(ty)) {
Ok(layout) => {
return Ok(SizeSkeleton::Known(layout.size));
}
}
}
-impl<'a, 'gcx, 'tcx, T: Copy> HasDataLayout for (TyCtxt<'a, 'gcx, 'tcx>, T) {
+impl<'tcx, T: HasDataLayout> HasDataLayout for LayoutCx<'tcx, T> {
fn data_layout(&self) -> &TargetDataLayout {
- self.0.data_layout()
+ self.tcx.data_layout()
}
}
-impl<'a, 'gcx, 'tcx, T: Copy> HasTyCtxt<'gcx> for (TyCtxt<'a, 'gcx, 'tcx>, T) {
+impl<'gcx, 'tcx, T: HasTyCtxt<'gcx>> HasTyCtxt<'gcx> for LayoutCx<'tcx, T> {
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'gcx> {
- self.0.tcx()
+ self.tcx.tcx()
}
}
fn layout_of(self, ty: T) -> Self::TyLayout;
}
-impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for (TyCtxt<'a, 'tcx, 'tcx>, ty::ParamEnv<'tcx>) {
+impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>;
/// Computes the layout of a type. Note that this implicitly
/// executes in "reveal all" mode.
- #[inline]
fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
- let (tcx, param_env) = self;
-
- let ty = tcx.normalize_associated_type_in_env(&ty, param_env.reveal_all());
- let details = tcx.layout_raw(param_env.reveal_all().and(ty))?;
+ let param_env = self.param_env.reveal_all();
+ let ty = self.tcx.normalize_associated_type_in_env(&ty, param_env);
+ let details = self.tcx.layout_raw(param_env.and(ty))?;
let layout = TyLayout {
ty,
details
// completed, to avoid problems around recursive structures
// and the like. (Admitedly, I wasn't able to reproduce a problem
// here, but it seems like the right thing to do. -nmatsakis)
- LayoutDetails::record_layout_for_printing(tcx, ty, param_env, layout);
+ self.record_layout_for_printing(layout);
Ok(layout)
}
}
-impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for (ty::maps::TyCtxtAt<'a, 'tcx, 'tcx>,
- ty::ParamEnv<'tcx>) {
+impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for LayoutCx<'tcx, ty::maps::TyCtxtAt<'a, 'tcx, 'tcx>> {
type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>;
/// Computes the layout of a type. Note that this implicitly
/// executes in "reveal all" mode.
- #[inline]
fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
- let (tcx_at, param_env) = self;
-
- let ty = tcx_at.tcx.normalize_associated_type_in_env(&ty, param_env.reveal_all());
- let details = tcx_at.layout_raw(param_env.reveal_all().and(ty))?;
+ let param_env = self.param_env.reveal_all();
+ let ty = self.tcx.normalize_associated_type_in_env(&ty, param_env.reveal_all());
+ let details = self.tcx.layout_raw(param_env.reveal_all().and(ty))?;
let layout = TyLayout {
ty,
details
// completed, to avoid problems around recursive structures
// and the like. (Admitedly, I wasn't able to reproduce a problem
// here, but it seems like the right thing to do. -nmatsakis)
- LayoutDetails::record_layout_for_printing(tcx_at.tcx, ty, param_env, layout);
+ let cx = LayoutCx {
+ tcx: *self.tcx,
+ param_env: self.param_env
+ };
+ cx.record_layout_for_printing(layout);
Ok(layout)
}
}
+// Helper (inherent) `layout_of` methods to avoid pushing `LayoutCx` to users.
+impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
+ /// Computes the layout of a type. Note that this implicitly
+ /// executes in "reveal all" mode.
+ #[inline]
+ pub fn layout_of(self, param_env_and_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>)
+ -> Result<TyLayout<'tcx>, LayoutError<'tcx>> {
+ let cx = LayoutCx {
+ tcx: self,
+ param_env: param_env_and_ty.param_env
+ };
+ cx.layout_of(param_env_and_ty.value)
+ }
+}
+
+impl<'a, 'tcx> ty::maps::TyCtxtAt<'a, 'tcx, 'tcx> {
+ /// Computes the layout of a type. Note that this implicitly
+ /// executes in "reveal all" mode.
+ #[inline]
+ pub fn layout_of(self, param_env_and_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>)
+ -> Result<TyLayout<'tcx>, LayoutError<'tcx>> {
+ let cx = LayoutCx {
+ tcx: self,
+ param_env: param_env_and_ty.param_env
+ };
+ cx.layout_of(param_env_and_ty.value)
+ }
+}
+
impl<'a, 'tcx> TyLayout<'tcx> {
pub fn for_variant<C>(&self, cx: C, variant_index: usize) -> Self
where C: LayoutOf<Ty<'tcx>> + HasTyCtxt<'tcx>,
-> (Arc<DefIdSet>, Arc<Vec<Arc<CodegenUnit<'tcx>>>>),
[] fn export_name: ExportName(DefId) -> Option<Symbol>,
[] fn contains_extern_indicator: ContainsExternIndicator(DefId) -> bool,
+ [] fn symbol_export_level: GetSymbolExportLevel(DefId) -> SymbolExportLevel,
[] fn is_translated_function: IsTranslatedFunction(DefId) -> bool,
[] fn codegen_unit: CodegenUnit(InternedString) -> Arc<CodegenUnit<'tcx>>,
[] fn compile_codegen_unit: CompileCodegenUnit(InternedString) -> Stats,
DepKind::TargetFeaturesWhitelist => { force!(target_features_whitelist, LOCAL_CRATE); }
DepKind::TargetFeaturesEnabled => { force!(target_features_enabled, def_id!()); }
+
+ DepKind::GetSymbolExportLevel => { force!(symbol_export_level, def_id!()); }
}
true
state.map(move |d| d.ty.subst(tcx, self.substs))
}
+ /// This is the types of the fields of a generate which
+ /// is available before the generator transformation.
+ /// It includes the upvars and the state discriminant which is u32.
+ pub fn pre_transforms_tys(self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'tcx>) ->
+ impl Iterator<Item=Ty<'tcx>> + 'a
+ {
+ self.upvar_tys(def_id, tcx).chain(iter::once(tcx.types.u32))
+ }
+
/// This is the types of all the fields stored in a generator.
/// It includes the upvars, state types and the state discriminant which is u32.
pub fn field_tys(self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'tcx>) ->
impl Iterator<Item=Ty<'tcx>> + 'a
{
- let upvars = self.upvar_tys(def_id, tcx);
- let state = self.state_tys(def_id, tcx);
- upvars.chain(iter::once(tcx.types.u32)).chain(state)
+ self.pre_transforms_tys(def_id, tcx).chain(self.state_tys(def_id, tcx))
}
}
/// The codegen backend to use for this target, typically "llvm"
pub codegen_backend: String,
+
+ /// The default visibility for symbols in this target should be "hidden"
+ /// rather than "default"
+ pub default_hidden_visibility: bool,
}
impl Default for TargetOptions {
no_builtins: false,
i128_lowering: false,
codegen_backend: "llvm".to_string(),
+ default_hidden_visibility: false,
}
}
}
key!(singlethread, bool);
key!(no_builtins, bool);
key!(codegen_backend);
+ key!(default_hidden_visibility, bool);
if let Some(array) = obj.find("abi-blacklist").and_then(Json::as_array) {
for name in array.iter().filter_map(|abi| abi.as_string()) {
target_option_val!(singlethread);
target_option_val!(no_builtins);
target_option_val!(codegen_backend);
+ target_option_val!(default_hidden_visibility);
if default.abi_blacklist != self.options.abi_blacklist {
d.insert("abi-blacklist".to_string(), self.options.abi_blacklist.iter()
// don't want to invoke that many gcc instances.
default_codegen_units: Some(1),
+ // Since MSP430 doesn't meaningfully support faulting on illegal
+ // instructions, LLVM generates a call to abort() function instead
+ // of a trap instruction. Such calls are 4 bytes long, and that is
+ // too much overhead for such small target.
+ trap_unreachable: false,
+
.. Default::default( )
}
})
// performing LTO with compiler-builtins.
no_builtins: true,
+ // no dynamic linking, no need for default visibility!
+ default_hidden_visibility: true,
+
.. Default::default()
};
Ok(Target {
continue
}
- let mut_span = tcx.sess.codemap().span_until_char(ids[0].2, ' ');
+ let mut_span = tcx.sess.codemap().span_until_non_whitespace(ids[0].2);
// Ok, every name wasn't used mutably, so issue a warning that this
// didn't need to be mutable.
}
}
+
impl<'a, 'tcx> PatternContext<'a, 'tcx> {
fn report_inlining_errors(&self, pat_span: Span) {
for error in &self.errors {
match *error {
PatternError::StaticInPattern(span) => {
- span_err!(self.tcx.sess, span, E0158,
- "statics cannot be referenced in patterns");
+ self.span_e0158(span, "statics cannot be referenced in patterns")
+ }
+ PatternError::AssociatedConstInPattern(span) => {
+ self.span_e0158(span, "associated consts cannot be referenced in patterns")
}
PatternError::ConstEval(ref err) => {
err.report(self.tcx, pat_span, "pattern");
}
}
}
+
+ fn span_e0158(&self, span: Span, text: &str) {
+ span_err!(self.tcx.sess, span, E0158, "{}", text)
+ }
}
impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
use rustc::hir::def::{Def, CtorKind};
use rustc::hir::def_id::DefId;
use rustc::ty::{self, Ty, TyCtxt};
-use rustc::ty::layout::LayoutOf;
use rustc::ty::util::IntTypeExt;
use rustc::ty::subst::{Substs, Subst};
use rustc::util::common::ErrorReported;
if tcx.fn_sig(def_id).abi() == Abi::RustIntrinsic {
let layout_of = |ty: Ty<'tcx>| {
let ty = tcx.erase_regions(&ty);
- (tcx.at(e.span), cx.param_env).layout_of(ty).map_err(|err| {
+ tcx.at(e.span).layout_of(cx.param_env.and(ty)).map_err(|err| {
ConstEvalErr { span: e.span, kind: LayoutError(err) }
})
};
#[derive(Clone, Debug)]
pub enum PatternError<'tcx> {
+ AssociatedConstInPattern(Span),
StaticInPattern(Span),
ConstEval(ConstEvalErr<'tcx>),
}
-> Pattern<'tcx> {
let ty = self.tables.node_id_to_type(id);
let def = self.tables.qpath_def(qpath, id);
+ let is_associated_const = match def {
+ Def::AssociatedConst(_) => true,
+ _ => false,
+ };
let kind = match def {
Def::Const(def_id) | Def::AssociatedConst(def_id) => {
let substs = self.tables.node_substs(id);
return pat;
}
None => {
- self.errors.push(PatternError::StaticInPattern(span));
+ self.errors.push(if is_associated_const {
+ PatternError::AssociatedConstInPattern(span)
+ } else {
+ PatternError::StaticInPattern(span)
+ });
PatternKind::Wild
}
}
let emitter =
errors::emitter::EmitterWriter::stderr(errors::ColorConfig::Auto,
None,
- true);
+ true,
+ false);
let handler = errors::Handler::with_emitter(true, false, Box::new(emitter));
handler.emit(&MultiSpan::new(),
"aborting due to previous error(s)",
let sysroot = sysroot_candidates.iter()
.map(|sysroot| {
let libdir = filesearch::relative_target_lib_path(&sysroot, &target);
- sysroot.join(&libdir).join("codegen-backends")
+ sysroot.join(libdir).with_file_name("codegen-backends")
})
.filter(|f| {
info!("codegen backend candidate: {}", f.display());
None);
let (odir, ofile) = make_output(&matches);
- let (input, input_file_path) = match make_input(&matches.free) {
- Some((input, input_file_path)) => callbacks.some_input(input, input_file_path),
+ let (input, input_file_path, input_err) = match make_input(&matches.free) {
+ Some((input, input_file_path, input_err)) => {
+ let (input, input_file_path) = callbacks.some_input(input, input_file_path);
+ (input, input_file_path, input_err)
+ },
None => match callbacks.no_input(&matches, &sopts, &cfg, &odir, &ofile, &descriptions) {
- Some((input, input_file_path)) => (input, input_file_path),
+ Some((input, input_file_path)) => (input, input_file_path, None),
None => return (Ok(()), None),
},
};
sopts, input_file_path.clone(), descriptions, codemap, emitter_dest,
);
+ if let Some(err) = input_err {
+ // Immediately stop compilation if there was an issue reading
+ // the input (for example if the input stream is not UTF-8).
+ sess.err(&format!("{}", err));
+ return (Err(CompileIncomplete::Stopped), Some(sess));
+ }
+
let trans = get_trans(&sess);
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
}
// Extract input (string or file and optional path) from matches.
-fn make_input(free_matches: &[String]) -> Option<(Input, Option<PathBuf>)> {
+fn make_input(free_matches: &[String]) -> Option<(Input, Option<PathBuf>, Option<io::Error>)> {
if free_matches.len() == 1 {
let ifile = &free_matches[0];
if ifile == "-" {
let mut src = String::new();
- io::stdin().read_to_string(&mut src).unwrap();
+ let err = if io::stdin().read_to_string(&mut src).is_err() {
+ Some(io::Error::new(io::ErrorKind::InvalidData,
+ "couldn't read from stdin, as it did not contain valid UTF-8"))
+ } else {
+ None
+ };
Some((Input::Str { name: FileName::Anon, input: src },
- None))
+ None, err))
} else {
Some((Input::File(PathBuf::from(ifile)),
- Some(PathBuf::from(ifile))))
+ Some(PathBuf::from(ifile)), None))
}
} else {
None
let emitter =
Box::new(errors::emitter::EmitterWriter::stderr(errors::ColorConfig::Auto,
None,
+ false,
false));
let handler = errors::Handler::with_emitter(true, false, emitter);
}],
msg: msg.to_owned(),
show_code_when_inline: false,
+ approximate: false,
});
self
}
}],
msg: msg.to_owned(),
show_code_when_inline: true,
+ approximate: false,
});
self
}
}).collect(),
msg: msg.to_owned(),
show_code_when_inline: true,
+ approximate: false,
+ });
+ self
+ }
+
+ /// This is a suggestion that may contain mistakes or fillers and should
+ /// be read and understood by a human.
+ pub fn span_approximate_suggestion(&mut self, sp: Span, msg: &str,
+ suggestion: String) -> &mut Self {
+ self.suggestions.push(CodeSuggestion {
+ substitutions: vec![Substitution {
+ parts: vec![SubstitutionPart {
+ snippet: suggestion,
+ span: sp,
+ }],
+ }],
+ msg: msg.to_owned(),
+ show_code_when_inline: true,
+ approximate: true,
+ });
+ self
+ }
+
+ pub fn span_approximate_suggestions(&mut self, sp: Span, msg: &str,
+ suggestions: Vec<String>) -> &mut Self {
+ self.suggestions.push(CodeSuggestion {
+ substitutions: suggestions.into_iter().map(|snippet| Substitution {
+ parts: vec![SubstitutionPart {
+ snippet,
+ span: sp,
+ }],
+ }).collect(),
+ msg: msg.to_owned(),
+ show_code_when_inline: true,
+ approximate: true,
});
self
}
msg: &str,
suggestions: Vec<String>)
-> &mut Self);
+ forward!(pub fn span_approximate_suggestion(&mut self,
+ sp: Span,
+ msg: &str,
+ suggestion: String)
+ -> &mut Self);
+ forward!(pub fn span_approximate_suggestions(&mut self,
+ sp: Span,
+ msg: &str,
+ suggestions: Vec<String>)
+ -> &mut Self);
forward!(pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self);
forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self);
dst: Destination,
cm: Option<Rc<CodeMapper>>,
short_message: bool,
+ teach: bool,
}
struct FileWithAnnotatedLines {
impl EmitterWriter {
pub fn stderr(color_config: ColorConfig,
code_map: Option<Rc<CodeMapper>>,
- short_message: bool)
+ short_message: bool,
+ teach: bool)
-> EmitterWriter {
if color_config.use_color() {
let dst = Destination::from_stderr();
EmitterWriter {
dst,
cm: code_map,
- short_message: short_message,
+ short_message,
+ teach,
}
} else {
EmitterWriter {
dst: Raw(Box::new(io::stderr())),
cm: code_map,
- short_message: short_message,
+ short_message,
+ teach,
}
}
}
pub fn new(dst: Box<Write + Send>,
code_map: Option<Rc<CodeMapper>>,
- short_message: bool)
+ short_message: bool,
+ teach: bool)
-> EmitterWriter {
EmitterWriter {
dst: Raw(dst),
cm: code_map,
- short_message: short_message,
+ short_message,
+ teach,
}
}
line: &Line,
width_offset: usize,
code_offset: usize) -> Vec<(usize, Style)> {
+ if line.line_index == 0 {
+ return Vec::new();
+ }
+
let source_string = match file.get_line(line.line_index - 1) {
Some(s) => s,
None => return Vec::new(),
code_offset + annotation.start_col,
style);
}
- _ => (),
+ _ if self.teach => {
+ buffer.set_style_range(line_offset,
+ code_offset + annotation.start_col,
+ code_offset + annotation.end_col,
+ style,
+ annotation.is_primary);
+ }
+ _ => {}
}
}
pub substitutions: Vec<Substitution>,
pub msg: String,
pub show_code_when_inline: bool,
+ /// Whether or not the suggestion is approximate
+ ///
+ /// Sometimes we may show suggestions with placeholders,
+ /// which are useful for users but not useful for
+ /// tools like rustfix
+ pub approximate: bool,
}
#[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
cm: Option<Rc<CodeMapper>>,
flags: HandlerFlags)
-> Handler {
- let emitter = Box::new(EmitterWriter::stderr(color_config, cm, false));
+ let emitter = Box::new(EmitterWriter::stderr(color_config, cm, false, false));
Handler::with_emitter_and_flags(emitter, flags)
}
// Code for annotating snippets.
-use syntax_pos::{Span, FileMap};
-use CodeMapper;
-use std::rc::Rc;
use Level;
-#[derive(Clone)]
-pub struct SnippetData {
- codemap: Rc<CodeMapper>,
- files: Vec<FileInfo>,
-}
-
-#[derive(Clone)]
-pub struct FileInfo {
- file: Rc<FileMap>,
-
- /// The "primary file", if any, gets a `-->` marker instead of
- /// `>>>`, and has a line-number/column printed and not just a
- /// filename (other files are not guaranteed to have line numbers
- /// or columns). It appears first in the listing. It is known to
- /// contain at least one primary span, though primary spans (which
- /// are designated with `^^^`) may also occur in other files.
- primary_span: Option<Span>,
-
- lines: Vec<Line>,
-}
-
#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct Line {
pub line_index: usize,
pub fn num_lines(&self) -> usize {
self.text.len()
}
+
+ pub fn set_style_range(&mut self,
+ line: usize,
+ col_start: usize,
+ col_end: usize,
+ style: Style,
+ overwrite: bool) {
+ for col in col_start..col_end {
+ self.set_style(line, col, style, overwrite);
+ }
+ }
+
+ pub fn set_style(&mut self, line: usize, col: usize, style: Style, overwrite: bool) {
+ if let Some(ref mut line) = self.styles.get_mut(line) {
+ if let Some(s) = line.get_mut(col) {
+ if *s == Style::NoStyle || *s == Style::Quotation || overwrite {
+ *s = style;
+ }
+ }
+ }
+ }
}
// repr(transparent) types are allowed to have arbitrary ZSTs, not just
// PhantomData -- skip checking all ZST fields
if def.repr.transparent() {
- let is_zst = (cx, cx.param_env(field.did))
- .layout_of(field_ty)
+ let is_zst = cx
+ .layout_of(cx.param_env(field.did).and(field_ty))
.map(|layout| layout.is_zst())
.unwrap_or(false);
if is_zst {
Assign(_, ref value) => (value, "assigned value", false),
AssignOp(.., ref value) => (value, "assigned value", false),
InPlace(_, ref value) => (value, "emplacement value", false),
- Call(_, ref args) => {
- for arg in args {
- self.check_unused_parens_core(cx, arg, "function argument", false)
+ // either function/method call, or something this lint doesn't care about
+ ref call_or_other => {
+ let args_to_check;
+ let call_kind;
+ match *call_or_other {
+ Call(_, ref args) => {
+ call_kind = "function";
+ args_to_check = &args[..];
+ },
+ MethodCall(_, ref args) => {
+ call_kind = "method";
+ // first "argument" is self (which sometimes needs parens)
+ args_to_check = &args[1..];
+ }
+ // actual catch-all arm
+ _ => { return; }
}
- return;
- },
- MethodCall(_, ref args) => {
- for arg in &args[1..] { // first "argument" is self (which sometimes needs parens)
- self.check_unused_parens_core(cx, arg, "method argument", false)
+ // Don't lint if this is a nested macro expansion: otherwise, the lint could
+ // trigger in situations that macro authors shouldn't have to care about, e.g.,
+ // when a parenthesized token tree matched in one macro expansion is matched as
+ // an expression in another and used as a fn/method argument (Issue #47775)
+ if e.span.ctxt().outer().expn_info()
+ .map_or(false, |info| info.call_site.ctxt().outer()
+ .expn_info().is_some()) {
+ return;
+ }
+ let msg = format!("{} argument", call_kind);
+ for arg in args_to_check {
+ self.check_unused_parens_core(cx, arg, &msg, false);
}
return;
}
- _ => return,
};
self.check_unused_parens_core(cx, &value, msg, struct_lit_needs_parens);
}
self.describe_field_from_ty(&tnm.ty, field)
}
ty::TyArray(ty, _) | ty::TySlice(ty) => self.describe_field_from_ty(&ty, field),
- ty::TyClosure(closure_def_id, _) => {
+ ty::TyClosure(def_id, _) | ty::TyGenerator(def_id, _, _) => {
// Convert the def-id into a node-id. node-ids are only valid for
// the local code in the current crate, so this returns an `Option` in case
// the closure comes from another crate. But in that case we wouldn't
// be borrowck'ing it, so we can just unwrap:
- let node_id = self.tcx.hir.as_local_node_id(closure_def_id).unwrap();
+ let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
let freevar = self.tcx.with_freevars(node_id, |fv| fv[field.index()]);
self.tcx.hir.name(freevar.var_id()).to_string()
}
};
if let PlaceContext::Copy = context {
- let ty = place_ty.to_ty(self.tcx());
- if self.cx
- .infcx
- .type_moves_by_default(self.cx.param_env, ty, DUMMY_SP)
- {
- span_mirbug!(self, place, "attempted copy of non-Copy type ({:?})", ty);
- }
+ let tcx = self.tcx();
+ let trait_ref = ty::TraitRef {
+ def_id: tcx.lang_items().copy_trait().unwrap(),
+ substs: tcx.mk_substs_trait(place_ty.to_ty(tcx), &[]),
+ };
+
+ // In order to have a Copy operand, the type T of the value must be Copy. Note that we
+ // prove that T: Copy, rather than using the type_moves_by_default test. This is
+ // important because type_moves_by_default ignores the resulting region obligations and
+ // assumes they pass. This can result in bounds from Copy impls being unsoundly ignored
+ // (e.g., #29149). Note that we decide to use Copy before knowing whether the bounds
+ // fully apply: in effect, the rule is that if a value of some type could implement
+ // Copy, then it must.
+ self.cx.prove_trait_ref(trait_ref, location);
}
place_ty
}
}
}
ty::TyGenerator(def_id, substs, _) => {
- // Try upvars first. `field_tys` requires final optimized MIR.
- if let Some(ty) = substs.upvar_tys(def_id, tcx).nth(field.index()) {
+ // Try pre-transform fields first (upvars and current state)
+ if let Some(ty) = substs.pre_transforms_tys(def_id, tcx).nth(field.index()) {
return Ok(ty);
}
+ // Then try `field_tys` which contains all the fields, but it
+ // requires the final optimized MIR.
return match substs.field_tys(def_id, tcx).nth(field.index()) {
Some(ty) => Ok(ty),
None => Err(FieldAccessError::OutOfRange {
- field_count: substs.field_tys(def_id, tcx).count() + 1,
+ field_count: substs.field_tys(def_id, tcx).count(),
}),
};
}
}
}
AggregateKind::Generator(def_id, substs, _) => {
- if let Some(ty) = substs.upvar_tys(def_id, tcx).nth(field_index) {
+ // Try pre-transform fields first (upvars and current state)
+ if let Some(ty) = substs.pre_transforms_tys(def_id, tcx).nth(field_index) {
Ok(ty)
} else {
+ // Then try `field_tys` which contains all the fields, but it
+ // requires the final optimized MIR.
match substs.field_tys(def_id, tcx).nth(field_index) {
Some(ty) => Ok(ty),
None => Err(FieldAccessError::OutOfRange {
- field_count: substs.field_tys(def_id, tcx).count() + 1,
+ field_count: substs.field_tys(def_id, tcx).count(),
}),
}
}
--- /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.
+
+pub use super::*;
+
+use rustc::mir::*;
+use rustc::mir::visit::Visitor;
+use dataflow::BitDenotation;
+
+/// This calculates if any part of a MIR local could have previously been borrowed.
+/// This means that once a local has been borrowed, its bit will always be set
+/// from that point and onwards, even if the borrow ends. You could also think of this
+/// as computing the lifetimes of infinite borrows.
+/// This is used to compute which locals are live during a yield expression for
+/// immovable generators.
+#[derive(Copy, Clone)]
+pub struct HaveBeenBorrowedLocals<'a, 'tcx: 'a> {
+ mir: &'a Mir<'tcx>,
+}
+
+impl<'a, 'tcx: 'a> HaveBeenBorrowedLocals<'a, 'tcx> {
+ pub fn new(mir: &'a Mir<'tcx>)
+ -> Self {
+ HaveBeenBorrowedLocals { mir: mir }
+ }
+
+ pub fn mir(&self) -> &Mir<'tcx> {
+ self.mir
+ }
+}
+
+impl<'a, 'tcx> BitDenotation for HaveBeenBorrowedLocals<'a, 'tcx> {
+ type Idx = Local;
+ fn name() -> &'static str { "has_been_borrowed_locals" }
+ fn bits_per_block(&self) -> usize {
+ self.mir.local_decls.len()
+ }
+
+ fn start_block_effect(&self, _sets: &mut IdxSet<Local>) {
+ // Nothing is borrowed on function entry
+ }
+
+ fn statement_effect(&self,
+ sets: &mut BlockSets<Local>,
+ loc: Location) {
+ BorrowedLocalsVisitor {
+ sets,
+ }.visit_statement(loc.block, &self.mir[loc.block].statements[loc.statement_index], loc);
+ }
+
+ fn terminator_effect(&self,
+ sets: &mut BlockSets<Local>,
+ loc: Location) {
+ BorrowedLocalsVisitor {
+ sets,
+ }.visit_terminator(loc.block, self.mir[loc.block].terminator(), loc);
+ }
+
+ fn propagate_call_return(&self,
+ _in_out: &mut IdxSet<Local>,
+ _call_bb: mir::BasicBlock,
+ _dest_bb: mir::BasicBlock,
+ _dest_place: &mir::Place) {
+ // Nothing to do when a call returns successfully
+ }
+}
+
+impl<'a, 'tcx> BitwiseOperator for HaveBeenBorrowedLocals<'a, 'tcx> {
+ #[inline]
+ fn join(&self, pred1: usize, pred2: usize) -> usize {
+ pred1 | pred2 // "maybe" means we union effects of both preds
+ }
+}
+
+impl<'a, 'tcx> InitialFlow for HaveBeenBorrowedLocals<'a, 'tcx> {
+ #[inline]
+ fn bottom_value() -> bool {
+ false // bottom = unborrowed
+ }
+}
+
+struct BorrowedLocalsVisitor<'b, 'c: 'b> {
+ sets: &'b mut BlockSets<'c, Local>,
+}
+
+fn find_local<'tcx>(place: &Place<'tcx>) -> Option<Local> {
+ match *place {
+ Place::Local(l) => Some(l),
+ Place::Static(..) => None,
+ Place::Projection(ref proj) => {
+ match proj.elem {
+ ProjectionElem::Deref => None,
+ _ => find_local(&proj.base)
+ }
+ }
+ }
+}
+
+impl<'tcx, 'b, 'c> Visitor<'tcx> for BorrowedLocalsVisitor<'b, 'c> {
+ fn visit_rvalue(&mut self,
+ rvalue: &Rvalue<'tcx>,
+ location: Location) {
+ if let Rvalue::Ref(_, _, ref place) = *rvalue {
+ if let Some(local) = find_local(place) {
+ self.sets.gen(&local);
+ }
+ }
+
+ self.super_rvalue(rvalue, location)
+ }
+}
// Issue #46746: Two-phase borrows handles
// stmts of form `Tmp = &mut Borrow` ...
match lhs {
- Place::Local(..) => {} // okay
- Place::Static(..) => unreachable!(), // (filtered by is_unsafe_place)
+ Place::Local(..) | Place::Static(..) => {} // okay
Place::Projection(..) => {
// ... can assign into projections,
// e.g. `box (&mut _)`. Current
pub use self::storage_liveness::*;
+mod borrowed_locals;
+
+pub use self::borrowed_locals::*;
+
#[allow(dead_code)]
pub(super) mod borrows;
pub use self::impls::{DefinitelyInitializedPlaces, MovingOutStatements};
pub use self::impls::EverInitializedPlaces;
pub use self::impls::borrows::{Borrows, BorrowData};
+pub use self::impls::HaveBeenBorrowedLocals;
pub(crate) use self::impls::borrows::{ActiveBorrows, Reservations, ReserveOrActivateIndex};
pub use self::at_location::{FlowAtLocation, FlowsAtLocation};
pub(crate) use self::drop_flag_effects::*;
type TyLayout = EvalResult<'tcx, TyLayout<'tcx>>;
fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
- (self.tcx, self.param_env).layout_of(ty)
+ self.tcx.layout_of(self.param_env.and(ty))
.map_err(|layout| EvalErrorKind::Layout(layout).into())
}
}
use rustc::hir::def_id::DefId;
use rustc::hir::map::DefPathData;
use rustc::mir::mono::{Linkage, Visibility};
+use rustc::middle::exported_symbols::SymbolExportLevel;
use rustc::ty::{self, TyCtxt, InstanceDef};
use rustc::ty::item_path::characteristic_def_id_of_type;
use rustc::util::nodemap::{FxHashMap, FxHashSet};
.or_insert_with(make_codegen_unit);
let mut can_be_internalized = true;
- let (linkage, visibility) = match trans_item.explicit_linkage(tcx) {
+ let default_visibility = |id: DefId| {
+ if tcx.sess.target.target.options.default_hidden_visibility &&
+ tcx.symbol_export_level(id) != SymbolExportLevel::C
+ {
+ Visibility::Hidden
+ } else {
+ Visibility::Default
+ }
+ };
+ let (linkage, mut visibility) = match trans_item.explicit_linkage(tcx) {
Some(explicit_linkage) => (explicit_linkage, Visibility::Default),
None => {
match trans_item {
Visibility::Hidden
} else if def_id.is_local() {
if tcx.is_exported_symbol(def_id) {
- Visibility::Default
+ can_be_internalized = false;
+ default_visibility(def_id)
} else {
Visibility::Hidden
}
MonoItem::GlobalAsm(node_id) => {
let def_id = tcx.hir.local_def_id(node_id);
let visibility = if tcx.is_exported_symbol(def_id) {
- Visibility::Default
+ can_be_internalized = false;
+ default_visibility(def_id)
} else {
Visibility::Hidden
};
use transform::{MirPass, MirSource};
use transform::simplify;
use transform::no_landing_pads::no_landing_pads;
-use dataflow::{do_dataflow, DebugFormatted, MaybeStorageLive, state_for_location};
+use dataflow::{do_dataflow, DebugFormatted, state_for_location};
+use dataflow::{MaybeStorageLive, HaveBeenBorrowedLocals};
pub struct StateTransform;
HashMap<BasicBlock, liveness::LocalSet>) {
let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len());
let node_id = tcx.hir.as_local_node_id(source.def_id).unwrap();
- let analysis = MaybeStorageLive::new(mir);
+
+ // Calculate when MIR locals have live storage. This gives us an upper bound of their
+ // lifetimes.
+ let storage_live_analysis = MaybeStorageLive::new(mir);
let storage_live =
- do_dataflow(tcx, mir, node_id, &[], &dead_unwinds, analysis,
+ do_dataflow(tcx, mir, node_id, &[], &dead_unwinds, storage_live_analysis,
|bd, p| DebugFormatted::new(&bd.mir().local_decls[p]));
+ // Find the MIR locals which do not use StorageLive/StorageDead statements.
+ // The storage of these locals are always live.
let mut ignored = StorageIgnored(IdxSetBuf::new_filled(mir.local_decls.len()));
ignored.visit_mir(mir);
- let mut borrowed_locals = BorrowedLocals(IdxSetBuf::new_empty(mir.local_decls.len()));
- borrowed_locals.visit_mir(mir);
+ // Calculate the MIR locals which have been previously
+ // borrowed (even if they are still active).
+ // This is only used for immovable generators.
+ let borrowed_locals = if !movable {
+ let analysis = HaveBeenBorrowedLocals::new(mir);
+ let result =
+ do_dataflow(tcx, mir, node_id, &[], &dead_unwinds, analysis,
+ |bd, p| DebugFormatted::new(&bd.mir().local_decls[p]));
+ Some((analysis, result))
+ } else {
+ None
+ };
+ // Calculate the liveness of MIR locals ignoring borrows.
let mut set = liveness::LocalSet::new_empty(mir.local_decls.len());
let mut liveness = liveness::liveness_of_locals(mir, LivenessMode {
include_regular_use: true,
statement_index: data.statements.len(),
};
- let storage_liveness = state_for_location(loc, &analysis, &storage_live, mir);
+ if let Some((ref analysis, ref result)) = borrowed_locals {
+ let borrowed_locals = state_for_location(loc,
+ analysis,
+ result,
+ mir);
+ // The `liveness` variable contains the liveness of MIR locals ignoring borrows.
+ // This is correct for movable generators since borrows cannot live across
+ // suspension points. However for immovable generators we need to account for
+ // borrows, so we conseratively assume that all borrowed locals live forever.
+ // To do this we just union our `liveness` result with `borrowed_locals`, which
+ // contains all the locals which has been borrowed before this suspension point.
+ // If a borrow is converted to a raw reference, we must also assume that it lives
+ // forever. Note that the final liveness is still bounded by the storage liveness
+ // of the local, which happens using the `intersect` operation below.
+ liveness.outs[block].union(&borrowed_locals);
+ }
+
+ let mut storage_liveness = state_for_location(loc,
+ &storage_live_analysis,
+ &storage_live,
+ mir);
+ // Store the storage liveness for later use so we can restore the state
+ // after a suspension point
storage_liveness_map.insert(block, storage_liveness.clone());
- let mut live_locals = storage_liveness;
-
// Mark locals without storage statements as always having live storage
- live_locals.union(&ignored.0);
+ storage_liveness.union(&ignored.0);
- if !movable {
- // For immovable generators we consider borrowed locals to always be live.
- // This effectively makes those locals use just the storage liveness.
- liveness.outs[block].union(&borrowed_locals.0);
- }
+ // Locals live are live at this point only if they are used across
+ // suspension points (the `liveness` variable)
+ // and their storage is live (the `storage_liveness` variable)
+ storage_liveness.intersect(&liveness.outs[block]);
- // Locals live are live at this point only if they are used across suspension points
- // and their storage is live
- live_locals.intersect(&liveness.outs[block]);
+ let live_locals = storage_liveness;
// Add the locals life at this suspension point to the set of locals which live across
// any suspension points
use rustc::mir::*;
use rustc::mir::visit::*;
use rustc::ty::{self, Instance, Ty, TyCtxt, TypeFoldable};
-use rustc::ty::layout::LayoutOf;
use rustc::ty::subst::{Subst,Substs};
use std::collections::VecDeque;
fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>) -> Option<u64> {
- (tcx, param_env).layout_of(ty).ok().map(|layout| layout.size.bytes())
+ tcx.layout_of(param_env.and(ty)).ok().map(|layout| layout.size.bytes())
}
fn subst_and_normalize<'a, 'tcx: 'a>(
kind.name())
.span_label(e.span,
"can only break with a value inside `loop`")
+ .span_suggestion(e.span,
+ &format!("instead, use `break` on its own \
+ without a value inside this `{}` loop",
+ kind.name()),
+ "break".to_string())
.emit();
}
}
if let (Ok(snippet), false) = (cm.span_to_snippet(binding.span),
binding.is_renamed_extern_crate()) {
+ let suggested_name = if name.as_str().chars().next().unwrap().is_uppercase() {
+ format!("Other{}", name)
+ } else {
+ format!("other_{}", name)
+ };
+
err.span_suggestion(binding.span,
rename_msg,
if snippet.ends_with(';') {
- format!("{} as Other{};",
+ format!("{} as {};",
&snippet[..snippet.len()-1],
- name)
+ suggested_name)
} else {
- format!("{} as Other{}", snippet, name)
+ format!("{} as {}", snippet, suggested_name)
});
} else {
err.span_label(binding.span, rename_msg);
name.as_ptr(),
ty);
+ if tcx.sess.target.target.options.default_hidden_visibility {
+ llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
+ }
+
let callee = CString::new(kind.fn_name(method.name)).unwrap();
let callee = llvm::LLVMRustGetOrInsertFunction(llmod,
callee.as_ptr(),
// Default per-arch clobbers
// Basically what clang does
let arch_clobbers = match &bx.sess().target.target.arch[..] {
- "x86" | "x86_64" => vec!["~{dirflag}", "~{fpsr}", "~{flags}"],
- _ => Vec::new()
+ "x86" | "x86_64" => vec!["~{dirflag}", "~{fpsr}", "~{flags}"],
+ "mips" | "mips64" => vec!["~{$1}"],
+ _ => Vec::new()
};
let all_constraints =
Arc::new(local_crate)
};
+
+ providers.symbol_export_level = export_level;
}
pub fn provide_extern(providers: &mut Providers) {
Arc::new(crate_exports)
};
+ providers.symbol_export_level = export_level;
}
fn export_level(tcx: TyCtxt, sym_def_id: DefId) -> SymbolExportLevel {
if cgcx.debuginfo != config::NoDebugInfo {
options.debuginfo(true);
}
- if cgcx.crate_types.contains(&config::CrateTypeExecutable) {
- options.start("main");
- }
+
options.stack(1024 * 1024);
options.import_memory(cgcx.wasm_import_memory);
let assembled = input.and_then(|input| {
target_pointer_width: tcx.sess.target.target.target_pointer_width.clone(),
binaryen_linker: tcx.sess.linker_flavor() == LinkerFlavor::Binaryen,
debuginfo: tcx.sess.opts.debuginfo,
- wasm_import_memory: wasm_import_memory,
+ wasm_import_memory,
assembler_cmd,
};
type TyLayout = TyLayout<'tcx>;
fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
- (self.tcx, ty::ParamEnv::empty(traits::Reveal::All))
- .layout_of(ty)
+ self.tcx.layout_of(ty::ParamEnv::empty(traits::Reveal::All).and(ty))
.unwrap_or_else(|e| match e {
LayoutError::SizeOverflow(_) => self.sess().fatal(&e.to_string()),
_ => bug!("failed to get layout for `{}`: {}", ty, e)
ty::TyClosure(..) |
ty::TyGenerator(..) |
ty::TyAdt(..) |
- ty::TyDynamic(..) |
+ // FIXME(eddyb) producing readable type names for trait objects can result
+ // in problematically distinct types due to HRTB and subtyping (see #47638).
+ // ty::TyDynamic(..) |
ty::TyForeign(..) |
ty::TyStr => {
let mut name = String::with_capacity(32);
debug!("compare_impl_method(impl_trait_ref={:?})",
impl_trait_ref);
+ let impl_m_span = tcx.sess.codemap().def_span(impl_m_span);
+
if let Err(ErrorReported) = compare_self_type(tcx,
impl_m,
impl_m_span,
check_region_bounds_on_impl_method(tcx,
impl_m_span,
impl_m,
+ trait_m,
&trait_m_generics,
&impl_m_generics,
trait_to_skol_substs)?;
};
let mut diag = struct_span_err!(tcx.sess,
- cause.span,
+ cause.span(&tcx),
E0053,
"method `{}` has an incompatible type for trait",
trait_m.name);
fn check_region_bounds_on_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
span: Span,
impl_m: &ty::AssociatedItem,
+ trait_m: &ty::AssociatedItem,
trait_generics: &ty::Generics,
impl_generics: &ty::Generics,
trait_to_skol_substs: &Substs<'tcx>)
-> Result<(), ErrorReported> {
+ let span = tcx.sess.codemap().def_span(span);
let trait_params = &trait_generics.regions[..];
let impl_params = &impl_generics.regions[..];
// are zero. Since I don't quite know how to phrase things at
// the moment, give a kind of vague error message.
if trait_params.len() != impl_params.len() {
- struct_span_err!(tcx.sess,
- span,
- E0195,
- "lifetime parameters or bounds on method `{}` do not match the \
- trait declaration",
- impl_m.name)
- .span_label(span, "lifetimes do not match trait")
- .emit();
+ let mut err = struct_span_err!(tcx.sess,
+ span,
+ E0195,
+ "lifetime parameters or bounds on method `{}` do not match \
+ the trait declaration",
+ impl_m.name);
+ err.span_label(span, "lifetimes do not match method in trait");
+ if let Some(sp) = tcx.hir.span_if_local(trait_m.def_id) {
+ err.span_label(tcx.sess.codemap().def_span(sp),
+ "lifetimes in impl do not match this method in trait");
+ }
+ err.emit();
return Err(ErrorReported);
}
}).map(|(ref impl_arg, ref trait_arg)| {
(impl_arg.span, Some(trait_arg.span))
})
- .unwrap_or_else(|| (cause.span, tcx.hir.span_if_local(trait_m.def_id)))
+ .unwrap_or_else(|| (cause.span(&tcx), tcx.hir.span_if_local(trait_m.def_id)))
} else {
- (cause.span, tcx.hir.span_if_local(trait_m.def_id))
+ (cause.span(&tcx), tcx.hir.span_if_local(trait_m.def_id))
}
}
TypeError::Sorts(ExpectedFound { .. }) => {
{
(impl_m_output.span(), Some(trait_m_output.span()))
} else {
- (cause.span, tcx.hir.span_if_local(trait_m.def_id))
+ (cause.span(&tcx), tcx.hir.span_if_local(trait_m.def_id))
}
})
} else {
- (cause.span, tcx.hir.span_if_local(trait_m.def_id))
+ (cause.span(&tcx), tcx.hir.span_if_local(trait_m.def_id))
}
}
- _ => (cause.span, tcx.hir.span_if_local(trait_m.def_id)),
+ _ => (cause.span(&tcx), tcx.hir.span_if_local(trait_m.def_id)),
}
}
}
fn visit_pat(&mut self, pat: &'tcx Pat) {
+ intravisit::walk_pat(self, pat);
+
+ self.expr_count += 1;
+
if let PatKind::Binding(..) = pat.node {
let scope = self.region_scope_tree.var_scope(pat.hir_id.local_id);
let ty = self.fcx.tables.borrow().pat_ty(pat);
self.record(ty, Some(scope), None, pat.span);
}
-
- self.expr_count += 1;
-
- intravisit::walk_pat(self, pat);
}
fn visit_expr(&mut self, expr: &'tcx Expr) {
use rustc::ty::fold::TypeFoldable;
use rustc::ty::maps::Providers;
use rustc::ty::util::{Representability, IntTypeExt};
-use rustc::ty::layout::LayoutOf;
use errors::{DiagnosticBuilder, DiagnosticId};
use require_c_abi_if_variadic;
let span = body.value.span;
if body.is_generator && can_be_generator.is_some() {
- fcx.yield_ty = Some(fcx.next_ty_var(TypeVariableOrigin::TypeInference(span)));
+ let yield_ty = fcx.next_ty_var(TypeVariableOrigin::TypeInference(span));
+ fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
+ fcx.yield_ty = Some(yield_ty);
}
GatherLocalsVisitor { fcx: &fcx, }.visit_body(body);
let field_infos: Vec<_> = adt.non_enum_variant().fields.iter().map(|field| {
let ty = field.ty(tcx, Substs::identity_for_item(tcx, field.did));
let param_env = tcx.param_env(field.did);
- let layout = (tcx, param_env).layout_of(ty);
+ let layout = tcx.layout_of(param_env.and(ty));
// We are currently checking the type this field came from, so it must be local
let span = tcx.hir.span_if_local(field.did).unwrap();
let zst = layout.map(|layout| layout.is_zst()).unwrap_or(false);
for (i, &impl1_def_id) in impls.iter().enumerate() {
for &impl2_def_id in &impls[(i + 1)..] {
- let used_to_be_allowed = self.tcx.infer_ctxt().enter(|infcx| {
- if let Some(overlap) =
- traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id,
- IntercrateMode::Issue43355)
- {
+ let used_to_be_allowed = traits::overlapping_impls(
+ self.tcx,
+ impl1_def_id,
+ impl2_def_id,
+ IntercrateMode::Issue43355,
+ |overlap| {
self.check_for_common_items_in_impls(
- impl1_def_id, impl2_def_id, overlap, false);
+ impl1_def_id,
+ impl2_def_id,
+ overlap,
+ false,
+ );
false
- } else {
- true
- }
- });
+ },
+ || true,
+ );
if used_to_be_allowed {
- self.tcx.infer_ctxt().enter(|infcx| {
- if let Some(overlap) =
- traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id,
- IntercrateMode::Fixed)
- {
- self.check_for_common_items_in_impls(
- impl1_def_id, impl2_def_id, overlap, true);
- }
- });
+ traits::overlapping_impls(
+ self.tcx,
+ impl1_def_id,
+ impl2_def_id,
+ IntercrateMode::Fixed,
+ |overlap| self.check_for_common_items_in_impls(
+ impl1_def_id,
+ impl2_def_id,
+ overlap,
+ true,
+ ),
+ || (),
+ );
}
}
}
let def_id = cx.tcx.hir.body_owner_def_id(n);
let param_env = cx.tcx.param_env(def_id);
let substs = Substs::identity_for_item(cx.tcx, def_id);
- let n = cx.tcx.const_eval(param_env.and((def_id, substs))).unwrap();
+ let n = cx.tcx.const_eval(param_env.and((def_id, substs))).unwrap_or_else(|_| {
+ cx.tcx.mk_const(ty::Const {
+ val: ConstVal::Unevaluated(def_id, substs),
+ ty: cx.tcx.types.usize
+ })
+ });
let n = if let ConstVal::Integral(ConstInt::Usize(n)) = n.val {
n.to_string()
} else if let ConstVal::Unevaluated(def_id, _) = n.val {
let mut n = cx.tcx.lift(&n).unwrap();
if let ConstVal::Unevaluated(def_id, substs) = n.val {
let param_env = cx.tcx.param_env(def_id);
- n = cx.tcx.const_eval(param_env.and((def_id, substs))).unwrap()
+ if let Ok(new_n) = cx.tcx.const_eval(param_env.and((def_id, substs))) {
+ n = new_n;
+ }
};
let n = if let ConstVal::Integral(ConstInt::Usize(n)) = n.val {
n.to_string()
overflow: auto;
}
-.sidebar .current {
+.sidebar .block > ul > li {
margin-right: -20px;
}
-.content, nav { max-width: 960px; }
+.content, nav {
+ max-width: 960px;
+}
/* Everything else */
-.js-only, .hidden { display: none !important; }
+.js-only, .hidden {
+ display: none !important;
+}
.sidebar img {
margin: 20px auto;
border: none;
}
-.location a:first-child { font-weight: 500; }
+.location a:first-child {
+ font-weight: 500;
+}
.block {
padding: 0;
-ms-user-select: none;
user-select: none;
}
-.line-numbers span { cursor: pointer; }
+.line-numbers span {
+ cursor: pointer;
+}
.docblock-short p {
display: inline;
text-overflow: ellipsis;
margin: 0;
}
-.docblock-short code { white-space: nowrap; }
+.docblock-short code {
+ white-space: nowrap;
+}
.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 {
border-bottom: 1px solid;
display: inline-block;
}
-#main { position: relative; }
+#main {
+ position: relative;
+}
#main > .since {
top: inherit;
font-family: "Fira Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
padding: 0;
}
-.content .item-list li { margin-bottom: 1em; }
+.content .item-list li {
+ margin-bottom: 1em;
+}
.content .multi-column {
-moz-column-count: 5;
));
let emitter = errors::emitter::EmitterWriter::new(box Sink(data.clone()),
Some(codemap.clone()),
+ false,
false);
let old = io::set_panic(Some(box Sink(data.clone())));
let _bomb = Bomb(data.clone(), old.unwrap_or(box io::stdout()));
force_alloc_system = []
panic-unwind = ["panic_unwind"]
profiler = ["profiler_builtins"]
+wasm_syscall = []
assert!(nan.to_degrees().is_nan());
assert_eq!(inf.to_degrees(), inf);
assert_eq!(neg_inf.to_degrees(), neg_inf);
+ assert_eq!(1_f32.to_degrees(), 57.2957795130823208767981548141051703);
}
#[test]
/// # if cfg!(target_os = "linux") {
/// use std::io;
///
- /// let error = io::Error::from_raw_os_error(98);
- /// assert_eq!(error.kind(), io::ErrorKind::AddrInUse);
+ /// let error = io::Error::from_raw_os_error(22);
+ /// assert_eq!(error.kind(), io::ErrorKind::InvalidInput);
/// # }
/// ```
///
/// # if cfg!(windows) {
/// use std::io;
///
- /// let error = io::Error::from_raw_os_error(10048);
- /// assert_eq!(error.kind(), io::ErrorKind::AddrInUse);
+ /// let error = io::Error::from_raw_os_error(10022);
+ /// assert_eq!(error.kind(), io::ErrorKind::InvalidInput);
/// # }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(test, allow(dead_code))]
pub mod guard {
- pub unsafe fn current() -> Option<usize> {
+ pub type Guard = !;
+ pub unsafe fn current() -> Option<Guard> {
None
}
- pub unsafe fn init() -> Option<usize> {
+ pub unsafe fn init() -> Option<Guard> {
None
}
}
}
pub mod guard {
- pub unsafe fn current() -> Option<usize> { None }
- pub unsafe fn init() -> Option<usize> { None }
+ pub type Guard = !;
+ pub unsafe fn current() -> Option<Guard> { None }
+ pub unsafe fn init() -> Option<Guard> { None }
}
use sys_common::thread_info;
- // This is initialized in init() and only read from after
- static mut PAGE_SIZE: usize = 0;
-
#[cfg(any(target_os = "linux", target_os = "android"))]
unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize {
#[repr(C)]
_data: *mut libc::c_void) {
use sys_common::util::report_overflow;
- let guard = thread_info::stack_guard().unwrap_or(0);
+ let guard = thread_info::stack_guard().unwrap_or(0..0);
let addr = siginfo_si_addr(info);
// If the faulting address is within the guard page, then we print a
// message saying so and abort.
- if guard != 0 && guard - PAGE_SIZE <= addr && addr < guard {
+ if guard.start <= addr && addr < guard.end {
report_overflow();
rtabort!("stack overflow");
} else {
static mut MAIN_ALTSTACK: *mut libc::c_void = ptr::null_mut();
pub unsafe fn init() {
- PAGE_SIZE = ::sys::os::page_size();
-
let mut action: sigaction = mem::zeroed();
action.sa_flags = SA_SIGINFO | SA_ONSTACK;
action.sa_sigaction = signal_handler as sighandler_t;
not(target_os = "solaris")))]
#[cfg_attr(test, allow(dead_code))]
pub mod guard {
- pub unsafe fn current() -> Option<usize> { None }
- pub unsafe fn init() -> Option<usize> { None }
+ use ops::Range;
+ pub type Guard = Range<usize>;
+ pub unsafe fn current() -> Option<Guard> { None }
+ pub unsafe fn init() -> Option<Guard> { None }
}
use libc;
use libc::mmap;
use libc::{PROT_NONE, MAP_PRIVATE, MAP_ANON, MAP_FAILED, MAP_FIXED};
+ use ops::Range;
use sys::os;
- #[cfg(any(target_os = "macos",
- target_os = "bitrig",
- target_os = "openbsd",
- target_os = "solaris"))]
+ // This is initialized in init() and only read from after
+ static mut PAGE_SIZE: usize = 0;
+
+ pub type Guard = Range<usize>;
+
+ #[cfg(target_os = "solaris")]
+ unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
+ let mut current_stack: libc::stack_t = ::mem::zeroed();
+ assert_eq!(libc::stack_getbounds(&mut current_stack), 0);
+ Some(current_stack.ss_sp)
+ }
+
+ #[cfg(target_os = "macos")]
unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
- current().map(|s| s as *mut libc::c_void)
+ let stackaddr = libc::pthread_get_stackaddr_np(libc::pthread_self()) as usize -
+ libc::pthread_get_stacksize_np(libc::pthread_self());
+ Some(stackaddr as *mut libc::c_void)
+ }
+
+ #[cfg(any(target_os = "openbsd", target_os = "bitrig"))]
+ unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
+ let mut current_stack: libc::stack_t = ::mem::zeroed();
+ assert_eq!(libc::pthread_stackseg_np(libc::pthread_self(),
+ &mut current_stack), 0);
+
+ let extra = if cfg!(target_os = "bitrig") {3} else {1} * PAGE_SIZE;
+ let stackaddr = if libc::pthread_main_np() == 1 {
+ // main thread
+ current_stack.ss_sp as usize - current_stack.ss_size + extra
+ } else {
+ // new thread
+ current_stack.ss_sp as usize - current_stack.ss_size
+ };
+ Some(stackaddr as *mut libc::c_void)
}
#[cfg(any(target_os = "android", target_os = "freebsd",
ret
}
- pub unsafe fn init() -> Option<usize> {
- let psize = os::page_size();
+ pub unsafe fn init() -> Option<Guard> {
+ PAGE_SIZE = os::page_size();
+
let mut stackaddr = get_stack_start()?;
// Ensure stackaddr is page aligned! A parent process might
// stackaddr < stackaddr + stacksize, so if stackaddr is not
// page-aligned, calculate the fix such that stackaddr <
// new_page_aligned_stackaddr < stackaddr + stacksize
- let remainder = (stackaddr as usize) % psize;
+ let remainder = (stackaddr as usize) % PAGE_SIZE;
if remainder != 0 {
- stackaddr = ((stackaddr as usize) + psize - remainder)
+ stackaddr = ((stackaddr as usize) + PAGE_SIZE - remainder)
as *mut libc::c_void;
}
// Instead, we'll just note where we expect rlimit to start
// faulting, so our handler can report "stack overflow", and
// trust that the kernel's own stack guard will work.
- Some(stackaddr as usize)
+ let stackaddr = stackaddr as usize;
+ Some(stackaddr - PAGE_SIZE..stackaddr)
} else {
// Reallocate the last page of the stack.
// This ensures SIGBUS will be raised on
// stack overflow.
- let result = mmap(stackaddr, psize, PROT_NONE,
+ let result = mmap(stackaddr, PAGE_SIZE, PROT_NONE,
MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0);
if result != stackaddr || result == MAP_FAILED {
panic!("failed to allocate a guard page");
}
+ let guardaddr = stackaddr as usize;
let offset = if cfg!(target_os = "freebsd") {
2
} else {
1
};
- Some(stackaddr as usize + offset * psize)
+ Some(guardaddr..guardaddr + offset * PAGE_SIZE)
}
}
- #[cfg(target_os = "solaris")]
- pub unsafe fn current() -> Option<usize> {
- let mut current_stack: libc::stack_t = ::mem::zeroed();
- assert_eq!(libc::stack_getbounds(&mut current_stack), 0);
- Some(current_stack.ss_sp as usize)
- }
-
- #[cfg(target_os = "macos")]
- pub unsafe fn current() -> Option<usize> {
- Some(libc::pthread_get_stackaddr_np(libc::pthread_self()) as usize -
- libc::pthread_get_stacksize_np(libc::pthread_self()))
- }
-
- #[cfg(any(target_os = "openbsd", target_os = "bitrig"))]
- pub unsafe fn current() -> Option<usize> {
- let mut current_stack: libc::stack_t = ::mem::zeroed();
- assert_eq!(libc::pthread_stackseg_np(libc::pthread_self(),
- &mut current_stack), 0);
-
- let extra = if cfg!(target_os = "bitrig") {3} else {1} * os::page_size();
- Some(if libc::pthread_main_np() == 1 {
- // main thread
- current_stack.ss_sp as usize - current_stack.ss_size + extra
- } else {
- // new thread
- current_stack.ss_sp as usize - current_stack.ss_size
- })
+ #[cfg(any(target_os = "macos",
+ target_os = "bitrig",
+ target_os = "openbsd",
+ target_os = "solaris"))]
+ pub unsafe fn current() -> Option<Guard> {
+ let stackaddr = get_stack_start()? as usize;
+ Some(stackaddr - PAGE_SIZE..stackaddr)
}
#[cfg(any(target_os = "android", target_os = "freebsd",
target_os = "linux", target_os = "netbsd", target_os = "l4re"))]
- pub unsafe fn current() -> Option<usize> {
+ pub unsafe fn current() -> Option<Guard> {
let mut ret = None;
let mut attr: libc::pthread_attr_t = ::mem::zeroed();
assert_eq!(libc::pthread_attr_init(&mut attr), 0);
assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr,
&mut size), 0);
+ let stackaddr = stackaddr as usize;
ret = if cfg!(target_os = "freebsd") {
- Some(stackaddr as usize - guardsize)
+ // FIXME does freebsd really fault *below* the guard addr?
+ let guardaddr = stackaddr - guardsize;
+ Some(guardaddr - PAGE_SIZE..guardaddr)
} else if cfg!(target_os = "netbsd") {
- Some(stackaddr as usize)
+ Some(stackaddr - guardsize..stackaddr)
+ } else if cfg!(all(target_os = "linux", target_env = "gnu")) {
+ // glibc used to include the guard area within the stack, as noted in the BUGS
+ // section of `man pthread_attr_getguardsize`. This has been corrected starting
+ // with glibc 2.27, and in some distro backports, so the guard is now placed at the
+ // end (below) the stack. There's no easy way for us to know which we have at
+ // runtime, so we'll just match any fault in the range right above or below the
+ // stack base to call that fault a stack overflow.
+ Some(stackaddr - guardsize..stackaddr + guardsize)
} else {
- Some(stackaddr as usize + guardsize)
+ Some(stackaddr..stackaddr + guardsize)
};
}
assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
use ffi::OsString;
use marker::PhantomData;
-use mem;
use vec;
+use sys::ArgsSysCall;
pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
// On wasm these should always be null, so there's nothing for us to do here
}
pub fn args() -> Args {
- // When the runtime debugging is enabled we'll link to some extra runtime
- // functions to actually implement this. These are for now just implemented
- // in a node.js script but they're off by default as they're sort of weird
- // in a web-wasm world.
- if !super::DEBUG {
- return Args {
- iter: Vec::new().into_iter(),
- _dont_send_or_sync_me: PhantomData,
- }
- }
-
- // You'll find the definitions of these in `src/etc/wasm32-shim.js`. These
- // are just meant for debugging and should not be relied on.
- extern {
- fn rust_wasm_args_count() -> usize;
- fn rust_wasm_args_arg_size(a: usize) -> usize;
- fn rust_wasm_args_arg_fill(a: usize, ptr: *mut u8);
- }
-
- unsafe {
- let cnt = rust_wasm_args_count();
- let mut v = Vec::with_capacity(cnt);
- for i in 0..cnt {
- let n = rust_wasm_args_arg_size(i);
- let mut data = vec![0; n];
- rust_wasm_args_arg_fill(i, data.as_mut_ptr());
- v.push(mem::transmute::<Vec<u8>, OsString>(data));
- }
- Args {
- iter: v.into_iter(),
- _dont_send_or_sync_me: PhantomData,
- }
+ let v = ArgsSysCall::perform();
+ Args {
+ iter: v.into_iter(),
+ _dont_send_or_sync_me: PhantomData,
}
}
use io;
use os::raw::c_char;
-
-// Right now the wasm backend doesn't even have the ability to print to the
-// console by default. Wasm can't import anything from JS! (you have to
-// explicitly provide it).
-//
-// Sometimes that's a real bummer, though, so this flag can be set to `true` to
-// enable calling various shims defined in `src/etc/wasm32-shim.js` which should
-// help receive debug output and see what's going on. In general this flag
-// currently controls "will we call out to our own defined shims in node.js",
-// and this flag should always be `false` for release builds.
-const DEBUG: bool = false;
+use ptr;
+use sys::os_str::Buf;
+use sys_common::{AsInner, FromInner};
+use ffi::{OsString, OsStr};
+use time::Duration;
pub mod args;
#[cfg(feature = "backtrace")]
}
pub unsafe fn abort_internal() -> ! {
- ::intrinsics::abort();
+ ExitSysCall::perform(1)
}
// We don't have randomness yet, but I totally used a random number generator to
pub fn hashmap_random_keys() -> (u64, u64) {
(1, 2)
}
+
+// Implement a minimal set of system calls to enable basic IO
+pub enum SysCallIndex {
+ Read = 0,
+ Write = 1,
+ Exit = 2,
+ Args = 3,
+ GetEnv = 4,
+ SetEnv = 5,
+ Time = 6,
+}
+
+#[repr(C)]
+pub struct ReadSysCall {
+ fd: usize,
+ ptr: *mut u8,
+ len: usize,
+ result: usize,
+}
+
+impl ReadSysCall {
+ pub fn perform(fd: usize, buffer: &mut [u8]) -> usize {
+ let mut call_record = ReadSysCall {
+ fd,
+ len: buffer.len(),
+ ptr: buffer.as_mut_ptr(),
+ result: 0
+ };
+ if unsafe { syscall(SysCallIndex::Read, &mut call_record) } {
+ call_record.result
+ } else {
+ 0
+ }
+ }
+}
+
+#[repr(C)]
+pub struct WriteSysCall {
+ fd: usize,
+ ptr: *const u8,
+ len: usize,
+}
+
+impl WriteSysCall {
+ pub fn perform(fd: usize, buffer: &[u8]) {
+ let mut call_record = WriteSysCall {
+ fd,
+ len: buffer.len(),
+ ptr: buffer.as_ptr()
+ };
+ unsafe { syscall(SysCallIndex::Write, &mut call_record); }
+ }
+}
+
+#[repr(C)]
+pub struct ExitSysCall {
+ code: usize,
+}
+
+impl ExitSysCall {
+ pub fn perform(code: usize) -> ! {
+ let mut call_record = ExitSysCall {
+ code
+ };
+ unsafe {
+ syscall(SysCallIndex::Exit, &mut call_record);
+ ::intrinsics::abort();
+ }
+ }
+}
+
+fn receive_buffer<E, F: FnMut(&mut [u8]) -> Result<usize, E>>(estimate: usize, mut f: F)
+ -> Result<Vec<u8>, E>
+{
+ let mut buffer = vec![0; estimate];
+ loop {
+ let result = f(&mut buffer)?;
+ if result <= buffer.len() {
+ buffer.truncate(result);
+ break;
+ }
+ buffer.resize(result, 0);
+ }
+ Ok(buffer)
+}
+
+#[repr(C)]
+pub struct ArgsSysCall {
+ ptr: *mut u8,
+ len: usize,
+ result: usize
+}
+
+impl ArgsSysCall {
+ pub fn perform() -> Vec<OsString> {
+ receive_buffer(1024, |buffer| -> Result<usize, !> {
+ let mut call_record = ArgsSysCall {
+ len: buffer.len(),
+ ptr: buffer.as_mut_ptr(),
+ result: 0
+ };
+ if unsafe { syscall(SysCallIndex::Args, &mut call_record) } {
+ Ok(call_record.result)
+ } else {
+ Ok(0)
+ }
+ })
+ .unwrap()
+ .split(|b| *b == 0)
+ .map(|s| FromInner::from_inner(Buf { inner: s.to_owned() }))
+ .collect()
+ }
+}
+
+#[repr(C)]
+pub struct GetEnvSysCall {
+ key_ptr: *const u8,
+ key_len: usize,
+ value_ptr: *mut u8,
+ value_len: usize,
+ result: usize
+}
+
+impl GetEnvSysCall {
+ pub fn perform(key: &OsStr) -> Option<OsString> {
+ let key_buf = &AsInner::as_inner(key).inner;
+ receive_buffer(64, |buffer| {
+ let mut call_record = GetEnvSysCall {
+ key_len: key_buf.len(),
+ key_ptr: key_buf.as_ptr(),
+ value_len: buffer.len(),
+ value_ptr: buffer.as_mut_ptr(),
+ result: !0usize
+ };
+ if unsafe { syscall(SysCallIndex::GetEnv, &mut call_record) } {
+ if call_record.result == !0usize {
+ Err(())
+ } else {
+ Ok(call_record.result)
+ }
+ } else {
+ Err(())
+ }
+ }).ok().map(|s| {
+ FromInner::from_inner(Buf { inner: s })
+ })
+ }
+}
+
+#[repr(C)]
+pub struct SetEnvSysCall {
+ key_ptr: *const u8,
+ key_len: usize,
+ value_ptr: *const u8,
+ value_len: usize
+}
+
+impl SetEnvSysCall {
+ pub fn perform(key: &OsStr, value: Option<&OsStr>) {
+ let key_buf = &AsInner::as_inner(key).inner;
+ let value_buf = value.map(|v| &AsInner::as_inner(v).inner);
+ let mut call_record = SetEnvSysCall {
+ key_len: key_buf.len(),
+ key_ptr: key_buf.as_ptr(),
+ value_len: value_buf.map(|v| v.len()).unwrap_or(!0usize),
+ value_ptr: value_buf.map(|v| v.as_ptr()).unwrap_or(ptr::null())
+ };
+ unsafe { syscall(SysCallIndex::SetEnv, &mut call_record); }
+ }
+}
+
+pub enum TimeClock {
+ Monotonic = 0,
+ System = 1,
+}
+
+#[repr(C)]
+pub struct TimeSysCall {
+ clock: usize,
+ secs_hi: usize,
+ secs_lo: usize,
+ nanos: usize
+}
+
+impl TimeSysCall {
+ pub fn perform(clock: TimeClock) -> Duration {
+ let mut call_record = TimeSysCall {
+ clock: clock as usize,
+ secs_hi: 0,
+ secs_lo: 0,
+ nanos: 0
+ };
+ if unsafe { syscall(SysCallIndex::Time, &mut call_record) } {
+ Duration::new(
+ ((call_record.secs_hi as u64) << 32) | (call_record.secs_lo as u64),
+ call_record.nanos as u32
+ )
+ } else {
+ panic!("Time system call is not implemented by WebAssembly host");
+ }
+ }
+}
+
+unsafe fn syscall<T>(index: SysCallIndex, data: &mut T) -> bool {
+ #[cfg(feature = "wasm_syscall")]
+ extern {
+ #[no_mangle]
+ fn rust_wasm_syscall(index: usize, data: *mut Void) -> usize;
+ }
+
+ #[cfg(not(feature = "wasm_syscall"))]
+ unsafe fn rust_wasm_syscall(_index: usize, _data: *mut Void) -> usize { 0 }
+
+ rust_wasm_syscall(index as usize, data as *mut T as *mut Void) != 0
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use core::intrinsics;
-
use error::Error as StdError;
use ffi::{OsString, OsStr};
use fmt;
use io;
-use mem;
use path::{self, PathBuf};
use str;
-use sys::{unsupported, Void};
+use sys::{unsupported, Void, ExitSysCall, GetEnvSysCall, SetEnvSysCall};
pub fn errno() -> i32 {
0
}
pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
- // If we're debugging the runtime then we actually probe node.js to ask for
- // the value of environment variables to help provide inputs to programs.
- // The `extern` shims here are defined in `src/etc/wasm32-shim.js` and are
- // intended for debugging only, you should not rely on them.
- if !super::DEBUG {
- return Ok(None)
- }
-
- extern {
- fn rust_wasm_getenv_len(k: *const u8, kl: usize) -> isize;
- fn rust_wasm_getenv_data(k: *const u8, kl: usize, v: *mut u8);
- }
- unsafe {
- let k: &[u8] = mem::transmute(k);
- let n = rust_wasm_getenv_len(k.as_ptr(), k.len());
- if n == -1 {
- return Ok(None)
- }
- let mut data = vec![0; n as usize];
- rust_wasm_getenv_data(k.as_ptr(), k.len(), data.as_mut_ptr());
- Ok(Some(mem::transmute(data)))
- }
+ Ok(GetEnvSysCall::perform(k))
}
-pub fn setenv(_k: &OsStr, _v: &OsStr) -> io::Result<()> {
- unsupported()
+pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
+ Ok(SetEnvSysCall::perform(k, Some(v)))
}
-pub fn unsetenv(_n: &OsStr) -> io::Result<()> {
- unsupported()
+pub fn unsetenv(k: &OsStr) -> io::Result<()> {
+ Ok(SetEnvSysCall::perform(k, None))
}
pub fn temp_dir() -> PathBuf {
}
pub fn exit(_code: i32) -> ! {
- unsafe { intrinsics::abort() }
+ ExitSysCall::perform(_code as isize as usize)
}
pub fn getpid() -> u32 {
// except according to those terms.
use io;
-use sys::{Void, unsupported};
+use sys::{ReadSysCall, WriteSysCall};
-pub struct Stdin(Void);
+pub struct Stdin;
pub struct Stdout;
pub struct Stderr;
impl Stdin {
pub fn new() -> io::Result<Stdin> {
- unsupported()
+ Ok(Stdin)
}
- pub fn read(&self, _data: &mut [u8]) -> io::Result<usize> {
- match self.0 {}
+ pub fn read(&self, data: &mut [u8]) -> io::Result<usize> {
+ Ok(ReadSysCall::perform(0, data))
}
}
}
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
- // If runtime debugging is enabled at compile time we'll invoke some
- // runtime functions that are defined in our src/etc/wasm32-shim.js
- // debugging script. Note that this ffi function call is intended
- // *purely* for debugging only and should not be relied upon.
- if !super::DEBUG {
- return unsupported()
- }
- extern {
- fn rust_wasm_write_stdout(data: *const u8, len: usize);
- }
- unsafe {
- rust_wasm_write_stdout(data.as_ptr(), data.len())
- }
+ WriteSysCall::perform(1, data);
Ok(data.len())
}
}
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
- // See comments in stdout for what's going on here.
- if !super::DEBUG {
- return unsupported()
- }
- extern {
- fn rust_wasm_write_stderr(data: *const u8, len: usize);
- }
- unsafe {
- rust_wasm_write_stderr(data.as_ptr(), data.len())
- }
+ WriteSysCall::perform(2, data);
Ok(data.len())
}
}
pub mod guard {
- pub unsafe fn current() -> Option<usize> { None }
- pub unsafe fn init() -> Option<usize> { None }
+ pub type Guard = !;
+ pub unsafe fn current() -> Option<Guard> { None }
+ pub unsafe fn init() -> Option<Guard> { None }
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use fmt;
use time::Duration;
+use sys::{TimeSysCall, TimeClock};
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
-pub struct Instant;
+pub struct Instant(Duration);
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub struct SystemTime;
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub struct SystemTime(Duration);
-pub const UNIX_EPOCH: SystemTime = SystemTime;
+pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0));
impl Instant {
pub fn now() -> Instant {
- panic!("not supported on web assembly");
+ Instant(TimeSysCall::perform(TimeClock::Monotonic))
}
- pub fn sub_instant(&self, _other: &Instant) -> Duration {
- panic!("can't sub yet");
+ pub fn sub_instant(&self, other: &Instant) -> Duration {
+ self.0 - other.0
}
- pub fn add_duration(&self, _other: &Duration) -> Instant {
- panic!("can't add yet");
+ pub fn add_duration(&self, other: &Duration) -> Instant {
+ Instant(self.0 + *other)
}
- pub fn sub_duration(&self, _other: &Duration) -> Instant {
- panic!("can't sub yet");
+ pub fn sub_duration(&self, other: &Duration) -> Instant {
+ Instant(self.0 - *other)
}
}
impl SystemTime {
pub fn now() -> SystemTime {
- panic!("not supported on web assembly");
+ SystemTime(TimeSysCall::perform(TimeClock::System))
}
- pub fn sub_time(&self, _other: &SystemTime)
+ pub fn sub_time(&self, other: &SystemTime)
-> Result<Duration, Duration> {
- panic!()
- }
-
- pub fn add_duration(&self, _other: &Duration) -> SystemTime {
- panic!()
+ self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
}
- pub fn sub_duration(&self, _other: &Duration) -> SystemTime {
- panic!()
+ pub fn add_duration(&self, other: &Duration) -> SystemTime {
+ SystemTime(self.0 + *other)
}
-}
-impl fmt::Debug for SystemTime {
- fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
- panic!()
+ pub fn sub_duration(&self, other: &Duration) -> SystemTime {
+ SystemTime(self.0 - *other)
}
}
#[cfg_attr(test, allow(dead_code))]
pub mod guard {
- pub unsafe fn current() -> Option<usize> { None }
- pub unsafe fn init() -> Option<usize> { None }
+ pub type Guard = !;
+ pub unsafe fn current() -> Option<Guard> { None }
+ pub unsafe fn init() -> Option<Guard> { None }
}
#![allow(dead_code)] // stack_guard isn't used right now on all platforms
use cell::RefCell;
+use sys::thread::guard::Guard;
use thread::Thread;
struct ThreadInfo {
- stack_guard: Option<usize>,
+ stack_guard: Option<Guard>,
thread: Thread,
}
ThreadInfo::with(|info| info.thread.clone())
}
-pub fn stack_guard() -> Option<usize> {
- ThreadInfo::with(|info| info.stack_guard).and_then(|o| o)
+pub fn stack_guard() -> Option<Guard> {
+ ThreadInfo::with(|info| info.stack_guard.clone()).and_then(|o| o)
}
-pub fn set(stack_guard: Option<usize>, thread: Thread) {
+pub fn set(stack_guard: Option<Guard>, thread: Thread) {
THREAD_INFO.with(|c| assert!(c.borrow().is_none()));
THREAD_INFO.with(move |c| *c.borrow_mut() = Some(ThreadInfo{
stack_guard,
--- /dev/null
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Temporal quantification.
+//!
+//! Example:
+//!
+//! ```
+//! use std::time::Duration;
+//!
+//! let five_seconds = Duration::new(5, 0);
+//! // both declarations are equivalent
+//! assert_eq!(Duration::new(5, 0), Duration::from_secs(5));
+//! ```
+
+#![stable(feature = "time", since = "1.3.0")]
+
+use error::Error;
+use fmt;
+use ops::{Add, Sub, AddAssign, SubAssign};
+use sys::time;
+use sys_common::FromInner;
+
+#[stable(feature = "time", since = "1.3.0")]
+pub use core::time::Duration;
+
+/// A measurement of a monotonically nondecreasing clock.
+/// Opaque and useful only with `Duration`.
+///
+/// Instants are always guaranteed to be no less than any previously measured
+/// instant when created, and are often useful for tasks such as measuring
+/// benchmarks or timing how long an operation takes.
+///
+/// Note, however, that instants are not guaranteed to be **steady**. In other
+/// words, each tick of the underlying clock may not be the same length (e.g.
+/// some seconds may be longer than others). An instant may jump forwards or
+/// experience time dilation (slow down or speed up), but it will never go
+/// backwards.
+///
+/// Instants are opaque types that can only be compared to one another. There is
+/// no method to get "the number of seconds" from an instant. Instead, it only
+/// allows measuring the duration between two instants (or comparing two
+/// instants).
+///
+/// Example:
+///
+/// ```no_run
+/// use std::time::{Duration, Instant};
+/// use std::thread::sleep;
+///
+/// fn main() {
+/// let now = Instant::now();
+///
+/// // we sleep for 2 seconds
+/// sleep(Duration::new(2, 0));
+/// // it prints '2'
+/// println!("{}", now.elapsed().as_secs());
+/// }
+/// ```
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[stable(feature = "time2", since = "1.8.0")]
+pub struct Instant(time::Instant);
+
+/// A measurement of the system clock, useful for talking to
+/// external entities like the file system or other processes.
+///
+/// Distinct from the [`Instant`] type, this time measurement **is not
+/// monotonic**. This means that you can save a file to the file system, then
+/// save another file to the file system, **and the second file has a
+/// `SystemTime` measurement earlier than the first**. In other words, an
+/// operation that happens after another operation in real time may have an
+/// earlier `SystemTime`!
+///
+/// Consequently, comparing two `SystemTime` instances to learn about the
+/// duration between them returns a [`Result`] instead of an infallible [`Duration`]
+/// to indicate that this sort of time drift may happen and needs to be handled.
+///
+/// Although a `SystemTime` cannot be directly inspected, the [`UNIX_EPOCH`]
+/// constant is provided in this module as an anchor in time to learn
+/// information about a `SystemTime`. By calculating the duration from this
+/// fixed point in time, a `SystemTime` can be converted to a human-readable time,
+/// or perhaps some other string representation.
+///
+/// [`Instant`]: ../../std/time/struct.Instant.html
+/// [`Result`]: ../../std/result/enum.Result.html
+/// [`Duration`]: ../../std/time/struct.Duration.html
+/// [`UNIX_EPOCH`]: ../../std/time/constant.UNIX_EPOCH.html
+///
+/// Example:
+///
+/// ```no_run
+/// use std::time::{Duration, SystemTime};
+/// use std::thread::sleep;
+///
+/// fn main() {
+/// let now = SystemTime::now();
+///
+/// // we sleep for 2 seconds
+/// sleep(Duration::new(2, 0));
+/// match now.elapsed() {
+/// Ok(elapsed) => {
+/// // it prints '2'
+/// println!("{}", elapsed.as_secs());
+/// }
+/// Err(e) => {
+/// // an error occurred!
+/// println!("Error: {:?}", e);
+/// }
+/// }
+/// }
+/// ```
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[stable(feature = "time2", since = "1.8.0")]
+pub struct SystemTime(time::SystemTime);
+
+/// An error returned from the `duration_since` and `elapsed` methods on
+/// `SystemTime`, used to learn how far in the opposite direction a system time
+/// lies.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::thread::sleep;
+/// use std::time::{Duration, SystemTime};
+///
+/// let sys_time = SystemTime::now();
+/// sleep(Duration::from_secs(1));
+/// let new_sys_time = SystemTime::now();
+/// match sys_time.duration_since(new_sys_time) {
+/// Ok(_) => {}
+/// Err(e) => println!("SystemTimeError difference: {:?}", e.duration()),
+/// }
+/// ```
+#[derive(Clone, Debug)]
+#[stable(feature = "time2", since = "1.8.0")]
+pub struct SystemTimeError(Duration);
+
+impl Instant {
+ /// Returns an instant corresponding to "now".
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::time::Instant;
+ ///
+ /// let now = Instant::now();
+ /// ```
+ #[stable(feature = "time2", since = "1.8.0")]
+ pub fn now() -> Instant {
+ Instant(time::Instant::now())
+ }
+
+ /// Returns the amount of time elapsed from another instant to this one.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if `earlier` is later than `self`.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::time::{Duration, Instant};
+ /// use std::thread::sleep;
+ ///
+ /// let now = Instant::now();
+ /// sleep(Duration::new(1, 0));
+ /// let new_now = Instant::now();
+ /// println!("{:?}", new_now.duration_since(now));
+ /// ```
+ #[stable(feature = "time2", since = "1.8.0")]
+ pub fn duration_since(&self, earlier: Instant) -> Duration {
+ self.0.sub_instant(&earlier.0)
+ }
+
+ /// Returns the amount of time elapsed since this instant was created.
+ ///
+ /// # Panics
+ ///
+ /// This function may panic if the current time is earlier than this
+ /// instant, which is something that can happen if an `Instant` is
+ /// produced synthetically.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::thread::sleep;
+ /// use std::time::{Duration, Instant};
+ ///
+ /// let instant = Instant::now();
+ /// let three_secs = Duration::from_secs(3);
+ /// sleep(three_secs);
+ /// assert!(instant.elapsed() >= three_secs);
+ /// ```
+ #[stable(feature = "time2", since = "1.8.0")]
+ pub fn elapsed(&self) -> Duration {
+ Instant::now() - *self
+ }
+}
+
+#[stable(feature = "time2", since = "1.8.0")]
+impl Add<Duration> for Instant {
+ type Output = Instant;
+
+ fn add(self, other: Duration) -> Instant {
+ Instant(self.0.add_duration(&other))
+ }
+}
+
+#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
+impl AddAssign<Duration> for Instant {
+ fn add_assign(&mut self, other: Duration) {
+ *self = *self + other;
+ }
+}
+
+#[stable(feature = "time2", since = "1.8.0")]
+impl Sub<Duration> for Instant {
+ type Output = Instant;
+
+ fn sub(self, other: Duration) -> Instant {
+ Instant(self.0.sub_duration(&other))
+ }
+}
+
+#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
+impl SubAssign<Duration> for Instant {
+ fn sub_assign(&mut self, other: Duration) {
+ *self = *self - other;
+ }
+}
+
+#[stable(feature = "time2", since = "1.8.0")]
+impl Sub<Instant> for Instant {
+ type Output = Duration;
+
+ fn sub(self, other: Instant) -> Duration {
+ self.duration_since(other)
+ }
+}
+
+#[stable(feature = "time2", since = "1.8.0")]
+impl fmt::Debug for Instant {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+impl SystemTime {
+ /// Returns the system time corresponding to "now".
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::time::SystemTime;
+ ///
+ /// let sys_time = SystemTime::now();
+ /// ```
+ #[stable(feature = "time2", since = "1.8.0")]
+ pub fn now() -> SystemTime {
+ SystemTime(time::SystemTime::now())
+ }
+
+ /// Returns the amount of time elapsed from an earlier point in time.
+ ///
+ /// This function may fail because measurements taken earlier are not
+ /// guaranteed to always be before later measurements (due to anomalies such
+ /// as the system clock being adjusted either forwards or backwards).
+ ///
+ /// If successful, [`Ok`]`(`[`Duration`]`)` is returned where the duration represents
+ /// the amount of time elapsed from the specified measurement to this one.
+ ///
+ /// Returns an [`Err`] if `earlier` is later than `self`, and the error
+ /// contains how far from `self` the time is.
+ ///
+ /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok
+ /// [`Duration`]: ../../std/time/struct.Duration.html
+ /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::time::SystemTime;
+ ///
+ /// let sys_time = SystemTime::now();
+ /// let difference = sys_time.duration_since(sys_time)
+ /// .expect("SystemTime::duration_since failed");
+ /// println!("{:?}", difference);
+ /// ```
+ #[stable(feature = "time2", since = "1.8.0")]
+ pub fn duration_since(&self, earlier: SystemTime)
+ -> Result<Duration, SystemTimeError> {
+ self.0.sub_time(&earlier.0).map_err(SystemTimeError)
+ }
+
+ /// Returns the amount of time elapsed since this system time was created.
+ ///
+ /// This function may fail as the underlying system clock is susceptible to
+ /// drift and updates (e.g. the system clock could go backwards), so this
+ /// function may not always succeed. If successful, [`Ok`]`(`[`Duration`]`)` is
+ /// returned where the duration represents the amount of time elapsed from
+ /// this time measurement to the current time.
+ ///
+ /// Returns an [`Err`] if `self` is later than the current system time, and
+ /// the error contains how far from the current system time `self` is.
+ ///
+ /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok
+ /// [`Duration`]: ../../std/time/struct.Duration.html
+ /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::thread::sleep;
+ /// use std::time::{Duration, SystemTime};
+ ///
+ /// let sys_time = SystemTime::now();
+ /// let one_sec = Duration::from_secs(1);
+ /// sleep(one_sec);
+ /// assert!(sys_time.elapsed().unwrap() >= one_sec);
+ /// ```
+ #[stable(feature = "time2", since = "1.8.0")]
+ pub fn elapsed(&self) -> Result<Duration, SystemTimeError> {
+ SystemTime::now().duration_since(*self)
+ }
+}
+
+#[stable(feature = "time2", since = "1.8.0")]
+impl Add<Duration> for SystemTime {
+ type Output = SystemTime;
+
+ fn add(self, dur: Duration) -> SystemTime {
+ SystemTime(self.0.add_duration(&dur))
+ }
+}
+
+#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
+impl AddAssign<Duration> for SystemTime {
+ fn add_assign(&mut self, other: Duration) {
+ *self = *self + other;
+ }
+}
+
+#[stable(feature = "time2", since = "1.8.0")]
+impl Sub<Duration> for SystemTime {
+ type Output = SystemTime;
+
+ fn sub(self, dur: Duration) -> SystemTime {
+ SystemTime(self.0.sub_duration(&dur))
+ }
+}
+
+#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
+impl SubAssign<Duration> for SystemTime {
+ fn sub_assign(&mut self, other: Duration) {
+ *self = *self - other;
+ }
+}
+
+#[stable(feature = "time2", since = "1.8.0")]
+impl fmt::Debug for SystemTime {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+/// An anchor in time which can be used to create new `SystemTime` instances or
+/// learn about where in time a `SystemTime` lies.
+///
+/// This constant is defined to be "1970-01-01 00:00:00 UTC" on all systems with
+/// respect to the system clock. Using `duration_since` on an existing
+/// [`SystemTime`] instance can tell how far away from this point in time a
+/// measurement lies, and using `UNIX_EPOCH + duration` can be used to create a
+/// [`SystemTime`] instance to represent another fixed point in time.
+///
+/// [`SystemTime`]: ../../std/time/struct.SystemTime.html
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::time::{SystemTime, UNIX_EPOCH};
+///
+/// match SystemTime::now().duration_since(UNIX_EPOCH) {
+/// Ok(n) => println!("1970-01-01 00:00:00 UTC was {} seconds ago!", n.as_secs()),
+/// Err(_) => panic!("SystemTime before UNIX EPOCH!"),
+/// }
+/// ```
+#[stable(feature = "time2", since = "1.8.0")]
+pub const UNIX_EPOCH: SystemTime = SystemTime(time::UNIX_EPOCH);
+
+impl SystemTimeError {
+ /// Returns the positive duration which represents how far forward the
+ /// second system time was from the first.
+ ///
+ /// A `SystemTimeError` is returned from the [`duration_since`] and [`elapsed`]
+ /// methods of [`SystemTime`] whenever the second system time represents a point later
+ /// in time than the `self` of the method call.
+ ///
+ /// [`duration_since`]: ../../std/time/struct.SystemTime.html#method.duration_since
+ /// [`elapsed`]: ../../std/time/struct.SystemTime.html#method.elapsed
+ /// [`SystemTime`]: ../../std/time/struct.SystemTime.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::thread::sleep;
+ /// use std::time::{Duration, SystemTime};
+ ///
+ /// let sys_time = SystemTime::now();
+ /// sleep(Duration::from_secs(1));
+ /// let new_sys_time = SystemTime::now();
+ /// match sys_time.duration_since(new_sys_time) {
+ /// Ok(_) => {}
+ /// Err(e) => println!("SystemTimeError difference: {:?}", e.duration()),
+ /// }
+ /// ```
+ #[stable(feature = "time2", since = "1.8.0")]
+ pub fn duration(&self) -> Duration {
+ self.0
+ }
+}
+
+#[stable(feature = "time2", since = "1.8.0")]
+impl Error for SystemTimeError {
+ fn description(&self) -> &str { "other time was not earlier than self" }
+}
+
+#[stable(feature = "time2", since = "1.8.0")]
+impl fmt::Display for SystemTimeError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "second time provided was later than self")
+ }
+}
+
+impl FromInner<time::SystemTime> for SystemTime {
+ fn from_inner(time: time::SystemTime) -> SystemTime {
+ SystemTime(time)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::{Instant, SystemTime, Duration, UNIX_EPOCH};
+
+ macro_rules! assert_almost_eq {
+ ($a:expr, $b:expr) => ({
+ let (a, b) = ($a, $b);
+ if a != b {
+ let (a, b) = if a > b {(a, b)} else {(b, a)};
+ assert!(a - Duration::new(0, 100) <= b);
+ }
+ })
+ }
+
+ #[test]
+ fn instant_monotonic() {
+ let a = Instant::now();
+ let b = Instant::now();
+ assert!(b >= a);
+ }
+
+ #[test]
+ fn instant_elapsed() {
+ let a = Instant::now();
+ a.elapsed();
+ }
+
+ #[test]
+ fn instant_math() {
+ let a = Instant::now();
+ let b = Instant::now();
+ let dur = b.duration_since(a);
+ assert_almost_eq!(b - dur, a);
+ assert_almost_eq!(a + dur, b);
+
+ let second = Duration::new(1, 0);
+ assert_almost_eq!(a - second + second, a);
+ }
+
+ #[test]
+ #[should_panic]
+ fn instant_duration_panic() {
+ let a = Instant::now();
+ (a - Duration::new(1, 0)).duration_since(a);
+ }
+
+ #[test]
+ fn system_time_math() {
+ let a = SystemTime::now();
+ let b = SystemTime::now();
+ match b.duration_since(a) {
+ Ok(dur) if dur == Duration::new(0, 0) => {
+ assert_almost_eq!(a, b);
+ }
+ Ok(dur) => {
+ assert!(b > a);
+ assert_almost_eq!(b - dur, a);
+ assert_almost_eq!(a + dur, b);
+ }
+ Err(dur) => {
+ let dur = dur.duration();
+ assert!(a > b);
+ assert_almost_eq!(b + dur, a);
+ assert_almost_eq!(a - dur, b);
+ }
+ }
+
+ let second = Duration::new(1, 0);
+ assert_almost_eq!(a.duration_since(a - second).unwrap(), second);
+ assert_almost_eq!(a.duration_since(a + second).unwrap_err()
+ .duration(), second);
+
+ assert_almost_eq!(a - second + second, a);
+
+ // A difference of 80 and 800 years cannot fit inside a 32-bit time_t
+ if !(cfg!(unix) && ::mem::size_of::<::libc::time_t>() <= 4) {
+ let eighty_years = second * 60 * 60 * 24 * 365 * 80;
+ assert_almost_eq!(a - eighty_years + eighty_years, a);
+ assert_almost_eq!(a - (eighty_years * 10) + (eighty_years * 10), a);
+ }
+
+ let one_second_from_epoch = UNIX_EPOCH + Duration::new(1, 0);
+ let one_second_from_epoch2 = UNIX_EPOCH + Duration::new(0, 500_000_000)
+ + Duration::new(0, 500_000_000);
+ assert_eq!(one_second_from_epoch, one_second_from_epoch2);
+ }
+
+ #[test]
+ fn system_time_elapsed() {
+ let a = SystemTime::now();
+ drop(a.elapsed());
+ }
+
+ #[test]
+ fn since_epoch() {
+ let ts = SystemTime::now();
+ let a = ts.duration_since(UNIX_EPOCH).unwrap();
+ let b = ts.duration_since(UNIX_EPOCH - Duration::new(1, 0)).unwrap();
+ assert!(b > a);
+ assert_eq!(b - a, Duration::new(1, 0));
+
+ let thirty_years = Duration::new(1, 0) * 60 * 60 * 24 * 365 * 30;
+
+ // Right now for CI this test is run in an emulator, and apparently the
+ // aarch64 emulator's sense of time is that we're still living in the
+ // 70s.
+ //
+ // Otherwise let's assume that we're all running computers later than
+ // 2000.
+ if !cfg!(target_arch = "aarch64") {
+ assert!(a > thirty_years);
+ }
+
+ // let's assume that we're all running computers earlier than 2090.
+ // Should give us ~70 years to fix this!
+ let hundred_twenty_years = thirty_years * 4;
+ assert!(a < hundred_twenty_years);
+ }
+}
+++ /dev/null
-// Copyright 2012-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.
-
-use iter::Sum;
-use ops::{Add, Sub, Mul, Div, AddAssign, SubAssign, MulAssign, DivAssign};
-
-const NANOS_PER_SEC: u32 = 1_000_000_000;
-const NANOS_PER_MILLI: u32 = 1_000_000;
-const NANOS_PER_MICRO: u32 = 1_000;
-const MILLIS_PER_SEC: u64 = 1_000;
-const MICROS_PER_SEC: u64 = 1_000_000;
-
-/// A `Duration` type to represent a span of time, typically used for system
-/// timeouts.
-///
-/// Each `Duration` is composed of a whole number of seconds and a fractional part
-/// represented in nanoseconds. If the underlying system does not support
-/// nanosecond-level precision, APIs binding a system timeout will typically round up
-/// the number of nanoseconds.
-///
-/// `Duration`s implement many common traits, including [`Add`], [`Sub`], and other
-/// [`ops`] traits.
-///
-/// [`Add`]: ../../std/ops/trait.Add.html
-/// [`Sub`]: ../../std/ops/trait.Sub.html
-/// [`ops`]: ../../std/ops/index.html
-///
-/// # Examples
-///
-/// ```
-/// use std::time::Duration;
-///
-/// let five_seconds = Duration::new(5, 0);
-/// let five_seconds_and_five_nanos = five_seconds + Duration::new(0, 5);
-///
-/// assert_eq!(five_seconds_and_five_nanos.as_secs(), 5);
-/// assert_eq!(five_seconds_and_five_nanos.subsec_nanos(), 5);
-///
-/// let ten_millis = Duration::from_millis(10);
-/// ```
-#[stable(feature = "duration", since = "1.3.0")]
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)]
-pub struct Duration {
- secs: u64,
- nanos: u32, // Always 0 <= nanos < NANOS_PER_SEC
-}
-
-impl Duration {
- /// Creates a new `Duration` from the specified number of whole seconds and
- /// additional nanoseconds.
- ///
- /// If the number of nanoseconds is greater than 1 billion (the number of
- /// nanoseconds in a second), then it will carry over into the seconds provided.
- ///
- /// # Panics
- ///
- /// This constructor will panic if the carry from the nanoseconds overflows
- /// the seconds counter.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::time::Duration;
- ///
- /// let five_seconds = Duration::new(5, 0);
- /// ```
- #[stable(feature = "duration", since = "1.3.0")]
- #[inline]
- pub fn new(secs: u64, nanos: u32) -> Duration {
- let secs = secs.checked_add((nanos / NANOS_PER_SEC) as u64)
- .expect("overflow in Duration::new");
- let nanos = nanos % NANOS_PER_SEC;
- Duration { secs: secs, nanos: nanos }
- }
-
- /// Creates a new `Duration` from the specified number of whole seconds.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::time::Duration;
- ///
- /// let duration = Duration::from_secs(5);
- ///
- /// assert_eq!(5, duration.as_secs());
- /// assert_eq!(0, duration.subsec_nanos());
- /// ```
- #[stable(feature = "duration", since = "1.3.0")]
- #[inline]
- pub const fn from_secs(secs: u64) -> Duration {
- Duration { secs: secs, nanos: 0 }
- }
-
- /// Creates a new `Duration` from the specified number of milliseconds.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::time::Duration;
- ///
- /// let duration = Duration::from_millis(2569);
- ///
- /// assert_eq!(2, duration.as_secs());
- /// assert_eq!(569_000_000, duration.subsec_nanos());
- /// ```
- #[stable(feature = "duration", since = "1.3.0")]
- #[inline]
- pub const fn from_millis(millis: u64) -> Duration {
- Duration {
- secs: millis / MILLIS_PER_SEC,
- nanos: ((millis % MILLIS_PER_SEC) as u32) * NANOS_PER_MILLI,
- }
- }
-
- /// Creates a new `Duration` from the specified number of microseconds.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(duration_from_micros)]
- /// use std::time::Duration;
- ///
- /// let duration = Duration::from_micros(1_000_002);
- ///
- /// assert_eq!(1, duration.as_secs());
- /// assert_eq!(2000, duration.subsec_nanos());
- /// ```
- #[unstable(feature = "duration_from_micros", issue = "44400")]
- #[inline]
- pub const fn from_micros(micros: u64) -> Duration {
- Duration {
- secs: micros / MICROS_PER_SEC,
- nanos: ((micros % MICROS_PER_SEC) as u32) * NANOS_PER_MICRO,
- }
- }
-
- /// Creates a new `Duration` from the specified number of nanoseconds.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(duration_extras)]
- /// use std::time::Duration;
- ///
- /// let duration = Duration::from_nanos(1_000_000_123);
- ///
- /// assert_eq!(1, duration.as_secs());
- /// assert_eq!(123, duration.subsec_nanos());
- /// ```
- #[unstable(feature = "duration_extras", issue = "46507")]
- #[inline]
- pub const fn from_nanos(nanos: u64) -> Duration {
- Duration {
- secs: nanos / (NANOS_PER_SEC as u64),
- nanos: (nanos % (NANOS_PER_SEC as u64)) as u32,
- }
- }
-
- /// Returns the number of _whole_ seconds contained by this `Duration`.
- ///
- /// The returned value does not include the fractional (nanosecond) part of the
- /// duration, which can be obtained using [`subsec_nanos`].
- ///
- /// # Examples
- ///
- /// ```
- /// use std::time::Duration;
- ///
- /// let duration = Duration::new(5, 730023852);
- /// assert_eq!(duration.as_secs(), 5);
- /// ```
- ///
- /// To determine the total number of seconds represented by the `Duration`,
- /// use `as_secs` in combination with [`subsec_nanos`]:
- ///
- /// ```
- /// use std::time::Duration;
- ///
- /// let duration = Duration::new(5, 730023852);
- ///
- /// assert_eq!(5.730023852,
- /// duration.as_secs() as f64
- /// + duration.subsec_nanos() as f64 * 1e-9);
- /// ```
- ///
- /// [`subsec_nanos`]: #method.subsec_nanos
- #[stable(feature = "duration", since = "1.3.0")]
- #[inline]
- pub fn as_secs(&self) -> u64 { self.secs }
-
- /// Returns the fractional part of this `Duration`, in milliseconds.
- ///
- /// This method does **not** return the length of the duration when
- /// represented by milliseconds. The returned number always represents a
- /// fractional portion of a second (i.e. it is less than one thousand).
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(duration_extras)]
- /// use std::time::Duration;
- ///
- /// let duration = Duration::from_millis(5432);
- /// assert_eq!(duration.as_secs(), 5);
- /// assert_eq!(duration.subsec_millis(), 432);
- /// ```
- #[unstable(feature = "duration_extras", issue = "46507")]
- #[inline]
- pub fn subsec_millis(&self) -> u32 { self.nanos / NANOS_PER_MILLI }
-
- /// Returns the fractional part of this `Duration`, in microseconds.
- ///
- /// This method does **not** return the length of the duration when
- /// represented by microseconds. The returned number always represents a
- /// fractional portion of a second (i.e. it is less than one million).
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(duration_extras, duration_from_micros)]
- /// use std::time::Duration;
- ///
- /// let duration = Duration::from_micros(1_234_567);
- /// assert_eq!(duration.as_secs(), 1);
- /// assert_eq!(duration.subsec_micros(), 234_567);
- /// ```
- #[unstable(feature = "duration_extras", issue = "46507")]
- #[inline]
- pub fn subsec_micros(&self) -> u32 { self.nanos / NANOS_PER_MICRO }
-
- /// Returns the fractional part of this `Duration`, in nanoseconds.
- ///
- /// This method does **not** return the length of the duration when
- /// represented by nanoseconds. The returned number always represents a
- /// fractional portion of a second (i.e. it is less than one billion).
- ///
- /// # Examples
- ///
- /// ```
- /// use std::time::Duration;
- ///
- /// let duration = Duration::from_millis(5010);
- /// assert_eq!(duration.as_secs(), 5);
- /// assert_eq!(duration.subsec_nanos(), 10_000_000);
- /// ```
- #[stable(feature = "duration", since = "1.3.0")]
- #[inline]
- pub fn subsec_nanos(&self) -> u32 { self.nanos }
-
- /// Checked `Duration` addition. Computes `self + other`, returning [`None`]
- /// if overflow occurred.
- ///
- /// [`None`]: ../../std/option/enum.Option.html#variant.None
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// use std::time::Duration;
- ///
- /// assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), Some(Duration::new(0, 1)));
- /// assert_eq!(Duration::new(1, 0).checked_add(Duration::new(std::u64::MAX, 0)), None);
- /// ```
- #[stable(feature = "duration_checked_ops", since = "1.16.0")]
- #[inline]
- pub fn checked_add(self, rhs: Duration) -> Option<Duration> {
- if let Some(mut secs) = self.secs.checked_add(rhs.secs) {
- let mut nanos = self.nanos + rhs.nanos;
- if nanos >= NANOS_PER_SEC {
- nanos -= NANOS_PER_SEC;
- if let Some(new_secs) = secs.checked_add(1) {
- secs = new_secs;
- } else {
- return None;
- }
- }
- debug_assert!(nanos < NANOS_PER_SEC);
- Some(Duration {
- secs,
- nanos,
- })
- } else {
- None
- }
- }
-
- /// Checked `Duration` subtraction. Computes `self - other`, returning [`None`]
- /// if the result would be negative or if overflow occurred.
- ///
- /// [`None`]: ../../std/option/enum.Option.html#variant.None
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// use std::time::Duration;
- ///
- /// assert_eq!(Duration::new(0, 1).checked_sub(Duration::new(0, 0)), Some(Duration::new(0, 1)));
- /// assert_eq!(Duration::new(0, 0).checked_sub(Duration::new(0, 1)), None);
- /// ```
- #[stable(feature = "duration_checked_ops", since = "1.16.0")]
- #[inline]
- pub fn checked_sub(self, rhs: Duration) -> Option<Duration> {
- if let Some(mut secs) = self.secs.checked_sub(rhs.secs) {
- let nanos = if self.nanos >= rhs.nanos {
- self.nanos - rhs.nanos
- } else {
- if let Some(sub_secs) = secs.checked_sub(1) {
- secs = sub_secs;
- self.nanos + NANOS_PER_SEC - rhs.nanos
- } else {
- return None;
- }
- };
- debug_assert!(nanos < NANOS_PER_SEC);
- Some(Duration { secs: secs, nanos: nanos })
- } else {
- None
- }
- }
-
- /// Checked `Duration` multiplication. Computes `self * other`, returning
- /// [`None`] if overflow occurred.
- ///
- /// [`None`]: ../../std/option/enum.Option.html#variant.None
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// use std::time::Duration;
- ///
- /// assert_eq!(Duration::new(0, 500_000_001).checked_mul(2), Some(Duration::new(1, 2)));
- /// assert_eq!(Duration::new(std::u64::MAX - 1, 0).checked_mul(2), None);
- /// ```
- #[stable(feature = "duration_checked_ops", since = "1.16.0")]
- #[inline]
- pub fn checked_mul(self, rhs: u32) -> Option<Duration> {
- // Multiply nanoseconds as u64, because it cannot overflow that way.
- let total_nanos = self.nanos as u64 * rhs as u64;
- let extra_secs = total_nanos / (NANOS_PER_SEC as u64);
- let nanos = (total_nanos % (NANOS_PER_SEC as u64)) as u32;
- if let Some(secs) = self.secs
- .checked_mul(rhs as u64)
- .and_then(|s| s.checked_add(extra_secs)) {
- debug_assert!(nanos < NANOS_PER_SEC);
- Some(Duration {
- secs,
- nanos,
- })
- } else {
- None
- }
- }
-
- /// Checked `Duration` division. Computes `self / other`, returning [`None`]
- /// if `other == 0`.
- ///
- /// [`None`]: ../../std/option/enum.Option.html#variant.None
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// use std::time::Duration;
- ///
- /// assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0)));
- /// assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000)));
- /// assert_eq!(Duration::new(2, 0).checked_div(0), None);
- /// ```
- #[stable(feature = "duration_checked_ops", since = "1.16.0")]
- #[inline]
- pub fn checked_div(self, rhs: u32) -> Option<Duration> {
- if rhs != 0 {
- let secs = self.secs / (rhs as u64);
- let carry = self.secs - secs * (rhs as u64);
- let extra_nanos = carry * (NANOS_PER_SEC as u64) / (rhs as u64);
- let nanos = self.nanos / rhs + (extra_nanos as u32);
- debug_assert!(nanos < NANOS_PER_SEC);
- Some(Duration { secs: secs, nanos: nanos })
- } else {
- None
- }
- }
-}
-
-#[stable(feature = "duration", since = "1.3.0")]
-impl Add for Duration {
- type Output = Duration;
-
- fn add(self, rhs: Duration) -> Duration {
- self.checked_add(rhs).expect("overflow when adding durations")
- }
-}
-
-#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
-impl AddAssign for Duration {
- fn add_assign(&mut self, rhs: Duration) {
- *self = *self + rhs;
- }
-}
-
-#[stable(feature = "duration", since = "1.3.0")]
-impl Sub for Duration {
- type Output = Duration;
-
- fn sub(self, rhs: Duration) -> Duration {
- self.checked_sub(rhs).expect("overflow when subtracting durations")
- }
-}
-
-#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
-impl SubAssign for Duration {
- fn sub_assign(&mut self, rhs: Duration) {
- *self = *self - rhs;
- }
-}
-
-#[stable(feature = "duration", since = "1.3.0")]
-impl Mul<u32> for Duration {
- type Output = Duration;
-
- fn mul(self, rhs: u32) -> Duration {
- self.checked_mul(rhs).expect("overflow when multiplying duration by scalar")
- }
-}
-
-#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
-impl MulAssign<u32> for Duration {
- fn mul_assign(&mut self, rhs: u32) {
- *self = *self * rhs;
- }
-}
-
-#[stable(feature = "duration", since = "1.3.0")]
-impl Div<u32> for Duration {
- type Output = Duration;
-
- fn div(self, rhs: u32) -> Duration {
- self.checked_div(rhs).expect("divide by zero error when dividing duration by scalar")
- }
-}
-
-#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
-impl DivAssign<u32> for Duration {
- fn div_assign(&mut self, rhs: u32) {
- *self = *self / rhs;
- }
-}
-
-#[stable(feature = "duration_sum", since = "1.16.0")]
-impl Sum for Duration {
- fn sum<I: Iterator<Item=Duration>>(iter: I) -> Duration {
- iter.fold(Duration::new(0, 0), |a, b| a + b)
- }
-}
-
-#[stable(feature = "duration_sum", since = "1.16.0")]
-impl<'a> Sum<&'a Duration> for Duration {
- fn sum<I: Iterator<Item=&'a Duration>>(iter: I) -> Duration {
- iter.fold(Duration::new(0, 0), |a, b| a + *b)
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::Duration;
-
- #[test]
- fn creation() {
- assert!(Duration::from_secs(1) != Duration::from_secs(0));
- assert_eq!(Duration::from_secs(1) + Duration::from_secs(2),
- Duration::from_secs(3));
- assert_eq!(Duration::from_millis(10) + Duration::from_secs(4),
- Duration::new(4, 10 * 1_000_000));
- assert_eq!(Duration::from_millis(4000), Duration::new(4, 0));
- }
-
- #[test]
- fn secs() {
- assert_eq!(Duration::new(0, 0).as_secs(), 0);
- assert_eq!(Duration::from_secs(1).as_secs(), 1);
- assert_eq!(Duration::from_millis(999).as_secs(), 0);
- assert_eq!(Duration::from_millis(1001).as_secs(), 1);
- }
-
- #[test]
- fn nanos() {
- assert_eq!(Duration::new(0, 0).subsec_nanos(), 0);
- assert_eq!(Duration::new(0, 5).subsec_nanos(), 5);
- assert_eq!(Duration::new(0, 1_000_000_001).subsec_nanos(), 1);
- assert_eq!(Duration::from_secs(1).subsec_nanos(), 0);
- assert_eq!(Duration::from_millis(999).subsec_nanos(), 999 * 1_000_000);
- assert_eq!(Duration::from_millis(1001).subsec_nanos(), 1 * 1_000_000);
- }
-
- #[test]
- fn add() {
- assert_eq!(Duration::new(0, 0) + Duration::new(0, 1),
- Duration::new(0, 1));
- assert_eq!(Duration::new(0, 500_000_000) + Duration::new(0, 500_000_001),
- Duration::new(1, 1));
- }
-
- #[test]
- fn checked_add() {
- assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)),
- Some(Duration::new(0, 1)));
- assert_eq!(Duration::new(0, 500_000_000).checked_add(Duration::new(0, 500_000_001)),
- Some(Duration::new(1, 1)));
- assert_eq!(Duration::new(1, 0).checked_add(Duration::new(::u64::MAX, 0)), None);
- }
-
- #[test]
- fn sub() {
- assert_eq!(Duration::new(0, 1) - Duration::new(0, 0),
- Duration::new(0, 1));
- assert_eq!(Duration::new(0, 500_000_001) - Duration::new(0, 500_000_000),
- Duration::new(0, 1));
- assert_eq!(Duration::new(1, 0) - Duration::new(0, 1),
- Duration::new(0, 999_999_999));
- }
-
- #[test]
- fn checked_sub() {
- let zero = Duration::new(0, 0);
- let one_nano = Duration::new(0, 1);
- let one_sec = Duration::new(1, 0);
- assert_eq!(one_nano.checked_sub(zero), Some(Duration::new(0, 1)));
- assert_eq!(one_sec.checked_sub(one_nano),
- Some(Duration::new(0, 999_999_999)));
- assert_eq!(zero.checked_sub(one_nano), None);
- assert_eq!(zero.checked_sub(one_sec), None);
- }
-
- #[test] #[should_panic]
- fn sub_bad1() {
- Duration::new(0, 0) - Duration::new(0, 1);
- }
-
- #[test] #[should_panic]
- fn sub_bad2() {
- Duration::new(0, 0) - Duration::new(1, 0);
- }
-
- #[test]
- fn mul() {
- assert_eq!(Duration::new(0, 1) * 2, Duration::new(0, 2));
- assert_eq!(Duration::new(1, 1) * 3, Duration::new(3, 3));
- assert_eq!(Duration::new(0, 500_000_001) * 4, Duration::new(2, 4));
- assert_eq!(Duration::new(0, 500_000_001) * 4000,
- Duration::new(2000, 4000));
- }
-
- #[test]
- fn checked_mul() {
- assert_eq!(Duration::new(0, 1).checked_mul(2), Some(Duration::new(0, 2)));
- assert_eq!(Duration::new(1, 1).checked_mul(3), Some(Duration::new(3, 3)));
- assert_eq!(Duration::new(0, 500_000_001).checked_mul(4), Some(Duration::new(2, 4)));
- assert_eq!(Duration::new(0, 500_000_001).checked_mul(4000),
- Some(Duration::new(2000, 4000)));
- assert_eq!(Duration::new(::u64::MAX - 1, 0).checked_mul(2), None);
- }
-
- #[test]
- fn div() {
- assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0));
- assert_eq!(Duration::new(1, 1) / 3, Duration::new(0, 333_333_333));
- assert_eq!(Duration::new(99, 999_999_000) / 100,
- Duration::new(0, 999_999_990));
- }
-
- #[test]
- fn checked_div() {
- assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0)));
- assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000)));
- assert_eq!(Duration::new(2, 0).checked_div(0), None);
- }
-}
+++ /dev/null
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Temporal quantification.
-//!
-//! Example:
-//!
-//! ```
-//! use std::time::Duration;
-//!
-//! let five_seconds = Duration::new(5, 0);
-//! // both declarations are equivalent
-//! assert_eq!(Duration::new(5, 0), Duration::from_secs(5));
-//! ```
-
-#![stable(feature = "time", since = "1.3.0")]
-
-use error::Error;
-use fmt;
-use ops::{Add, Sub, AddAssign, SubAssign};
-use sys::time;
-use sys_common::FromInner;
-
-#[stable(feature = "time", since = "1.3.0")]
-pub use self::duration::Duration;
-
-mod duration;
-
-/// A measurement of a monotonically nondecreasing clock.
-/// Opaque and useful only with `Duration`.
-///
-/// Instants are always guaranteed to be no less than any previously measured
-/// instant when created, and are often useful for tasks such as measuring
-/// benchmarks or timing how long an operation takes.
-///
-/// Note, however, that instants are not guaranteed to be **steady**. In other
-/// words, each tick of the underlying clock may not be the same length (e.g.
-/// some seconds may be longer than others). An instant may jump forwards or
-/// experience time dilation (slow down or speed up), but it will never go
-/// backwards.
-///
-/// Instants are opaque types that can only be compared to one another. There is
-/// no method to get "the number of seconds" from an instant. Instead, it only
-/// allows measuring the duration between two instants (or comparing two
-/// instants).
-///
-/// Example:
-///
-/// ```no_run
-/// use std::time::{Duration, Instant};
-/// use std::thread::sleep;
-///
-/// fn main() {
-/// let now = Instant::now();
-///
-/// // we sleep for 2 seconds
-/// sleep(Duration::new(2, 0));
-/// // it prints '2'
-/// println!("{}", now.elapsed().as_secs());
-/// }
-/// ```
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-#[stable(feature = "time2", since = "1.8.0")]
-pub struct Instant(time::Instant);
-
-/// A measurement of the system clock, useful for talking to
-/// external entities like the file system or other processes.
-///
-/// Distinct from the [`Instant`] type, this time measurement **is not
-/// monotonic**. This means that you can save a file to the file system, then
-/// save another file to the file system, **and the second file has a
-/// `SystemTime` measurement earlier than the first**. In other words, an
-/// operation that happens after another operation in real time may have an
-/// earlier `SystemTime`!
-///
-/// Consequently, comparing two `SystemTime` instances to learn about the
-/// duration between them returns a [`Result`] instead of an infallible [`Duration`]
-/// to indicate that this sort of time drift may happen and needs to be handled.
-///
-/// Although a `SystemTime` cannot be directly inspected, the [`UNIX_EPOCH`]
-/// constant is provided in this module as an anchor in time to learn
-/// information about a `SystemTime`. By calculating the duration from this
-/// fixed point in time, a `SystemTime` can be converted to a human-readable time,
-/// or perhaps some other string representation.
-///
-/// [`Instant`]: ../../std/time/struct.Instant.html
-/// [`Result`]: ../../std/result/enum.Result.html
-/// [`Duration`]: ../../std/time/struct.Duration.html
-/// [`UNIX_EPOCH`]: ../../std/time/constant.UNIX_EPOCH.html
-///
-/// Example:
-///
-/// ```no_run
-/// use std::time::{Duration, SystemTime};
-/// use std::thread::sleep;
-///
-/// fn main() {
-/// let now = SystemTime::now();
-///
-/// // we sleep for 2 seconds
-/// sleep(Duration::new(2, 0));
-/// match now.elapsed() {
-/// Ok(elapsed) => {
-/// // it prints '2'
-/// println!("{}", elapsed.as_secs());
-/// }
-/// Err(e) => {
-/// // an error occurred!
-/// println!("Error: {:?}", e);
-/// }
-/// }
-/// }
-/// ```
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-#[stable(feature = "time2", since = "1.8.0")]
-pub struct SystemTime(time::SystemTime);
-
-/// An error returned from the `duration_since` and `elapsed` methods on
-/// `SystemTime`, used to learn how far in the opposite direction a system time
-/// lies.
-///
-/// # Examples
-///
-/// ```no_run
-/// use std::thread::sleep;
-/// use std::time::{Duration, SystemTime};
-///
-/// let sys_time = SystemTime::now();
-/// sleep(Duration::from_secs(1));
-/// let new_sys_time = SystemTime::now();
-/// match sys_time.duration_since(new_sys_time) {
-/// Ok(_) => {}
-/// Err(e) => println!("SystemTimeError difference: {:?}", e.duration()),
-/// }
-/// ```
-#[derive(Clone, Debug)]
-#[stable(feature = "time2", since = "1.8.0")]
-pub struct SystemTimeError(Duration);
-
-impl Instant {
- /// Returns an instant corresponding to "now".
- ///
- /// # Examples
- ///
- /// ```
- /// use std::time::Instant;
- ///
- /// let now = Instant::now();
- /// ```
- #[stable(feature = "time2", since = "1.8.0")]
- pub fn now() -> Instant {
- Instant(time::Instant::now())
- }
-
- /// Returns the amount of time elapsed from another instant to this one.
- ///
- /// # Panics
- ///
- /// This function will panic if `earlier` is later than `self`.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::time::{Duration, Instant};
- /// use std::thread::sleep;
- ///
- /// let now = Instant::now();
- /// sleep(Duration::new(1, 0));
- /// let new_now = Instant::now();
- /// println!("{:?}", new_now.duration_since(now));
- /// ```
- #[stable(feature = "time2", since = "1.8.0")]
- pub fn duration_since(&self, earlier: Instant) -> Duration {
- self.0.sub_instant(&earlier.0)
- }
-
- /// Returns the amount of time elapsed since this instant was created.
- ///
- /// # Panics
- ///
- /// This function may panic if the current time is earlier than this
- /// instant, which is something that can happen if an `Instant` is
- /// produced synthetically.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::thread::sleep;
- /// use std::time::{Duration, Instant};
- ///
- /// let instant = Instant::now();
- /// let three_secs = Duration::from_secs(3);
- /// sleep(three_secs);
- /// assert!(instant.elapsed() >= three_secs);
- /// ```
- #[stable(feature = "time2", since = "1.8.0")]
- pub fn elapsed(&self) -> Duration {
- Instant::now() - *self
- }
-}
-
-#[stable(feature = "time2", since = "1.8.0")]
-impl Add<Duration> for Instant {
- type Output = Instant;
-
- fn add(self, other: Duration) -> Instant {
- Instant(self.0.add_duration(&other))
- }
-}
-
-#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
-impl AddAssign<Duration> for Instant {
- fn add_assign(&mut self, other: Duration) {
- *self = *self + other;
- }
-}
-
-#[stable(feature = "time2", since = "1.8.0")]
-impl Sub<Duration> for Instant {
- type Output = Instant;
-
- fn sub(self, other: Duration) -> Instant {
- Instant(self.0.sub_duration(&other))
- }
-}
-
-#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
-impl SubAssign<Duration> for Instant {
- fn sub_assign(&mut self, other: Duration) {
- *self = *self - other;
- }
-}
-
-#[stable(feature = "time2", since = "1.8.0")]
-impl Sub<Instant> for Instant {
- type Output = Duration;
-
- fn sub(self, other: Instant) -> Duration {
- self.duration_since(other)
- }
-}
-
-#[stable(feature = "time2", since = "1.8.0")]
-impl fmt::Debug for Instant {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- self.0.fmt(f)
- }
-}
-
-impl SystemTime {
- /// Returns the system time corresponding to "now".
- ///
- /// # Examples
- ///
- /// ```
- /// use std::time::SystemTime;
- ///
- /// let sys_time = SystemTime::now();
- /// ```
- #[stable(feature = "time2", since = "1.8.0")]
- pub fn now() -> SystemTime {
- SystemTime(time::SystemTime::now())
- }
-
- /// Returns the amount of time elapsed from an earlier point in time.
- ///
- /// This function may fail because measurements taken earlier are not
- /// guaranteed to always be before later measurements (due to anomalies such
- /// as the system clock being adjusted either forwards or backwards).
- ///
- /// If successful, [`Ok`]`(`[`Duration`]`)` is returned where the duration represents
- /// the amount of time elapsed from the specified measurement to this one.
- ///
- /// Returns an [`Err`] if `earlier` is later than `self`, and the error
- /// contains how far from `self` the time is.
- ///
- /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok
- /// [`Duration`]: ../../std/time/struct.Duration.html
- /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
- ///
- /// # Examples
- ///
- /// ```
- /// use std::time::SystemTime;
- ///
- /// let sys_time = SystemTime::now();
- /// let difference = sys_time.duration_since(sys_time)
- /// .expect("SystemTime::duration_since failed");
- /// println!("{:?}", difference);
- /// ```
- #[stable(feature = "time2", since = "1.8.0")]
- pub fn duration_since(&self, earlier: SystemTime)
- -> Result<Duration, SystemTimeError> {
- self.0.sub_time(&earlier.0).map_err(SystemTimeError)
- }
-
- /// Returns the amount of time elapsed since this system time was created.
- ///
- /// This function may fail as the underlying system clock is susceptible to
- /// drift and updates (e.g. the system clock could go backwards), so this
- /// function may not always succeed. If successful, [`Ok`]`(`[`Duration`]`)` is
- /// returned where the duration represents the amount of time elapsed from
- /// this time measurement to the current time.
- ///
- /// Returns an [`Err`] if `self` is later than the current system time, and
- /// the error contains how far from the current system time `self` is.
- ///
- /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok
- /// [`Duration`]: ../../std/time/struct.Duration.html
- /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::thread::sleep;
- /// use std::time::{Duration, SystemTime};
- ///
- /// let sys_time = SystemTime::now();
- /// let one_sec = Duration::from_secs(1);
- /// sleep(one_sec);
- /// assert!(sys_time.elapsed().unwrap() >= one_sec);
- /// ```
- #[stable(feature = "time2", since = "1.8.0")]
- pub fn elapsed(&self) -> Result<Duration, SystemTimeError> {
- SystemTime::now().duration_since(*self)
- }
-}
-
-#[stable(feature = "time2", since = "1.8.0")]
-impl Add<Duration> for SystemTime {
- type Output = SystemTime;
-
- fn add(self, dur: Duration) -> SystemTime {
- SystemTime(self.0.add_duration(&dur))
- }
-}
-
-#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
-impl AddAssign<Duration> for SystemTime {
- fn add_assign(&mut self, other: Duration) {
- *self = *self + other;
- }
-}
-
-#[stable(feature = "time2", since = "1.8.0")]
-impl Sub<Duration> for SystemTime {
- type Output = SystemTime;
-
- fn sub(self, dur: Duration) -> SystemTime {
- SystemTime(self.0.sub_duration(&dur))
- }
-}
-
-#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
-impl SubAssign<Duration> for SystemTime {
- fn sub_assign(&mut self, other: Duration) {
- *self = *self - other;
- }
-}
-
-#[stable(feature = "time2", since = "1.8.0")]
-impl fmt::Debug for SystemTime {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- self.0.fmt(f)
- }
-}
-
-/// An anchor in time which can be used to create new `SystemTime` instances or
-/// learn about where in time a `SystemTime` lies.
-///
-/// This constant is defined to be "1970-01-01 00:00:00 UTC" on all systems with
-/// respect to the system clock. Using `duration_since` on an existing
-/// [`SystemTime`] instance can tell how far away from this point in time a
-/// measurement lies, and using `UNIX_EPOCH + duration` can be used to create a
-/// [`SystemTime`] instance to represent another fixed point in time.
-///
-/// [`SystemTime`]: ../../std/time/struct.SystemTime.html
-///
-/// # Examples
-///
-/// ```no_run
-/// use std::time::{SystemTime, UNIX_EPOCH};
-///
-/// match SystemTime::now().duration_since(UNIX_EPOCH) {
-/// Ok(n) => println!("1970-01-01 00:00:00 UTC was {} seconds ago!", n.as_secs()),
-/// Err(_) => panic!("SystemTime before UNIX EPOCH!"),
-/// }
-/// ```
-#[stable(feature = "time2", since = "1.8.0")]
-pub const UNIX_EPOCH: SystemTime = SystemTime(time::UNIX_EPOCH);
-
-impl SystemTimeError {
- /// Returns the positive duration which represents how far forward the
- /// second system time was from the first.
- ///
- /// A `SystemTimeError` is returned from the [`duration_since`] and [`elapsed`]
- /// methods of [`SystemTime`] whenever the second system time represents a point later
- /// in time than the `self` of the method call.
- ///
- /// [`duration_since`]: ../../std/time/struct.SystemTime.html#method.duration_since
- /// [`elapsed`]: ../../std/time/struct.SystemTime.html#method.elapsed
- /// [`SystemTime`]: ../../std/time/struct.SystemTime.html
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::thread::sleep;
- /// use std::time::{Duration, SystemTime};
- ///
- /// let sys_time = SystemTime::now();
- /// sleep(Duration::from_secs(1));
- /// let new_sys_time = SystemTime::now();
- /// match sys_time.duration_since(new_sys_time) {
- /// Ok(_) => {}
- /// Err(e) => println!("SystemTimeError difference: {:?}", e.duration()),
- /// }
- /// ```
- #[stable(feature = "time2", since = "1.8.0")]
- pub fn duration(&self) -> Duration {
- self.0
- }
-}
-
-#[stable(feature = "time2", since = "1.8.0")]
-impl Error for SystemTimeError {
- fn description(&self) -> &str { "other time was not earlier than self" }
-}
-
-#[stable(feature = "time2", since = "1.8.0")]
-impl fmt::Display for SystemTimeError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "second time provided was later than self")
- }
-}
-
-impl FromInner<time::SystemTime> for SystemTime {
- fn from_inner(time: time::SystemTime) -> SystemTime {
- SystemTime(time)
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::{Instant, SystemTime, Duration, UNIX_EPOCH};
-
- macro_rules! assert_almost_eq {
- ($a:expr, $b:expr) => ({
- let (a, b) = ($a, $b);
- if a != b {
- let (a, b) = if a > b {(a, b)} else {(b, a)};
- assert!(a - Duration::new(0, 100) <= b);
- }
- })
- }
-
- #[test]
- fn instant_monotonic() {
- let a = Instant::now();
- let b = Instant::now();
- assert!(b >= a);
- }
-
- #[test]
- fn instant_elapsed() {
- let a = Instant::now();
- a.elapsed();
- }
-
- #[test]
- fn instant_math() {
- let a = Instant::now();
- let b = Instant::now();
- let dur = b.duration_since(a);
- assert_almost_eq!(b - dur, a);
- assert_almost_eq!(a + dur, b);
-
- let second = Duration::new(1, 0);
- assert_almost_eq!(a - second + second, a);
- }
-
- #[test]
- #[should_panic]
- fn instant_duration_panic() {
- let a = Instant::now();
- (a - Duration::new(1, 0)).duration_since(a);
- }
-
- #[test]
- fn system_time_math() {
- let a = SystemTime::now();
- let b = SystemTime::now();
- match b.duration_since(a) {
- Ok(dur) if dur == Duration::new(0, 0) => {
- assert_almost_eq!(a, b);
- }
- Ok(dur) => {
- assert!(b > a);
- assert_almost_eq!(b - dur, a);
- assert_almost_eq!(a + dur, b);
- }
- Err(dur) => {
- let dur = dur.duration();
- assert!(a > b);
- assert_almost_eq!(b + dur, a);
- assert_almost_eq!(a - dur, b);
- }
- }
-
- let second = Duration::new(1, 0);
- assert_almost_eq!(a.duration_since(a - second).unwrap(), second);
- assert_almost_eq!(a.duration_since(a + second).unwrap_err()
- .duration(), second);
-
- assert_almost_eq!(a - second + second, a);
-
- // A difference of 80 and 800 years cannot fit inside a 32-bit time_t
- if !(cfg!(unix) && ::mem::size_of::<::libc::time_t>() <= 4) {
- let eighty_years = second * 60 * 60 * 24 * 365 * 80;
- assert_almost_eq!(a - eighty_years + eighty_years, a);
- assert_almost_eq!(a - (eighty_years * 10) + (eighty_years * 10), a);
- }
-
- let one_second_from_epoch = UNIX_EPOCH + Duration::new(1, 0);
- let one_second_from_epoch2 = UNIX_EPOCH + Duration::new(0, 500_000_000)
- + Duration::new(0, 500_000_000);
- assert_eq!(one_second_from_epoch, one_second_from_epoch2);
- }
-
- #[test]
- fn system_time_elapsed() {
- let a = SystemTime::now();
- drop(a.elapsed());
- }
-
- #[test]
- fn since_epoch() {
- let ts = SystemTime::now();
- let a = ts.duration_since(UNIX_EPOCH).unwrap();
- let b = ts.duration_since(UNIX_EPOCH - Duration::new(1, 0)).unwrap();
- assert!(b > a);
- assert_eq!(b - a, Duration::new(1, 0));
-
- let thirty_years = Duration::new(1, 0) * 60 * 60 * 24 * 365 * 30;
-
- // Right now for CI this test is run in an emulator, and apparently the
- // aarch64 emulator's sense of time is that we're still living in the
- // 70s.
- //
- // Otherwise let's assume that we're all running computers later than
- // 2000.
- if !cfg!(target_arch = "aarch64") {
- assert!(a > thirty_years);
- }
-
- // let's assume that we're all running computers earlier than 2090.
- // Should give us ~70 years to fix this!
- let hundred_twenty_years = thirty_years * 4;
- assert!(a < hundred_twenty_years);
- }
-}
}
}
- /// Given a `Span`, try to get a shorter span ending just after the first
- /// occurrence of `char` `c`.
+ /// Given a `Span`, get a new `Span` covering the first token and all its trailing whitespace or
+ /// the original `Span`.
+ ///
+ /// If `sp` points to `"let mut x"`, then a span pointing at `"let "` will be returned.
+ pub fn span_until_non_whitespace(&self, sp: Span) -> Span {
+ if let Ok(snippet) = self.span_to_snippet(sp) {
+ let mut offset = 0;
+ // get the bytes width of all the non-whitespace characters
+ for c in snippet.chars().take_while(|c| !c.is_whitespace()) {
+ offset += c.len_utf8();
+ }
+ // get the bytes width of all the whitespace characters after that
+ for c in snippet[offset..].chars().take_while(|c| c.is_whitespace()) {
+ offset += c.len_utf8();
+ }
+ if offset > 1 {
+ return sp.with_hi(BytePos(sp.lo().0 + offset as u32));
+ }
+ }
+ sp
+ }
+
+ /// Given a `Span`, try to get a shorter span ending just after the first occurrence of `char`
+ /// `c`.
pub fn span_through_char(&self, sp: Span, c: char) -> Span {
if let Ok(snippet) = self.span_to_snippet(sp) {
if let Some(offset) = snippet.find(c) {
is just used for rustc unit tests \
and will never be stable",
cfg_fn!(rustc_attrs))),
+ ("rustc_serialize_exclude_null", Normal, Gated(Stability::Unstable,
+ "rustc_attrs",
+ "the `#[rustc_serialize_exclude_null]` attribute \
+ is an internal-only feature",
+ cfg_fn!(rustc_attrs))),
("rustc_synthetic", Whitelisted, Gated(Stability::Unstable,
"rustc_attrs",
"this attribute \
registry: Option<Registry>,
cm: Rc<CodeMapper + 'static>,
pretty: bool,
+ /// Whether "approximate suggestions" are enabled in the config
+ approximate_suggestions: bool,
}
impl JsonEmitter {
pub fn stderr(registry: Option<Registry>,
code_map: Rc<CodeMap>,
- pretty: bool) -> JsonEmitter {
+ pretty: bool,
+ approximate_suggestions: bool) -> JsonEmitter {
JsonEmitter {
dst: Box::new(io::stderr()),
registry,
cm: code_map,
pretty,
+ approximate_suggestions,
}
}
pub fn basic(pretty: bool) -> JsonEmitter {
let file_path_mapping = FilePathMapping::empty();
- JsonEmitter::stderr(None, Rc::new(CodeMap::new(file_path_mapping)), pretty)
+ JsonEmitter::stderr(None, Rc::new(CodeMap::new(file_path_mapping)),
+ pretty, false)
}
pub fn new(dst: Box<Write + Send>,
registry: Option<Registry>,
code_map: Rc<CodeMap>,
- pretty: bool) -> JsonEmitter {
+ pretty: bool,
+ approximate_suggestions: bool) -> JsonEmitter {
JsonEmitter {
dst,
registry,
cm: code_map,
pretty,
+ approximate_suggestions,
}
}
}
}
#[derive(RustcEncodable)]
+#[allow(unused_attributes)]
struct DiagnosticSpan {
file_name: String,
byte_start: u32,
/// If we are suggesting a replacement, this will contain text
/// that should be sliced in atop this span.
suggested_replacement: Option<String>,
+ /// If the suggestion is approximate
+ #[rustc_serialize_exclude_null]
+ suggestion_approximate: Option<bool>,
/// Macro invocations that created the code at this span, if any.
expansion: Option<Box<DiagnosticSpanMacroExpansion>>,
}
}
let buf = BufWriter::default();
let output = buf.clone();
- EmitterWriter::new(Box::new(buf), Some(je.cm.clone()), false).emit(db);
+ EmitterWriter::new(Box::new(buf), Some(je.cm.clone()), false, false).emit(db);
let output = Arc::try_unwrap(output.0).unwrap().into_inner().unwrap();
let output = String::from_utf8(output).unwrap();
impl DiagnosticSpan {
fn from_span_label(span: SpanLabel,
- suggestion: Option<&String>,
+ suggestion: Option<(&String, bool)>,
je: &JsonEmitter)
-> DiagnosticSpan {
Self::from_span_etc(span.span,
fn from_span_etc(span: Span,
is_primary: bool,
label: Option<String>,
- suggestion: Option<&String>,
+ suggestion: Option<(&String, bool)>,
je: &JsonEmitter)
-> DiagnosticSpan {
// obtain the full backtrace from the `macro_backtrace`
fn from_span_full(span: Span,
is_primary: bool,
label: Option<String>,
- suggestion: Option<&String>,
+ suggestion: Option<(&String, bool)>,
mut backtrace: vec::IntoIter<MacroBacktrace>,
je: &JsonEmitter)
-> DiagnosticSpan {
def_site_span,
})
});
+
+ let suggestion_approximate = if je.approximate_suggestions {
+ suggestion.map(|x| x.1)
+ } else {
+ None
+ };
+
DiagnosticSpan {
file_name: start.file.name.to_string(),
byte_start: span.lo().0 - start.file.start_pos.0,
column_end: end.col.0 + 1,
is_primary,
text: DiagnosticSpanLine::from_span(span, je),
- suggested_replacement: suggestion.cloned(),
+ suggested_replacement: suggestion.map(|x| x.0.clone()),
+ suggestion_approximate,
expansion: backtrace_step,
label,
}
suggestion.substitutions
.iter()
.flat_map(|substitution| {
- substitution.parts.iter().map(move |suggestion| {
+ substitution.parts.iter().map(move |suggestion_inner| {
let span_label = SpanLabel {
- span: suggestion.span,
+ span: suggestion_inner.span,
is_primary: true,
label: None,
};
DiagnosticSpan::from_span_label(span_label,
- Some(&suggestion.snippet),
+ Some((&suggestion_inner.snippet,
+ suggestion.approximate)),
je)
})
})
#![feature(match_default_bindings)]
#![feature(i128_type)]
#![feature(const_atomic_usize_new)]
+#![feature(rustc_attrs)]
// See librustc_cratesio_shim/Cargo.toml for a comment explaining this.
#[allow(unused_extern_crates)]
self.err_span(self.mk_sp(from_pos, to_pos), m)
}
+ /// Pushes a character to a message string for error reporting
+ fn push_escaped_char_for_msg(m: &mut String, c: char) {
+ match c {
+ '\u{20}'...'\u{7e}' => {
+ // Don't escape \, ' or " for user-facing messages
+ m.push(c);
+ }
+ _ => {
+ for c in c.escape_default() {
+ m.push(c);
+ }
+ }
+ }
+ }
+
/// Report a lexical error spanning [`from_pos`, `to_pos`), appending an
/// escaped character to the error message
fn fatal_span_char(&self, from_pos: BytePos, to_pos: BytePos, m: &str, c: char) -> FatalError {
let mut m = m.to_string();
m.push_str(": ");
- for c in c.escape_default() {
- m.push(c)
- }
+ Self::push_escaped_char_for_msg(&mut m, c);
self.fatal_span_(from_pos, to_pos, &m[..])
}
fn struct_fatal_span_char(&self,
-> DiagnosticBuilder<'a> {
let mut m = m.to_string();
m.push_str(": ");
- for c in c.escape_default() {
- m.push(c)
- }
+ Self::push_escaped_char_for_msg(&mut m, c);
self.sess.span_diagnostic.struct_span_fatal(self.mk_sp(from_pos, to_pos), &m[..])
}
fn err_span_char(&self, from_pos: BytePos, to_pos: BytePos, m: &str, c: char) {
let mut m = m.to_string();
m.push_str(": ");
- for c in c.escape_default() {
- m.push(c)
- }
+ Self::push_escaped_char_for_msg(&mut m, c);
self.err_span_(from_pos, to_pos, &m[..]);
}
fn struct_err_span_char(&self,
-> DiagnosticBuilder<'a> {
let mut m = m.to_string();
m.push_str(": ");
- for c in c.escape_default() {
- m.push(c)
- }
+ Self::push_escaped_char_for_msg(&mut m, c);
self.sess.span_diagnostic.struct_span_err(self.mk_sp(from_pos, to_pos), &m[..])
}
fn mk_sess(cm: Rc<CodeMap>) -> ParseSess {
let emitter = errors::emitter::EmitterWriter::new(Box::new(io::sink()),
Some(cm.clone()),
+ false,
false);
ParseSess {
span_diagnostic: errors::Handler::with_emitter(true, false, Box::new(emitter)),
keywords::Unsafe.name(),
keywords::While.name(),
keywords::Yield.name(),
+ keywords::Static.name(),
].contains(&ident.name)
}
let emitter = EmitterWriter::new(Box::new(Shared { data: output.clone() }),
Some(code_map.clone()),
+ false,
false);
let handler = Handler::with_emitter(true, false, Box::new(emitter));
handler.span_err(msp, "foo");
Struct(_, ref fields) => {
let emit_struct_field = cx.ident_of("emit_struct_field");
let mut stmts = Vec::new();
- for (i, &FieldInfo { name, ref self_, span, .. }) in fields.iter().enumerate() {
+ for (i, &FieldInfo { name, ref self_, span, attrs, .. }) in fields.iter().enumerate() {
let name = match name {
Some(id) => id.name,
None => Symbol::intern(&format!("_field{}", i)),
} else {
cx.expr(span, ExprKind::Ret(Some(call)))
};
- stmts.push(cx.stmt_expr(call));
+
+ // This exists for https://github.com/rust-lang/rust/pull/47540
+ //
+ // If we decide to stabilize that flag this can be removed
+ let expr = if attrs.iter().any(|a| a.check_name("rustc_serialize_exclude_null")) {
+ let is_some = cx.ident_of("is_some");
+ let condition = cx.expr_method_call(span, self_.clone(), is_some, vec![]);
+ cx.expr_if(span, condition, call, None)
+ } else {
+ call
+ };
+ let stmt = cx.stmt_expr(expr);
+ stmts.push(stmt);
}
// unit structs have no fields and need to return Ok()
/// Return a `Span` that would enclose both `self` and `end`.
pub fn to(self, end: Span) -> Span {
- let span = self.data();
- let end = end.data();
+ let span_data = self.data();
+ let end_data = end.data();
+ // FIXME(jseyfried): self.ctxt should always equal end.ctxt here (c.f. issue #23480)
+ // Return the macro span on its own to avoid weird diagnostic output. It is preferable to
+ // have an incomplete span than a completely nonsensical one.
+ if span_data.ctxt != end_data.ctxt {
+ if span_data.ctxt == SyntaxContext::empty() {
+ return end;
+ } else if end_data.ctxt == SyntaxContext::empty() {
+ return self;
+ }
+ // both span fall within a macro
+ // FIXME(estebank) check if it is the *same* macro
+ }
Span::new(
- cmp::min(span.lo, end.lo),
- cmp::max(span.hi, end.hi),
- // FIXME(jseyfried): self.ctxt should always equal end.ctxt here (c.f. issue #23480)
- if span.ctxt == SyntaxContext::empty() { end.ctxt } else { span.ctxt },
+ cmp::min(span_data.lo, end_data.lo),
+ cmp::max(span_data.hi, end_data.hi),
+ if span_data.ctxt == SyntaxContext::empty() { end_data.ctxt } else { span_data.ctxt },
)
}
StringMap<FunctionImporter::ImportMapTy> ImportLists;
StringMap<FunctionImporter::ExportSetTy> ExportLists;
StringMap<GVSummaryMapTy> ModuleToDefinedGVSummaries;
+
+#if LLVM_VERSION_GE(7, 0)
+ LLVMRustThinLTOData() : Index(/* isPerformingAnalysis = */ false) {}
+#endif
};
// Just an argument to the `LLVMRustCreateThinLTOData` function below.
//
// 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;
+ };
+ computeDeadSymbols(Ret->Index, Ret->GUIDPreservedSymbols, deadIsPrevailing);
+#else
computeDeadSymbols(Ret->Index, Ret->GUIDPreservedSymbols);
+#endif
ComputeCrossModuleImport(
Ret->Index,
Ret->ModuleToDefinedGVSummaries,
pub fn str(_: &[u8]) {
}
-// CHECK: @trait_borrow(%"core::ops::drop::Drop"* nonnull %arg0.0, {}* noalias nonnull readonly %arg0.1)
+// CHECK: @trait_borrow({}* nonnull %arg0.0, {}* noalias nonnull readonly %arg0.1)
// FIXME #25759 This should also have `nocapture`
#[no_mangle]
pub fn trait_borrow(_: &Drop) {
}
-// CHECK: @trait_box(%"core::ops::drop::Drop"* noalias nonnull, {}* noalias nonnull readonly)
+// CHECK: @trait_box({}* noalias nonnull, {}* noalias nonnull readonly)
#[no_mangle]
pub fn trait_box(_: Box<Drop>) {
}
// ignore-wasm
// ignore-emscripten
// ignore-windows
-// no-system-llvm
+// min-system-llvm-version 5.0
// compile-flags: -C no-prepopulate-passes
#![crate_type = "lib"]
trait Trait {
fn bar<'a,'b:'a>(x: &'a str, y: &'b str);
+ //~^ NOTE lifetimes in impl do not match this method in trait
}
struct Foo;
impl Trait for Foo {
fn bar<'a,'b>(x: &'a str, y: &'b str) { //~ ERROR E0195
- //~^ lifetimes do not match trait
+ //~^ NOTE lifetimes do not match method in trait
}
}
}
struct Abc;
+
impl Foo for Abc {
const X: EFoo = EFoo::B;
}
pub fn test<A: Foo, B: Foo>(arg: EFoo) {
match arg {
- A::X => println!("A::X"), //~ error: statics cannot be referenced in patterns [E0158]
- B::X => println!("B::X"), //~ error: statics cannot be referenced in patterns [E0158]
+ A::X => println!("A::X"),
+ //~^ error: associated consts cannot be referenced in patterns [E0158]
+ B::X => println!("B::X"),
+ //~^ error: associated consts cannot be referenced in patterns [E0158]
_ => (),
}
}
trait NoLifetime {
fn get<'p, T : Test<'p>>(&self) -> T;
+ //~^ NOTE lifetimes in impl do not match this method in trait
}
trait Test<'p> {
impl<'a> NoLifetime for Foo<'a> {
fn get<'p, T : Test<'a>>(&self) -> T {
-//~^ ERROR E0195
-//~| lifetimes do not match trait
+ //~^ ERROR E0195
+ //~| NOTE lifetimes do not match method in trait
return *self as T;
}
}
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that the 'static bound from the Copy impl is respected. Regression test for #29149.
+
+#![feature(nll)]
+
+#[derive(Clone)] struct Foo<'a>(&'a u32);
+impl Copy for Foo<'static> {}
+
+fn main() {
+ let s = 2;
+ let a = Foo(&s); //~ ERROR `s` does not live long enough [E0597]
+ drop(a);
+ drop(a);
+}
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Check that explicit region bounds are allowed on the various
-// nominal types (but not on other types) and that they are type
-// checked.
-
-struct Inv<'a> { // invariant w/r/t 'a
- x: &'a mut &'a isize
-}
-
-pub trait Foo<'a, 't> {
- fn no_bound<'b>(self, b: Inv<'b>);
- fn has_bound<'b:'a>(self, b: Inv<'b>);
- fn wrong_bound1<'b,'c,'d:'a+'b>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>);
- fn okay_bound<'b,'c,'d:'a+'b+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>);
- fn another_bound<'x: 'a>(self, x: Inv<'x>, y: Inv<'t>);
-}
-
-impl<'a, 't> Foo<'a, 't> for &'a isize {
- fn no_bound<'b:'a>(self, b: Inv<'b>) {
- //~^ ERROR lifetime parameters or bounds on method `no_bound` do not match
- }
-
- fn has_bound<'b>(self, b: Inv<'b>) {
- //~^ ERROR lifetime parameters or bounds on method `has_bound` do not match
- }
-
- fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
- //~^ ERROR method not compatible with trait
- //
- // Note: This is a terrible error message. It is caused
- // because, in the trait, 'b is early bound, and in the impl,
- // 'c is early bound, so -- after substitution -- the
- // lifetimes themselves look isomorphic. We fail because the
- // lifetimes that appear in the types are in the wrong
- // order. This should really be fixed by keeping more
- // information about the lifetime declarations in the trait so
- // that we can compare better to the impl, even in cross-crate
- // cases.
- }
-
- fn okay_bound<'b,'c,'e:'b+'c>(self, b: Inv<'b>, c: Inv<'c>, e: Inv<'e>) {
- }
-
- fn another_bound<'x: 't>(self, x: Inv<'x>, y: Inv<'t>) {
- //~^ ERROR E0276
- }
-}
-
-fn main() { }
fn main() {
// these literals are just silly.
''';
- //~^ ERROR: character constant must be escaped: \'
+ //~^ ERROR: character constant must be escaped: '
// note that this is a literal "\n" byte
'
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z parse-only
+
+\ //~ ERROR: unknown start of token: \
--- /dev/null
+-include ../tools.mk
+
+all:
+ cp non-utf8 $(TMPDIR)/non-utf.rs
+ cat $(TMPDIR)/non-utf.rs | $(RUSTC) - 2>&1 \
+ | $(CGREP) "error: couldn't read from stdin, as it did not contain valid UTF-8"
--- /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(generators)]
+
+fn main() {
+ unsafe {
+ static move || {
+ // Tests that the generator transformation finds out that `a` is not live
+ // during the yield expression. Type checking will also compute liveness
+ // and it should also find out that `a` is not live.
+ // The compiler will panic if the generator transformation finds that
+ // `a` is live and type checking finds it dead.
+ let a = {
+ yield ();
+ 4i32
+ };
+ &a;
+ };
+ }
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Regression test for issue #47139:
+//
+// Coherence was encountering an (unnecessary) overflow trying to
+// decide if the two impls of dummy overlap.
+//
+// The overflow went something like:
+//
+// - `&'a ?T: Insertable` ?
+// - let ?T = Option<?U> ?
+// - `Option<?U>: Insertable` ?
+// - `Option<&'a ?U>: Insertable` ?
+// - `&'a ?U: Insertable` ?
+//
+// While somewhere in the middle, a projection would occur, which
+// broke cycle detection.
+//
+// It turned out that this cycle was being kicked off due to some
+// extended diagnostic attempts in coherence, so removing those
+// sidestepped the issue for now.
+
+#![allow(dead_code)]
+
+pub trait Insertable {
+ type Values;
+
+ fn values(self) -> Self::Values;
+}
+
+impl<T> Insertable for Option<T>
+ where
+ T: Insertable,
+ T::Values: Default,
+{
+ type Values = T::Values;
+
+ fn values(self) -> Self::Values {
+ self.map(Insertable::values).unwrap_or_default()
+ }
+}
+
+impl<'a, T> Insertable for &'a Option<T>
+ where
+ Option<&'a T>: Insertable,
+{
+ type Values = <Option<&'a T> as Insertable>::Values;
+
+ fn values(self) -> Self::Values {
+ self.as_ref().values()
+ }
+}
+
+impl<'a, T> Insertable for &'a [T]
+{
+ type Values = Self;
+
+ fn values(self) -> Self::Values {
+ self
+ }
+}
+
+trait Unimplemented { }
+
+trait Dummy { }
+
+struct Foo<T> { t: T }
+
+impl<'a, U> Dummy for Foo<&'a U>
+ where &'a U: Insertable
+{
+}
+
+impl<T> Dummy for T
+ where T: Unimplemented
+{ }
+
+fn main() {
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Regression test for issue #47139:
+//
+// Same as issue-47139-1.rs, but the impls of dummy are in the
+// opposite order. This influenced the way that coherence ran and in
+// some cases caused the overflow to occur when it wouldn't otherwise.
+// In an effort to make the regr test more robust, I am including both
+// orderings.
+
+#![allow(dead_code)]
+
+pub trait Insertable {
+ type Values;
+
+ fn values(self) -> Self::Values;
+}
+
+impl<T> Insertable for Option<T>
+ where
+ T: Insertable,
+ T::Values: Default,
+{
+ type Values = T::Values;
+
+ fn values(self) -> Self::Values {
+ self.map(Insertable::values).unwrap_or_default()
+ }
+}
+
+impl<'a, T> Insertable for &'a Option<T>
+ where
+ Option<&'a T>: Insertable,
+{
+ type Values = <Option<&'a T> as Insertable>::Values;
+
+ fn values(self) -> Self::Values {
+ self.as_ref().values()
+ }
+}
+
+impl<'a, T> Insertable for &'a [T]
+{
+ type Values = Self;
+
+ fn values(self) -> Self::Values {
+ self
+ }
+}
+
+trait Unimplemented { }
+
+trait Dummy { }
+
+struct Foo<T> { t: T }
+
+impl<T> Dummy for T
+ where T: Unimplemented
+{ }
+
+impl<'a, U> Dummy for Foo<&'a U>
+ where &'a U: Insertable
+{
+}
+
+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.
+
+fn id<'c, 'b>(f: &'c &'b Fn(&i32)) -> &'c &'b Fn(&'static i32) {
+ f
+}
+
+fn main() {
+ let f: &Fn(&i32) = &|x| {};
+ id(&f);
+}
--- /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(nll)]
+
+static mut x: &'static u32 = &0;
+
+fn foo() {
+ unsafe { x = &1; }
+}
+
+fn main() { }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// min-llvm-version 4.0
+// no-system-llvm -- needs MCSubtargetInfo::getFeatureTable()
// ignore-cloudabi no std::env
#![feature(cfg_target_feature)]
// ignore-emscripten no processes
// ignore-musl FIXME #31506
// ignore-pretty
-// no-system-llvm
+// min-system-llvm-version 5.0
// compile-flags: -C lto
// no-prefer-dynamic
// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-musl FIXME #31506
-// no-system-llvm
+// min-system-llvm-version 5.0
use std::mem;
use std::process::Command;
--- /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.
+
+// Just check if we don't get an ICE for the _S type.
+
+#![feature(const_size_of)]
+
+use std::cell::Cell;
+use std::mem;
+
+pub struct S {
+ s: Cell<usize>
+}
+
+pub type _S = [usize; 0 - (mem::size_of::<S>() != 4) as usize];
note: the lifetime 'a as defined on the impl at 17:1...
--> $DIR/associated-const-impl-wrong-lifetime.rs:17:1
|
-17 | / impl<'a> Foo for &'a () {
-18 | | const NAME: &'a str = "unit";
-19 | | //~^ ERROR mismatched types [E0308]
-20 | | }
- | |_^
+17 | impl<'a> Foo for &'a () {
+ | ^^^^^^^^^^^^^^^^^^^^^^^
= note: ...does not necessarily outlive the static lifetime
error: aborting due to previous error
= note: `foo` must be defined only once in the type namespace of this module
help: You can use `as` to change the binding name of the import
|
-13 | use foo::foo as Otherfoo;
- | ^^^^^^^^^^^^^^^^^^^^
+13 | use foo::foo as other_foo;
+ | ^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that explicit region bounds are allowed on the various
+// nominal types (but not on other types) and that they are type
+// checked.
+
+struct Inv<'a> { // invariant w/r/t 'a
+ x: &'a mut &'a isize
+}
+
+pub trait Foo<'a, 't> {
+ fn no_bound<'b>(self, b: Inv<'b>);
+ fn has_bound<'b:'a>(self, b: Inv<'b>);
+ fn wrong_bound1<'b,'c,'d:'a+'b>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>);
+ fn okay_bound<'b,'c,'d:'a+'b+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>);
+ fn another_bound<'x: 'a>(self, x: Inv<'x>, y: Inv<'t>);
+}
+
+impl<'a, 't> Foo<'a, 't> for &'a isize {
+ fn no_bound<'b:'a>(self, b: Inv<'b>) {
+ //~^ ERROR lifetime parameters or bounds on method `no_bound` do not match
+ }
+
+ fn has_bound<'b>(self, b: Inv<'b>) {
+ //~^ ERROR lifetime parameters or bounds on method `has_bound` do not match
+ }
+
+ fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
+ //~^ ERROR method not compatible with trait
+ //
+ // Note: This is a terrible error message. It is caused
+ // because, in the trait, 'b is early bound, and in the impl,
+ // 'c is early bound, so -- after substitution -- the
+ // lifetimes themselves look isomorphic. We fail because the
+ // lifetimes that appear in the types are in the wrong
+ // order. This should really be fixed by keeping more
+ // information about the lifetime declarations in the trait so
+ // that we can compare better to the impl, even in cross-crate
+ // cases.
+ }
+
+ fn okay_bound<'b,'c,'e:'b+'c>(self, b: Inv<'b>, c: Inv<'c>, e: Inv<'e>) {
+ }
+
+ fn another_bound<'x: 't>(self, x: Inv<'x>, y: Inv<'t>) {
+ //~^ ERROR E0276
+ }
+}
+
+fn main() { }
--- /dev/null
+error[E0195]: lifetime parameters or bounds on method `no_bound` do not match the trait declaration
+ --> $DIR/regions-bound-missing-bound-in-impl.rs:28:5
+ |
+20 | fn no_bound<'b>(self, b: Inv<'b>);
+ | ---------------------------------- lifetimes in impl do not match this method in trait
+...
+28 | fn no_bound<'b:'a>(self, b: Inv<'b>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetimes do not match method in trait
+
+error[E0195]: lifetime parameters or bounds on method `has_bound` do not match the trait declaration
+ --> $DIR/regions-bound-missing-bound-in-impl.rs:32:5
+ |
+21 | fn has_bound<'b:'a>(self, b: Inv<'b>);
+ | -------------------------------------- lifetimes in impl do not match this method in trait
+...
+32 | fn has_bound<'b>(self, b: Inv<'b>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetimes do not match method in trait
+
+error[E0308]: method not compatible with trait
+ --> $DIR/regions-bound-missing-bound-in-impl.rs:36:5
+ |
+36 | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
+ |
+ = note: expected type `fn(&'a isize, Inv<'c>, Inv<'c>, Inv<'d>)`
+ found type `fn(&'a isize, Inv<'_>, Inv<'c>, Inv<'d>)`
+note: the lifetime 'c as defined on the method body at 36:5...
+ --> $DIR/regions-bound-missing-bound-in-impl.rs:36:5
+ |
+36 | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...does not necessarily outlive the lifetime 'c as defined on the method body at 36:5
+ --> $DIR/regions-bound-missing-bound-in-impl.rs:36:5
+ |
+36 | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0276]: impl has stricter requirements than trait
+ --> $DIR/regions-bound-missing-bound-in-impl.rs:53:5
+ |
+24 | fn another_bound<'x: 'a>(self, x: Inv<'x>, y: Inv<'t>);
+ | ------------------------------------------------------- definition of `another_bound` from trait
+...
+53 | fn another_bound<'x: 't>(self, x: Inv<'x>, y: Inv<'t>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `'x: 't`
+
+error: aborting due to 4 previous errors
+
note: ...does not necessarily outlive the lifetime 'x as defined on the function body at 42:1
--> $DIR/expect-region-supply-region.rs:42:1
|
-42 | / fn expect_bound_supply_named<'x>() {
-43 | | let mut f: Option<&u32> = None;
-44 | |
-45 | | // Here we give a type annotation that `x` should be free. We get
-... |
-54 | | });
-55 | | }
- | |_^
+42 | fn expect_bound_supply_named<'x>() {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0308]: mismatched types
--> $DIR/expect-region-supply-region.rs:47:33
note: the lifetime 'x as defined on the function body at 42:1...
--> $DIR/expect-region-supply-region.rs:42:1
|
-42 | / fn expect_bound_supply_named<'x>() {
-43 | | let mut f: Option<&u32> = None;
-44 | |
-45 | | // Here we give a type annotation that `x` should be free. We get
-... |
-54 | | });
-55 | | }
- | |_^
+42 | fn expect_bound_supply_named<'x>() {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 47:29
--> $DIR/expect-region-supply-region.rs:47:29
|
= note: `foo` must be defined only once in the value namespace of this module
help: You can use `as` to change the binding name of the import
|
-23 | use sub2::foo as Otherfoo; //~ ERROR the name `foo` is defined multiple times
- | ^^^^^^^^^^^^^^^^^^^^^
+23 | use sub2::foo as other_foo; //~ ERROR the name `foo` is defined multiple times
+ | ^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
-error[E0626]: borrow may still be in use when generator yields (Mir)
- --> $DIR/generator-with-nll.rs:20:17
- |
-20 | let b = &mut true; //~ ERROR borrow may still be in use when generator yields (Ast)
- | ^^^^^^^^^
-21 | //~^ borrow may still be in use when generator yields (Mir)
-22 | yield ();
- | -------- possible yield occurs here
-
error[E0626]: borrow may still be in use when generator yields (Ast)
--> $DIR/generator-with-nll.rs:19:23
|
22 | yield ();
| -------- possible yield occurs here
+error[E0626]: borrow may still be in use when generator yields (Mir)
+ --> $DIR/generator-with-nll.rs:20:17
+ |
+20 | let b = &mut true; //~ ERROR borrow may still be in use when generator yields (Ast)
+ | ^^^^^^^^^
+21 | //~^ borrow may still be in use when generator yields (Mir)
+22 | yield ();
+ | -------- possible yield occurs here
+
error: aborting due to 3 previous errors
--- /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(generators)]
+
+enum Test { A(i32), B, }
+
+fn main() { }
+
+fn fun(test: Test) {
+ move || {
+ if let Test::A(ref _a) = test { //~ ERROR borrow may still be in use when generator yields
+ yield ();
+ }
+ };
+}
--- /dev/null
+error[E0626]: borrow may still be in use when generator yields
+ --> $DIR/pattern-borrow.rs:19:24
+ |
+19 | if let Test::A(ref _a) = test { //~ ERROR borrow may still be in use when generator yields
+ | ^^^^^^
+20 | yield ();
+ | -------- possible yield occurs here
+
+error: aborting due to previous error
+
--- /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(generators, generator_trait)]
+
+use std::ops::Generator;
+
+fn main() {
+ let s = String::from("foo");
+ let mut gen = move || { //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied
+ yield s[..];
+ };
+ gen.resume(); //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied
+}
--- /dev/null
+error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied
+ --> $DIR/sized-yield.rs:17:26
+ |
+17 | let mut gen = move || { //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied
+ | __________________________^
+18 | | yield s[..];
+19 | | };
+ | |____^ `str` does not have a constant size known at compile-time
+ |
+ = help: the trait `std::marker::Sized` is not implemented for `str`
+ = note: the yield type of a generator must have a statically known size
+
+error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied
+ --> $DIR/sized-yield.rs:20:8
+ |
+20 | gen.resume(); //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied
+ | ^^^^^^ `str` does not have a constant size known at compile-time
+ |
+ = help: the trait `std::marker::Sized` is not implemented for `str`
+
+error: aborting due to 2 previous errors
+
-error[E0626]: borrow may still be in use when generator yields (Mir)
- --> $DIR/yield-while-local-borrowed.rs:24:17
- |
-24 | let a = &mut 3;
- | ^^^^^^
-...
-27 | yield();
- | ------- possible yield occurs here
-
error[E0626]: borrow may still be in use when generator yields (Ast)
--> $DIR/yield-while-local-borrowed.rs:24:22
|
55 | yield();
| ------- possible yield occurs here
+error[E0626]: borrow may still be in use when generator yields (Mir)
+ --> $DIR/yield-while-local-borrowed.rs:24:17
+ |
+24 | let a = &mut 3;
+ | ^^^^^^
+...
+27 | yield();
+ | ------- possible yield occurs here
+
error[E0626]: borrow may still be in use when generator yields (Mir)
--> $DIR/yield-while-local-borrowed.rs:52:21
|
--> $DIR/trait_type.rs:17:4
|
17 | fn fmt(&self, x: &str) -> () { }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability
|
= note: expected type `fn(&MyType, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>`
found type `fn(&MyType, &str)`
--> $DIR/trait_type.rs:27:4
|
27 | fn fmt() -> () { }
- | ^^^^^^^^^^^^^^^^^^ expected `&self` in impl
+ | ^^^^^^^^^^^^^^ expected `&self` in impl
|
= note: `fmt` from trait: `fn(&Self, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>`
= note: `foo` must be defined only once in the value namespace of this module
help: You can use `as` to change the binding name of the import
|
-25 | use a::foo as Otherfoo; //~ ERROR the name `foo` is defined multiple times
- | ^^^^^^^^^^^^^^^^^^
+25 | use a::foo as other_foo; //~ ERROR the name `foo` is defined multiple times
+ | ^^^^^^^^^^^^^^^^^^^
error[E0659]: `foo` is ambiguous
--> $DIR/duplicate.rs:56:9
--- /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(warnings)]
+#![allow(unused_variables, dead_code, unused, bad_style)]
+#![deny(elided_lifetime_in_path)]
+
+struct Foo<'a> { x: &'a u32 }
+fn foo(x: &Foo) {
+ //~^ ERROR: hidden lifetime parameters are deprecated, try `Foo<'_>`
+}
+
+fn main() {}
--- /dev/null
+error: hidden lifetime parameters are deprecated, try `Foo<'_>`
+ --> $DIR/ellided-lifetimes.rs:15:12
+ |
+15 | fn foo(x: &Foo) {
+ | ^^^
+ |
+note: lint level defined here
+ --> $DIR/ellided-lifetimes.rs:12:9
+ |
+12 | #![deny(elided_lifetime_in_path)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /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 std::ops::Deref;
+trait Trait {}
+
+struct Struct;
+
+impl Deref for Struct {
+ type Target = Trait;
+ fn deref(&self) -> &Trait {
+ unimplemented!();
+ }
+}
+//~^^^^ ERROR cannot infer an appropriate lifetime for lifetime parameter
--- /dev/null
+error[E0601]: main function not found
+
+error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in generic type due to conflicting requirements
+ --> $DIR/mismatched_trait_impl-2.rs:18:5
+ |
+18 | fn deref(&self) -> &Trait {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 18:5...
+ --> $DIR/mismatched_trait_impl-2.rs:18:5
+ |
+18 | / fn deref(&self) -> &Trait {
+19 | | unimplemented!();
+20 | | }
+ | |_____^
+ = note: ...but the lifetime must also be valid for the static lifetime...
+ = note: ...so that the method type is compatible with trait:
+ expected fn(&Struct) -> &Trait + 'static
+ found fn(&Struct) -> &Trait
+
+error: aborting due to 2 previous errors
+
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter 'a in generic type due to conflicting requirements
--> $DIR/mismatched_trait_impl.rs:19:5
|
-19 | / fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { //~ ERROR cannot infer
-20 | | x
-21 | | }
- | |_____^
+19 | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { //~ ERROR cannot infer
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the method body at 19:5...
--> $DIR/mismatched_trait_impl.rs:19:5
20 | | x
21 | | }
| |_____^
-note: ...so that method type is compatible with trait (expected fn(&i32, &'a u32, &u32) -> &'a u32, found fn(&i32, &u32, &u32) -> &u32)
- --> $DIR/mismatched_trait_impl.rs:19:5
- |
-19 | / fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { //~ ERROR cannot infer
-20 | | x
-21 | | }
- | |_____^
-note: but, the lifetime must be valid for the lifetime 'a as defined on the method body at 19:5...
+note: ...but the lifetime must also be valid for the lifetime 'a as defined on the method body at 19:5...
--> $DIR/mismatched_trait_impl.rs:19:5
|
-19 | / fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { //~ ERROR cannot infer
-20 | | x
-21 | | }
- | |_____^
-note: ...so that method type is compatible with trait (expected fn(&i32, &'a u32, &u32) -> &'a u32, found fn(&i32, &u32, &u32) -> &u32)
- --> $DIR/mismatched_trait_impl.rs:19:5
- |
-19 | / fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { //~ ERROR cannot infer
-20 | | x
-21 | | }
- | |_____^
+19 | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { //~ ERROR cannot infer
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: ...so that the method type is compatible with trait:
+ expected fn(&i32, &'a u32, &u32) -> &'a u32
+ found fn(&i32, &u32, &u32) -> &u32
error: aborting due to previous error
= note: `sync` must be defined only once in the type namespace of this module
help: You can use `as` to change the binding name of the import
|
-14 | use std::sync as Othersync; //~ ERROR the name `sync` is defined multiple times
- | ^^^^^^^^^^^^^^^^^^^^^^
+14 | use std::sync as other_sync; //~ ERROR the name `sync` is defined multiple times
+ | ^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
note: ...does not necessarily outlive the lifetime 'a as defined on the trait at 13:1
--> $DIR/issue-27942.rs:13:1
|
-13 | / pub trait Buffer<'a, R: Resources<'a>> {
-14 | |
-15 | | fn select(&self) -> BufferViewHandle<R>;
-16 | | //~^ ERROR mismatched types
-... |
-19 | | //~| lifetime mismatch
-20 | | }
- | |_^
+13 | pub trait Buffer<'a, R: Resources<'a>> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0308]: mismatched types
--> $DIR/issue-27942.rs:15:5
note: the lifetime 'a as defined on the trait at 13:1...
--> $DIR/issue-27942.rs:13:1
|
-13 | / pub trait Buffer<'a, R: Resources<'a>> {
-14 | |
-15 | | fn select(&self) -> BufferViewHandle<R>;
-16 | | //~^ ERROR mismatched types
-... |
-19 | | //~| lifetime mismatch
-20 | | }
- | |_^
+13 | pub trait Buffer<'a, R: Resources<'a>> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...does not necessarily outlive the anonymous lifetime #1 defined on the method body at 15:5
--> $DIR/issue-27942.rs:15:5
|
note: ...does not necessarily outlive the lifetime 'a as defined on the impl at 13:1
--> $DIR/issue-37884.rs:13:1
|
-13 | / impl<'a, T: 'a> Iterator for RepeatMut<'a, T> {
-14 | |
-15 | | type Item = &'a mut T;
-16 | | fn next(&'a mut self) -> Option<Self::Item>
-... |
-21 | | }
-22 | | }
- | |_^
+13 | impl<'a, T: 'a> Iterator for RepeatMut<'a, T> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 13:1...
--> $DIR/issue-46472.rs:13:1
|
-13 | / fn bar<'a>() -> &'a mut u32 {
-14 | | &mut 4
-15 | | //~^ ERROR borrowed value does not live long enough (Ast) [E0597]
-16 | | //~| ERROR borrowed value does not live long enough (Mir) [E0597]
-17 | | }
- | |_^
+13 | fn bar<'a>() -> &'a mut u32 {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0597]: borrowed value does not live long enough (Mir)
--> $DIR/issue-46472.rs:14:10
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 13:1...
--> $DIR/issue-46472.rs:13:1
|
-13 | / fn bar<'a>() -> &'a mut u32 {
-14 | | &mut 4
-15 | | //~^ ERROR borrowed value does not live long enough (Ast) [E0597]
-16 | | //~| ERROR borrowed value does not live long enough (Mir) [E0597]
-17 | | }
- | |_^
+13 | fn bar<'a>() -> &'a mut u32 {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
--- /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 T {
+ fn f(&self, _: ()) {
+ None::<()>.map(Self::f);
+ }
+ //~^^ ERROR function is expected to take a single 0-tuple as argument
+}
--- /dev/null
+error[E0601]: main function not found
+
+error[E0593]: function is expected to take a single 0-tuple as argument, but it takes 2 distinct arguments
+ --> $DIR/issue-47706-trait.rs:13:20
+ |
+12 | fn f(&self, _: ()) {
+ | ------------------ takes 2 distinct arguments
+13 | None::<()>.map(Self::f);
+ | ^^^ expected function that takes a single 0-tuple as argument
+
+error: aborting due to 2 previous errors
+
--- /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.
+
+// must-compile-successfully
+
+#![warn(unused_parens)]
+
+macro_rules! the_worship_the_heart_lifts_above {
+ ( @as_expr, $e:expr) => { $e };
+ ( @generate_fn, $name:tt) => {
+ #[allow(dead_code)] fn the_moth_for_the_star<'a>() -> Option<&'a str> {
+ Some(the_worship_the_heart_lifts_above!( @as_expr, $name ))
+ }
+ };
+ ( $name:ident ) => { the_worship_the_heart_lifts_above!( @generate_fn, (stringify!($name))); }
+ // ↑ Notably, this does 𝘯𝘰𝘵 warn: we're declining to lint unused parens in
+ // function/method arguments inside of nested macros because of situations
+ // like those reported in Issue #47775
+}
+
+macro_rules! and_the_heavens_reject_not {
+ () => {
+ // ↓ But let's test that we still lint for unused parens around
+ // function args inside of simple, one-deep macros.
+ #[allow(dead_code)] fn the_night_for_the_morrow() -> Option<isize> { Some((2)) }
+ //~^ WARN unnecessary parentheses around function argument
+ }
+}
+
+the_worship_the_heart_lifts_above!(rah);
+and_the_heavens_reject_not!();
+
+fn main() {}
--- /dev/null
+warning: unnecessary parentheses around function argument
+ --> $DIR/issue-47775-nested-macro-unnecessary-parens-arg.rs:32:83
+ |
+32 | #[allow(dead_code)] fn the_night_for_the_morrow() -> Option<isize> { Some((2)) }
+ | ^^^ help: remove these parentheses
+...
+38 | and_the_heavens_reject_not!();
+ | ------------------------------ in this macro invocation
+ |
+note: lint level defined here
+ --> $DIR/issue-47775-nested-macro-unnecessary-parens-arg.rs:13:9
+ |
+13 | #![warn(unused_parens)]
+ | ^^^^^^^^^^^^^
+
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-tidy-tab
+
#![warn(unused_mut, unused_parens)] // UI tests pass `-A unused`—see Issue #43896
#![feature(no_debug)]
let mut a = (1); // should suggest no `mut`, no parens
//~^ WARN does not need to be mutable
//~| WARN unnecessary parentheses
+ // the line after `mut` has a `\t` at the beginning, this is on purpose
+ let mut
+ b = 1;
+ //~^^ WARN does not need to be mutable
let d = Equinox { warp_factor: 9.975 };
match d {
Equinox { warp_factor: warp_factor } => {} // should suggest shorthand
//~^ WARN this pattern is redundant
}
- println!("{}", a);
+ println!("{} {}", a, b);
}
}
warning: unnecessary parentheses around assigned value
- --> $DIR/suggestions.rs:46:21
+ --> $DIR/suggestions.rs:48:21
|
-46 | let mut a = (1); // should suggest no `mut`, no parens
+48 | let mut a = (1); // should suggest no `mut`, no parens
| ^^^ help: remove these parentheses
|
note: lint level defined here
- --> $DIR/suggestions.rs:11:21
+ --> $DIR/suggestions.rs:13:21
|
-11 | #![warn(unused_mut, unused_parens)] // UI tests pass `-A unused`—see Issue #43896
+13 | #![warn(unused_mut, unused_parens)] // UI tests pass `-A unused`—see Issue #43896
| ^^^^^^^^^^^^^
warning: use of deprecated attribute `no_debug`: the `#[no_debug]` attribute was an experimental feature that has been deprecated due to lack of demand. See https://github.com/rust-lang/rust/issues/29721
- --> $DIR/suggestions.rs:41:1
+ --> $DIR/suggestions.rs:43:1
|
-41 | #[no_debug] // should suggest removal of deprecated attribute
+43 | #[no_debug] // should suggest removal of deprecated attribute
| ^^^^^^^^^^^ help: remove this attribute
|
= note: #[warn(deprecated)] on by default
warning: variable does not need to be mutable
- --> $DIR/suggestions.rs:46:13
+ --> $DIR/suggestions.rs:48:13
|
-46 | let mut a = (1); // should suggest no `mut`, no parens
- | ---^^
+48 | let mut a = (1); // should suggest no `mut`, no parens
+ | ----^
| |
| help: remove this `mut`
|
note: lint level defined here
- --> $DIR/suggestions.rs:11:9
+ --> $DIR/suggestions.rs:13:9
|
-11 | #![warn(unused_mut, unused_parens)] // UI tests pass `-A unused`—see Issue #43896
+13 | #![warn(unused_mut, unused_parens)] // UI tests pass `-A unused`—see Issue #43896
| ^^^^^^^^^^
+warning: variable does not need to be mutable
+ --> $DIR/suggestions.rs:52:13
+ |
+52 | let mut
+ | _____________^
+ | |_____________|
+ | ||
+53 | || b = 1;
+ | ||____________-^
+ | |____________|
+ | help: remove this `mut`
+
warning: static is marked #[no_mangle], but not exported
- --> $DIR/suggestions.rs:14:14
+ --> $DIR/suggestions.rs:16:14
|
-14 | #[no_mangle] static SHENZHOU: usize = 1; // should suggest `pub`
+16 | #[no_mangle] static SHENZHOU: usize = 1; // should suggest `pub`
| -^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| help: try making it public: `pub`
= note: #[warn(private_no_mangle_statics)] on by default
error: const items should never be #[no_mangle]
- --> $DIR/suggestions.rs:16:14
+ --> $DIR/suggestions.rs:18:14
|
-16 | #[no_mangle] const DISCOVERY: usize = 1; // should suggest `pub static` rather than `const`
+18 | #[no_mangle] const DISCOVERY: usize = 1; // should suggest `pub static` rather than `const`
| -----^^^^^^^^^^^^^^^^^^^^^^
| |
| help: try a static value: `pub static`
= note: #[deny(no_mangle_const_items)] on by default
warning: functions generic over types must be mangled
- --> $DIR/suggestions.rs:20:1
+ --> $DIR/suggestions.rs:22:1
|
-19 | #[no_mangle] // should suggest removal (generics can't be no-mangle)
+21 | #[no_mangle] // should suggest removal (generics can't be no-mangle)
| ------------ help: remove this attribute
-20 | pub fn defiant<T>(_t: T) {}
+22 | pub fn defiant<T>(_t: T) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: #[warn(no_mangle_generic_items)] on by default
warning: function is marked #[no_mangle], but not exported
- --> $DIR/suggestions.rs:24:1
+ --> $DIR/suggestions.rs:26:1
|
-24 | fn rio_grande() {} // should suggest `pub`
+26 | fn rio_grande() {} // should suggest `pub`
| -^^^^^^^^^^^^^^^^^
| |
| help: try making it public: `pub`
= note: #[warn(private_no_mangle_fns)] on by default
warning: static is marked #[no_mangle], but not exported
- --> $DIR/suggestions.rs:31:18
+ --> $DIR/suggestions.rs:33:18
|
-31 | #[no_mangle] pub static DAUNTLESS: bool = true;
+33 | #[no_mangle] pub static DAUNTLESS: bool = true;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: function is marked #[no_mangle], but not exported
- --> $DIR/suggestions.rs:33:18
+ --> $DIR/suggestions.rs:35:18
|
-33 | #[no_mangle] pub fn val_jean() {}
+35 | #[no_mangle] pub fn val_jean() {}
| ^^^^^^^^^^^^^^^^^^^^
warning: denote infinite loops with `loop { ... }`
- --> $DIR/suggestions.rs:44:5
+ --> $DIR/suggestions.rs:46:5
|
-44 | while true { // should suggest `loop`
+46 | while true { // should suggest `loop`
| ^^^^^^^^^^ help: use `loop`
|
= note: #[warn(while_true)] on by default
warning: the `warp_factor:` in this pattern is redundant
- --> $DIR/suggestions.rs:51:23
+ --> $DIR/suggestions.rs:57:23
|
-51 | Equinox { warp_factor: warp_factor } => {} // should suggest shorthand
+57 | Equinox { warp_factor: warp_factor } => {} // should suggest shorthand
| ------------^^^^^^^^^^^^
| |
| help: remove this
|
22 | break 22 //~ ERROR `break` with value from a `for` loop
| ^^^^^^^^ can only break with a value inside `loop`
+help: instead, use `break` on its own without a value inside this `for` loop
+ |
+22 | break //~ ERROR `break` with value from a `for` loop
+ | ^^^^^
error: aborting due to previous error
--- /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.
+
+macro_rules! bad {
+ ($s:ident whatever) => {
+ {
+ let $s = 0;
+ *&mut $s = 0;
+ //~^ ERROR cannot borrow immutable local variable `foo` as mutable [E0596]
+ }
+ }
+}
+
+fn main() {
+ bad!(foo whatever);
+}
--- /dev/null
+error[E0596]: cannot borrow immutable local variable `foo` as mutable
+ --> $DIR/span-covering-argument-1.rs:15:19
+ |
+14 | let $s = 0;
+ | -- consider changing this to `mut $s`
+15 | *&mut $s = 0;
+ | ^^ cannot borrow mutably
+...
+22 | bad!(foo whatever);
+ | ------------------- in this macro invocation
+
+error: aborting due to previous error
+
= note: `transmute` must be defined only once in the value namespace of this module
help: You can use `as` to change the binding name of the import
|
-11 | use std::mem::transmute as Othertransmute;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+11 | use std::mem::transmute as other_transmute;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
warning: struct is never used: `S`
- --> $DIR/macro-span-replacement.rs:17:9
+ --> $DIR/macro-span-replacement.rs:17:14
|
17 | $b $a; //~ WARN struct is never used
- | ^^^^^^
+ | ^
...
22 | m!(S struct);
| ------------- in this macro invocation
--> $DIR/static-lifetime.rs:13:1
|
13 | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {} //~ ERROR lifetime bound
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: but lifetime parameter must outlive the static lifetime
error: aborting due to previous error
= note: `std` must be defined only once in the type namespace of this module
help: You can use `as` to change the binding name of the import
|
-11 | extern crate std as Otherstd;
+11 | extern crate std as other_std;
|
error: aborting due to previous error
= note: `bar` must be defined only once in the type namespace of this module
help: You can use `as` to change the binding name of the import
|
-15 | self as Otherbar
+15 | self as other_bar
|
error: aborting due to 3 previous errors
.expect("Malformed llvm version directive");
// Ignore if using system LLVM and actual version
// is smaller the minimum required version
- !(config.system_llvm && &actual_version[..] < min_version)
+ config.system_llvm && &actual_version[..] < min_version
} else {
false
}
-Subproject commit 511321ae1c2fa3f0e334885fecf406dd6c882836
+Subproject commit dee42bda8156a28ead609080e27b02173bb9c29e
-Subproject commit e0e3e22248cd14ebbe0253e9720261a0328bfc59
+Subproject commit 346238f49740d6c98102a6a59811b1625c73a9d7