From c95be3d033a72880749813ae0bfc7067437f9c19 Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Thu, 16 May 2019 14:32:28 -0400 Subject: [PATCH 01/11] strip synstructure consts from compiler docs --- Cargo.lock | 8 ++++---- src/bootstrap/doc.rs | 2 +- src/librustc_macros/Cargo.toml | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4417c25abcb4e..6efce4297dcd2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -835,7 +835,7 @@ dependencies = [ "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2849,7 +2849,7 @@ dependencies = [ "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3385,7 +3385,7 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4306,7 +4306,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)" = "ae8b29eb5210bc5cf63ed6149cbf9adfc82ac0be023d8735c176ee74a2db4da7" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" -"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" +"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" "checksum tar 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)" = "a303ba60a099fcd2aaa646b14d2724591a96a75283e4b7ed3d1a1658909d9ae2" "checksum tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7e91405c14320e5c79b3d148e1c86f40749a36e490642202a31689cb1a3452b2" "checksum tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9de21546595a0873061940d994bbbc5c35f024ae4fd61ec5c5b159115684f508" diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 9c3a17bff6b7a..5605ec34083be 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -728,7 +728,7 @@ impl Step for Rustc { // Build cargo command. let mut cargo = builder.cargo(compiler, Mode::Rustc, target, "doc"); - cargo.env("RUSTDOCFLAGS", "--document-private-items"); + cargo.env("RUSTDOCFLAGS", "--document-private-items --passes strip-hidden"); compile::rustc_cargo(builder, &mut cargo); // Only include compiler crates, no dependencies of those, such as `libc`. diff --git a/src/librustc_macros/Cargo.toml b/src/librustc_macros/Cargo.toml index 6e32a53c364a6..f989ebc6dfd8e 100644 --- a/src/librustc_macros/Cargo.toml +++ b/src/librustc_macros/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" proc-macro = true [dependencies] -synstructure = "0.10.1" +synstructure = "0.10.2" syn = { version = "0.15.22", features = ["full"] } proc-macro2 = "0.4.24" quote = "0.6.10" From 89d437ec76cab8153ada936c5d67ef2deb901eb4 Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Sat, 4 May 2019 15:37:12 -0400 Subject: [PATCH 02/11] do not print panic message on doctest failures --- src/librustdoc/test.rs | 139 ++++++++++++++---- .../rustdoc-ui/failed-doctest-compile-fail.rs | 11 ++ .../failed-doctest-compile-fail.stdout | 14 ++ .../failed-doctest-missing-codes.rs | 11 ++ .../failed-doctest-missing-codes.stdout | 26 ++++ src/test/rustdoc-ui/failed-doctest-output.rs | 5 +- .../rustdoc-ui/failed-doctest-output.stdout | 32 ++-- .../rustdoc-ui/failed-doctest-should-panic.rs | 11 ++ .../failed-doctest-should-panic.stdout | 14 ++ .../rustdoc-ui/unparseable-doc-test.stdout | 4 +- 10 files changed, 224 insertions(+), 43 deletions(-) create mode 100644 src/test/rustdoc-ui/failed-doctest-compile-fail.rs create mode 100644 src/test/rustdoc-ui/failed-doctest-compile-fail.stdout create mode 100644 src/test/rustdoc-ui/failed-doctest-missing-codes.rs create mode 100644 src/test/rustdoc-ui/failed-doctest-missing-codes.stdout create mode 100644 src/test/rustdoc-ui/failed-doctest-should-panic.rs create mode 100644 src/test/rustdoc-ui/failed-doctest-should-panic.stdout diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index d76d4380755f2..9d1a0cc074c88 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -17,7 +17,7 @@ use std::io::prelude::*; use std::io; use std::panic::{self, AssertUnwindSafe}; use std::path::PathBuf; -use std::process::Command; +use std::process::{self, Command}; use std::str; use std::sync::{Arc, Mutex}; use syntax::symbol::sym; @@ -160,13 +160,45 @@ fn scrape_test_config(krate: &::rustc::hir::Crate) -> TestOptions { opts } -fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize, - cfgs: Vec, libs: Vec, - cg: CodegenOptions, externs: Externs, - should_panic: bool, no_run: bool, as_test_harness: bool, - compile_fail: bool, mut error_codes: Vec, opts: &TestOptions, - maybe_sysroot: Option, linker: Option, edition: Edition, - persist_doctests: Option) { +/// Documentation test failure modes. +enum TestFailure { + /// The test failed to compile. + CompileError, + /// The test is marked `compile_fail` but compiled successfully. + UnexpectedCompilePass, + /// The test failed to compile (as expected) but the compiler output did not contain all + /// expected error codes. + MissingErrorCodes(Vec), + /// The test binary was unable to be executed. + ExecutionError(io::Error), + /// The test binary exited with a non-zero exit code. + /// + /// This typically means an assertion in the test failed or another form of panic occurred. + ExecutionFailure(process::Output), + /// The test is marked `should_panic` but the test binary executed successfully. + UnexpectedRunPass, +} + +fn run_test( + test: &str, + cratename: &str, + filename: &FileName, + line: usize, + cfgs: Vec, + libs: Vec, + cg: CodegenOptions, + externs: Externs, + should_panic: bool, + no_run: bool, + as_test_harness: bool, + compile_fail: bool, + mut error_codes: Vec, + opts: &TestOptions, + maybe_sysroot: Option, + linker: Option, + edition: Edition, + persist_doctests: Option, +) -> Result<(), TestFailure> { let (test, line_offset) = match panic::catch_unwind(|| { make_test(test, Some(cratename), as_test_harness, opts, edition) }) { @@ -307,44 +339,43 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize, match (compile_result, compile_fail) { (Ok(()), true) => { - panic!("test compiled while it wasn't supposed to") + return Err(TestFailure::UnexpectedCompilePass); } (Ok(()), false) => {} (Err(_), true) => { - if error_codes.len() > 0 { + if !error_codes.is_empty() { let out = String::from_utf8(data.lock().unwrap().to_vec()).unwrap(); error_codes.retain(|err| !out.contains(err)); + + if !error_codes.is_empty() { + return Err(TestFailure::MissingErrorCodes(error_codes)); + } } } (Err(_), false) => { - panic!("couldn't compile the test") + return Err(TestFailure::CompileError); } } - if error_codes.len() > 0 { - panic!("Some expected error codes were not found: {:?}", error_codes); + if no_run { + return Ok(()); } - if no_run { return } - // Run the code! let mut cmd = Command::new(output_file); match cmd.output() { - Err(e) => panic!("couldn't run the test: {}{}", e, - if e.kind() == io::ErrorKind::PermissionDenied { - " - maybe your tempdir is mounted with noexec?" - } else { "" }), + Err(e) => return Err(TestFailure::ExecutionError(e)), Ok(out) => { if should_panic && out.status.success() { - panic!("test executable succeeded when it should have failed"); + return Err(TestFailure::UnexpectedRunPass); } else if !should_panic && !out.status.success() { - panic!("test executable failed:\n{}\n{}\n", - str::from_utf8(&out.stdout).unwrap_or(""), - str::from_utf8(&out.stderr).unwrap_or("")); + return Err(TestFailure::ExecutionFailure(out)); } } } + + Ok(()) } /// Transforms a test into code that can be compiled into a Rust binary, and returns the number of @@ -711,7 +742,7 @@ impl Tester for Collector { allow_fail: config.allow_fail, }, testfn: testing::DynTestFn(box move || { - run_test( + let res = run_test( &test, &cratename, &filename, @@ -730,7 +761,65 @@ impl Tester for Collector { linker, edition, persist_doctests - ) + ); + + if let Err(err) = res { + match err { + TestFailure::CompileError => { + eprint!("Couldn't compile the test."); + } + TestFailure::UnexpectedCompilePass => { + eprint!("Test compiled successfully, but it's marked `compile_fail`."); + } + TestFailure::UnexpectedRunPass => { + eprint!("Test executable succeeded, but it's marked `should_panic`."); + } + TestFailure::MissingErrorCodes(codes) => { + eprint!("Some expected error codes were not found: {:?}", codes); + } + TestFailure::ExecutionError(err) => { + eprint!("Couldn't run the test: {}", err); + if err.kind() == io::ErrorKind::PermissionDenied { + eprint!(" - maybe your tempdir is mounted with noexec?"); + } + } + TestFailure::ExecutionFailure(out) => { + let reason = if let Some(code) = out.status.code() { + format!("exit code {}", code) + } else { + String::from("terminated by signal") + }; + + eprintln!("Test executable failed ({}).", reason); + + // FIXME(#12309): An unfortunate side-effect of capturing the test + // executable's output is that the relative ordering between the test's + // stdout and stderr is lost. However, this is better than the + // alternative: if the test executable inherited the parent's I/O + // handles the output wouldn't be captured at all, even on success. + // + // The ordering could be preserved if the test process' stderr was + // redirected to stdout, but that functionality does not exist in the + // standard library, so it may not be portable enough. + let stdout = str::from_utf8(&out.stdout).unwrap_or_default(); + let stderr = str::from_utf8(&out.stderr).unwrap_or_default(); + + if !stdout.is_empty() || !stderr.is_empty() { + eprintln!(); + + if !stdout.is_empty() { + eprintln!("stdout:\n{}", stdout); + } + + if !stderr.is_empty() { + eprintln!("stderr:\n{}", stderr); + } + } + } + } + + panic::resume_unwind(box ()); + } }), }); } diff --git a/src/test/rustdoc-ui/failed-doctest-compile-fail.rs b/src/test/rustdoc-ui/failed-doctest-compile-fail.rs new file mode 100644 index 0000000000000..297d6efd45fee --- /dev/null +++ b/src/test/rustdoc-ui/failed-doctest-compile-fail.rs @@ -0,0 +1,11 @@ +// FIXME: if/when the output of the test harness can be tested on its own, this test should be +// adapted to use that, and that normalize line can go away + +// compile-flags:--test +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// failure-status: 101 + +/// ```compile_fail +/// println!("Hello"); +/// ``` +pub struct Foo; diff --git a/src/test/rustdoc-ui/failed-doctest-compile-fail.stdout b/src/test/rustdoc-ui/failed-doctest-compile-fail.stdout new file mode 100644 index 0000000000000..74e33d7beebeb --- /dev/null +++ b/src/test/rustdoc-ui/failed-doctest-compile-fail.stdout @@ -0,0 +1,14 @@ + +running 1 test +test $DIR/failed-doctest-compile-fail.rs - Foo (line 8) ... FAILED + +failures: + +---- $DIR/failed-doctest-compile-fail.rs - Foo (line 8) stdout ---- +Test compiled successfully, but it's marked `compile_fail`. + +failures: + $DIR/failed-doctest-compile-fail.rs - Foo (line 8) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out + diff --git a/src/test/rustdoc-ui/failed-doctest-missing-codes.rs b/src/test/rustdoc-ui/failed-doctest-missing-codes.rs new file mode 100644 index 0000000000000..62102062d4991 --- /dev/null +++ b/src/test/rustdoc-ui/failed-doctest-missing-codes.rs @@ -0,0 +1,11 @@ +// FIXME: if/when the output of the test harness can be tested on its own, this test should be +// adapted to use that, and that normalize line can go away + +// compile-flags:--test +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// failure-status: 101 + +/// ```compile_fail,E0004 +/// let x: () = 5i32; +/// ``` +pub struct Foo; diff --git a/src/test/rustdoc-ui/failed-doctest-missing-codes.stdout b/src/test/rustdoc-ui/failed-doctest-missing-codes.stdout new file mode 100644 index 0000000000000..d206b721765b2 --- /dev/null +++ b/src/test/rustdoc-ui/failed-doctest-missing-codes.stdout @@ -0,0 +1,26 @@ + +running 1 test +test $DIR/failed-doctest-missing-codes.rs - Foo (line 8) ... FAILED + +failures: + +---- $DIR/failed-doctest-missing-codes.rs - Foo (line 8) stdout ---- +error[E0308]: mismatched types + --> $DIR/failed-doctest-missing-codes.rs:9:13 + | +3 | let x: () = 5i32; + | ^^^^ expected (), found i32 + | + = note: expected type `()` + found type `i32` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. +Some expected error codes were not found: ["E0004"] + +failures: + $DIR/failed-doctest-missing-codes.rs - Foo (line 8) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out + diff --git a/src/test/rustdoc-ui/failed-doctest-output.rs b/src/test/rustdoc-ui/failed-doctest-output.rs index 48f1424e6b23d..d2cdeb8f8f50e 100644 --- a/src/test/rustdoc-ui/failed-doctest-output.rs +++ b/src/test/rustdoc-ui/failed-doctest-output.rs @@ -5,10 +5,13 @@ // compile-flags:--test // normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" // failure-status: 101 -// rustc-env:RUST_BACKTRACE=0 // doctest fails at runtime /// ``` +/// println!("stdout 1"); +/// eprintln!("stderr 1"); +/// println!("stdout 2"); +/// eprintln!("stderr 2"); /// panic!("oh no"); /// ``` pub struct SomeStruct; diff --git a/src/test/rustdoc-ui/failed-doctest-output.stdout b/src/test/rustdoc-ui/failed-doctest-output.stdout index 45efa30d9919c..0c42c652d786c 100644 --- a/src/test/rustdoc-ui/failed-doctest-output.stdout +++ b/src/test/rustdoc-ui/failed-doctest-output.stdout @@ -1,13 +1,13 @@ running 2 tests -test $DIR/failed-doctest-output.rs - OtherStruct (line 17) ... FAILED -test $DIR/failed-doctest-output.rs - SomeStruct (line 11) ... FAILED +test $DIR/failed-doctest-output.rs - OtherStruct (line 20) ... FAILED +test $DIR/failed-doctest-output.rs - SomeStruct (line 10) ... FAILED failures: ----- $DIR/failed-doctest-output.rs - OtherStruct (line 17) stdout ---- +---- $DIR/failed-doctest-output.rs - OtherStruct (line 20) stdout ---- error[E0425]: cannot find value `no` in this scope - --> $DIR/failed-doctest-output.rs:18:1 + --> $DIR/failed-doctest-output.rs:21:1 | 3 | no | ^^ not found in this scope @@ -15,21 +15,25 @@ error[E0425]: cannot find value `no` in this scope error: aborting due to previous error For more information about this error, try `rustc --explain E0425`. -thread '$DIR/failed-doctest-output.rs - OtherStruct (line 17)' panicked at 'couldn't compile the test', src/librustdoc/test.rs:320:13 +Couldn't compile the test. +---- $DIR/failed-doctest-output.rs - SomeStruct (line 10) stdout ---- +Test executable failed (exit code 101). + +stdout: +stdout 1 +stdout 2 + +stderr: +stderr 1 +stderr 2 +thread 'main' panicked at 'oh no', $DIR/failed-doctest-output.rs:7:1 note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace. ----- $DIR/failed-doctest-output.rs - SomeStruct (line 11) stdout ---- -thread '$DIR/failed-doctest-output.rs - SomeStruct (line 11)' panicked at 'test executable failed: - -thread 'main' panicked at 'oh no', $DIR/failed-doctest-output.rs:3:1 -note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace. - -', src/librustdoc/test.rs:342:17 failures: - $DIR/failed-doctest-output.rs - OtherStruct (line 17) - $DIR/failed-doctest-output.rs - SomeStruct (line 11) + $DIR/failed-doctest-output.rs - OtherStruct (line 20) + $DIR/failed-doctest-output.rs - SomeStruct (line 10) test result: FAILED. 0 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out diff --git a/src/test/rustdoc-ui/failed-doctest-should-panic.rs b/src/test/rustdoc-ui/failed-doctest-should-panic.rs new file mode 100644 index 0000000000000..400fb97804aab --- /dev/null +++ b/src/test/rustdoc-ui/failed-doctest-should-panic.rs @@ -0,0 +1,11 @@ +// FIXME: if/when the output of the test harness can be tested on its own, this test should be +// adapted to use that, and that normalize line can go away + +// compile-flags:--test +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// failure-status: 101 + +/// ```should_panic +/// println!("Hello, world!"); +/// ``` +pub struct Foo; diff --git a/src/test/rustdoc-ui/failed-doctest-should-panic.stdout b/src/test/rustdoc-ui/failed-doctest-should-panic.stdout new file mode 100644 index 0000000000000..081b64b50af9b --- /dev/null +++ b/src/test/rustdoc-ui/failed-doctest-should-panic.stdout @@ -0,0 +1,14 @@ + +running 1 test +test $DIR/failed-doctest-should-panic.rs - Foo (line 8) ... FAILED + +failures: + +---- $DIR/failed-doctest-should-panic.rs - Foo (line 8) stdout ---- +Test executable succeeded, but it's marked `should_panic`. + +failures: + $DIR/failed-doctest-should-panic.rs - Foo (line 8) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out + diff --git a/src/test/rustdoc-ui/unparseable-doc-test.stdout b/src/test/rustdoc-ui/unparseable-doc-test.stdout index f31b64fbce36a..0350c01643607 100644 --- a/src/test/rustdoc-ui/unparseable-doc-test.stdout +++ b/src/test/rustdoc-ui/unparseable-doc-test.stdout @@ -13,9 +13,7 @@ error: unterminated double quote string error: aborting due to previous error -thread '$DIR/unparseable-doc-test.rs - foo (line 6)' panicked at 'couldn't compile the test', src/librustdoc/test.rs:320:13 -note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace. - +Couldn't compile the test. failures: $DIR/unparseable-doc-test.rs - foo (line 6) From 24b2e20b3127b5a8da20c4910080bf9756dd2a45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 26 May 2019 11:39:48 -0700 Subject: [PATCH 03/11] Account for short-hand init structs when suggesting conversion --- src/librustc_typeck/check/demand.rs | 6 ++++- src/librustc_typeck/check/mod.rs | 20 +++++++++++----- src/test/ui/suggestions/issue-52820.rs | 12 ++++++++++ src/test/ui/suggestions/issue-52820.stderr | 27 ++++++++++++++++++++++ 4 files changed, 58 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/suggestions/issue-52820.rs create mode 100644 src/test/ui/suggestions/issue-52820.stderr diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index a4e687b8f9080..bc872f8c03c0e 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -270,7 +270,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { None } - fn is_hir_id_from_struct_pattern_shorthand_field(&self, hir_id: hir::HirId, sp: Span) -> bool { + crate fn is_hir_id_from_struct_pattern_shorthand_field( + &self, + hir_id: hir::HirId, + sp: Span, + ) -> bool { let cm = self.sess().source_map(); let parent_id = self.tcx.hir().get_parent_node_by_hir_id(hir_id); if let Some(parent) = self.tcx.hir().find_by_hir_id(parent_id) { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 655bf5722ae5a..e6c9448a6057c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5014,6 +5014,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Applicability::MachineApplicable, ); } else if !self.check_for_cast(err, expr, found, expected) { + let is_struct_pat_shorthand_field = self.is_hir_id_from_struct_pattern_shorthand_field( + expr.hir_id, + expr.span, + ); let methods = self.get_conversion_methods(expr.span, expected, found); if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) { let mut suggestions = iter::repeat(&expr_text).zip(methods.iter()) @@ -5023,14 +5027,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { None // do not suggest code that is already there (#53348) } else { let method_call_list = [".to_vec()", ".to_string()"]; - if receiver.ends_with(".clone()") + let sugg = if receiver.ends_with(".clone()") && method_call_list.contains(&method_call.as_str()) { let max_len = receiver.rfind(".").unwrap(); - Some(format!("{}{}", &receiver[..max_len], method_call)) - } - else { - Some(format!("{}{}", receiver, method_call)) - } + format!("{}{}", &receiver[..max_len], method_call) + } else { + format!("{}{}", receiver, method_call) + }; + Some(if is_struct_pat_shorthand_field { + format!("{}: {}", receiver, sugg) + } else { + sugg + }) } }).peekable(); if suggestions.peek().is_some() { diff --git a/src/test/ui/suggestions/issue-52820.rs b/src/test/ui/suggestions/issue-52820.rs new file mode 100644 index 0000000000000..075b07f565203 --- /dev/null +++ b/src/test/ui/suggestions/issue-52820.rs @@ -0,0 +1,12 @@ +struct Bravery { + guts: String, + brains: String, +} + +fn main() { + let guts = "mettle"; + let _ = Bravery { + guts, //~ ERROR mismatched types + brains: guts.clone(), //~ ERROR mismatched types + }; +} diff --git a/src/test/ui/suggestions/issue-52820.stderr b/src/test/ui/suggestions/issue-52820.stderr new file mode 100644 index 0000000000000..fb568aca250e7 --- /dev/null +++ b/src/test/ui/suggestions/issue-52820.stderr @@ -0,0 +1,27 @@ +error[E0308]: mismatched types + --> $DIR/issue-52820.rs:9:9 + | +LL | guts, + | ^^^^ + | | + | expected struct `std::string::String`, found &str + | help: try using a conversion method: `guts: guts.to_string()` + | + = note: expected type `std::string::String` + found type `&str` + +error[E0308]: mismatched types + --> $DIR/issue-52820.rs:10:17 + | +LL | brains: guts.clone(), + | ^^^^^^^^^^^^ + | | + | expected struct `std::string::String`, found &str + | help: try using a conversion method: `guts.to_string()` + | + = note: expected type `std::string::String` + found type `&str` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. From 1b86bd73cd5e8e463f50e5c53968125d0ab4e1f0 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 28 May 2019 15:18:37 +0200 Subject: [PATCH 04/11] is_union returns ty to avoid computing it twice --- .../borrow_check/conflict_errors.rs | 50 ++++++++++--------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/src/librustc_mir/borrow_check/conflict_errors.rs b/src/librustc_mir/borrow_check/conflict_errors.rs index 8022d1f0c7315..58adc24b80987 100644 --- a/src/librustc_mir/borrow_check/conflict_errors.rs +++ b/src/librustc_mir/borrow_check/conflict_errors.rs @@ -595,11 +595,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { ) -> (String, String, String, String) { // Define a small closure that we can use to check if the type of a place // is a union. - let is_union = |place: &Place<'tcx>| -> bool { - place.ty(self.mir, self.infcx.tcx).ty - .ty_adt_def() - .map(|adt| adt.is_union()) - .unwrap_or(false) + let union_ty = |place: &Place<'tcx>| -> Option> { + let ty = place.ty(self.mir, self.infcx.tcx).ty; + ty.ty_adt_def().filter(|adt| adt.is_union()).map(|_| ty) }; // Start with an empty tuple, so we can use the functions on `Option` to reduce some @@ -619,7 +617,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { let mut current = first_borrowed_place; while let Place::Projection(box Projection { base, elem }) = current { match elem { - ProjectionElem::Field(field, _) if is_union(base) => { + ProjectionElem::Field(field, _) if union_ty(base).is_some() => { return Some((base, field)); }, _ => current = base, @@ -632,25 +630,29 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // borrowed place and look for a access to a different field of the same union. let mut current = second_borrowed_place; while let Place::Projection(box Projection { base, elem }) = current { - match elem { - ProjectionElem::Field(field, _) if { - is_union(base) && field != target_field && base == target_base - } => { - let desc_base = self.describe_place(base) - .unwrap_or_else(|| "_".to_owned()); - let desc_first = self.describe_place(first_borrowed_place) - .unwrap_or_else(|| "_".to_owned()); - let desc_second = self.describe_place(second_borrowed_place) - .unwrap_or_else(|| "_".to_owned()); - - // Also compute the name of the union type, eg. `Foo` so we - // can add a helpful note with it. - let ty = base.ty(self.mir, self.infcx.tcx).ty; - - return Some((desc_base, desc_first, desc_second, ty.to_string())); - }, - _ => current = base, + if let ProjectionElem::Field(field, _) = elem { + if let Some(union_ty) = union_ty(base) { + if field != target_field && base == target_base { + let desc_base = + self.describe_place(base).unwrap_or_else(|| "_".to_owned()); + let desc_first = self + .describe_place(first_borrowed_place) + .unwrap_or_else(|| "_".to_owned()); + let desc_second = self + .describe_place(second_borrowed_place) + .unwrap_or_else(|| "_".to_owned()); + + return Some(( + desc_base, + desc_first, + desc_second, + union_ty.to_string(), + )); + } + } } + + current = base; } None }) From bb94fc00695be648f62751e8f393e11644d938ae Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 28 May 2019 16:47:59 +0200 Subject: [PATCH 05/11] Use closure to avoid self.describe_place(...).unwrap_or_else(...) repetition --- .../borrow_check/conflict_errors.rs | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/librustc_mir/borrow_check/conflict_errors.rs b/src/librustc_mir/borrow_check/conflict_errors.rs index 58adc24b80987..5c5d495466cda 100644 --- a/src/librustc_mir/borrow_check/conflict_errors.rs +++ b/src/librustc_mir/borrow_check/conflict_errors.rs @@ -599,6 +599,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { let ty = place.ty(self.mir, self.infcx.tcx).ty; ty.ty_adt_def().filter(|adt| adt.is_union()).map(|_| ty) }; + let describe_place = |place| self.describe_place(place).unwrap_or_else(|| "_".to_owned()); // Start with an empty tuple, so we can use the functions on `Option` to reduce some // code duplication (particularly around returning an empty description in the failure @@ -633,19 +634,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { if let ProjectionElem::Field(field, _) = elem { if let Some(union_ty) = union_ty(base) { if field != target_field && base == target_base { - let desc_base = - self.describe_place(base).unwrap_or_else(|| "_".to_owned()); - let desc_first = self - .describe_place(first_borrowed_place) - .unwrap_or_else(|| "_".to_owned()); - let desc_second = self - .describe_place(second_borrowed_place) - .unwrap_or_else(|| "_".to_owned()); - return Some(( - desc_base, - desc_first, - desc_second, + describe_place(base), + describe_place(first_borrowed_place), + describe_place(second_borrowed_place), union_ty.to_string(), )); } @@ -659,9 +651,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { .unwrap_or_else(|| { // If we didn't find a field access into a union, or both places match, then // only return the description of the first place. - let desc_place = self.describe_place(first_borrowed_place) - .unwrap_or_else(|| "_".to_owned()); - (desc_place, "".to_string(), "".to_string(), "".to_string()) + ( + describe_place(first_borrowed_place), + "".to_string(), + "".to_string(), + "".to_string(), + ) }) } From 35ce2abf2142f5f5e96222fd4dd6b9472f59a6ca Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 28 May 2019 22:53:16 +0100 Subject: [PATCH 06/11] Use proper const printing in rustdoc --- src/librustdoc/clean/mod.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 4ee63a4c9703b..e68ad6a7c3b4b 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -3145,10 +3145,7 @@ impl<'tcx> Clean for ty::Const<'tcx> { fn clean(&self, cx: &DocContext<'_>) -> Constant { Constant { type_: self.ty.clean(cx), - expr: match self.val { - ConstValue::Param(ty::ParamConst { name, .. }) => format!("{}", name), - e => format!("{:?}", e), // FIXME generic consts with expressions - }, + expr: format!("{}", self), } } } From 7f9dc73a31b94b76a87151467d0dd6dfc186a573 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 28 May 2019 22:53:36 +0100 Subject: [PATCH 07/11] Add a const-generics folder to rustdoc tests --- .../{generic-const.rs => const-generics/const-impl.rs} | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) rename src/test/rustdoc/{generic-const.rs => const-generics/const-impl.rs} (99%) diff --git a/src/test/rustdoc/generic-const.rs b/src/test/rustdoc/const-generics/const-impl.rs similarity index 99% rename from src/test/rustdoc/generic-const.rs rename to src/test/rustdoc/const-generics/const-impl.rs index d6794ac8f1d94..85ee6d3376b27 100644 --- a/src/test/rustdoc/generic-const.rs +++ b/src/test/rustdoc/const-generics/const-impl.rs @@ -1,7 +1,8 @@ +// ignore-tidy-linelength + #![feature(const_generics)] -#![crate_name = "foo"] -// ignore-tidy-linelength +#![crate_name = "foo"] pub enum Order { Sorted, From 9c9b7b4eaceefe88bafc3b4e3529635973320253 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 28 May 2019 22:53:48 +0100 Subject: [PATCH 08/11] Add a regression test for unevaluated const in rustdoc --- src/test/rustdoc/const-generics/add-impl.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/test/rustdoc/const-generics/add-impl.rs diff --git a/src/test/rustdoc/const-generics/add-impl.rs b/src/test/rustdoc/const-generics/add-impl.rs new file mode 100644 index 0000000000000..ed45d339728bc --- /dev/null +++ b/src/test/rustdoc/const-generics/add-impl.rs @@ -0,0 +1,21 @@ +// ignore-tidy-linelength + +#![feature(const_generics)] + +#![crate_name = "foo"] + +use std::ops::Add; + +// @has foo/struct.Simd.html '//pre[@class="rust struct"]' 'pub struct Simd' +pub struct Simd { + inner: T, +} + +// @has foo/struct.Simd.html '//div[@id="implementations-list"]/h3/code' 'impl Add> for Simd' +impl Add for Simd { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + Self { inner: 0 } + } +} From 1529067a046b079c1348ead39199e9c491a5f472 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 May 2019 10:00:13 +0200 Subject: [PATCH 09/11] split libcore::mem into multiple files --- src/libcore/mem.rs | 1406 ------------------------------ src/libcore/mem/manually_drop.rs | 146 ++++ src/libcore/mem/maybe_uninit.rs | 519 +++++++++++ src/libcore/mem/mod.rs | 752 ++++++++++++++++ 4 files changed, 1417 insertions(+), 1406 deletions(-) delete mode 100644 src/libcore/mem.rs create mode 100644 src/libcore/mem/manually_drop.rs create mode 100644 src/libcore/mem/maybe_uninit.rs create mode 100644 src/libcore/mem/mod.rs diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs deleted file mode 100644 index 40f4354213b40..0000000000000 --- a/src/libcore/mem.rs +++ /dev/null @@ -1,1406 +0,0 @@ -//! Basic functions for dealing with memory. -//! -//! This module contains functions for querying the size and alignment of -//! types, initializing and manipulating memory. - -#![stable(feature = "rust1", since = "1.0.0")] - -use crate::clone; -use crate::cmp; -use crate::fmt; -use crate::hash; -use crate::intrinsics; -use crate::marker::{Copy, PhantomData, Sized}; -use crate::ptr; -use crate::ops::{Deref, DerefMut}; - -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(inline)] -pub use crate::intrinsics::transmute; - -/// Takes ownership and "forgets" about the value **without running its destructor**. -/// -/// Any resources the value manages, such as heap memory or a file handle, will linger -/// forever in an unreachable state. However, it does not guarantee that pointers -/// to this memory will remain valid. -/// -/// * If you want to leak memory, see [`Box::leak`][leak]. -/// * If you want to obtain a raw pointer to the memory, see [`Box::into_raw`][into_raw]. -/// * If you want to dispose of a value properly, running its destructor, see -/// [`mem::drop`][drop]. -/// -/// # Safety -/// -/// `forget` is not marked as `unsafe`, because Rust's safety guarantees -/// do not include a guarantee that destructors will always run. For example, -/// a program can create a reference cycle using [`Rc`][rc], or call -/// [`process::exit`][exit] to exit without running destructors. Thus, allowing -/// `mem::forget` from safe code does not fundamentally change Rust's safety -/// guarantees. -/// -/// That said, leaking resources such as memory or I/O objects is usually undesirable, -/// so `forget` is only recommended for specialized use cases like those shown below. -/// -/// Because forgetting a value is allowed, any `unsafe` code you write must -/// allow for this possibility. You cannot return a value and expect that the -/// caller will necessarily run the value's destructor. -/// -/// [rc]: ../../std/rc/struct.Rc.html -/// [exit]: ../../std/process/fn.exit.html -/// -/// # Examples -/// -/// Leak an I/O object, never closing the file: -/// -/// ```no_run -/// use std::mem; -/// use std::fs::File; -/// -/// let file = File::open("foo.txt").unwrap(); -/// mem::forget(file); -/// ``` -/// -/// The practical use cases for `forget` are rather specialized and mainly come -/// up in unsafe or FFI code. -/// -/// [drop]: fn.drop.html -/// [uninit]: fn.uninitialized.html -/// [clone]: ../clone/trait.Clone.html -/// [swap]: fn.swap.html -/// [box]: ../../std/boxed/struct.Box.html -/// [leak]: ../../std/boxed/struct.Box.html#method.leak -/// [into_raw]: ../../std/boxed/struct.Box.html#method.into_raw -/// [ub]: ../../reference/behavior-considered-undefined.html -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub fn forget(t: T) { - ManuallyDrop::new(t); -} - -/// Like [`forget`], but also accepts unsized values. -/// -/// This function is just a shim intended to be removed when the `unsized_locals` feature gets -/// stabilized. -/// -/// [`forget`]: fn.forget.html -#[inline] -#[unstable(feature = "forget_unsized", issue = "0")] -pub fn forget_unsized(t: T) { - unsafe { intrinsics::forget(t) } -} - -/// Returns the size of a type in bytes. -/// -/// More specifically, this is the offset in bytes between successive elements -/// in an array with that item type including alignment padding. Thus, for any -/// type `T` and length `n`, `[T; n]` has a size of `n * size_of::()`. -/// -/// In general, the size of a type is not stable across compilations, but -/// specific types such as primitives are. -/// -/// The following table gives the size for primitives. -/// -/// Type | size_of::\() -/// ---- | --------------- -/// () | 0 -/// bool | 1 -/// u8 | 1 -/// u16 | 2 -/// u32 | 4 -/// u64 | 8 -/// u128 | 16 -/// i8 | 1 -/// i16 | 2 -/// i32 | 4 -/// i64 | 8 -/// i128 | 16 -/// f32 | 4 -/// f64 | 8 -/// char | 4 -/// -/// Furthermore, `usize` and `isize` have the same size. -/// -/// The types `*const T`, `&T`, `Box`, `Option<&T>`, and `Option>` all have -/// the same size. If `T` is Sized, all of those types have the same size as `usize`. -/// -/// The mutability of a pointer does not change its size. As such, `&T` and `&mut T` -/// have the same size. Likewise for `*const T` and `*mut T`. -/// -/// # Size of `#[repr(C)]` items -/// -/// The `C` representation for items has a defined layout. With this layout, -/// the size of items is also stable as long as all fields have a stable size. -/// -/// ## Size of Structs -/// -/// For `structs`, the size is determined by the following algorithm. -/// -/// For each field in the struct ordered by declaration order: -/// -/// 1. Add the size of the field. -/// 2. Round up the current size to the nearest multiple of the next field's [alignment]. -/// -/// Finally, round the size of the struct to the nearest multiple of its [alignment]. -/// The alignment of the struct is usually the largest alignment of all its -/// fields; this can be changed with the use of `repr(align(N))`. -/// -/// Unlike `C`, zero sized structs are not rounded up to one byte in size. -/// -/// ## Size of Enums -/// -/// Enums that carry no data other than the discriminant have the same size as C enums -/// on the platform they are compiled for. -/// -/// ## Size of Unions -/// -/// The size of a union is the size of its largest field. -/// -/// Unlike `C`, zero sized unions are not rounded up to one byte in size. -/// -/// # Examples -/// -/// ``` -/// use std::mem; -/// -/// // Some primitives -/// assert_eq!(4, mem::size_of::()); -/// assert_eq!(8, mem::size_of::()); -/// assert_eq!(0, mem::size_of::<()>()); -/// -/// // Some arrays -/// assert_eq!(8, mem::size_of::<[i32; 2]>()); -/// assert_eq!(12, mem::size_of::<[i32; 3]>()); -/// assert_eq!(0, mem::size_of::<[i32; 0]>()); -/// -/// -/// // Pointer size equality -/// assert_eq!(mem::size_of::<&i32>(), mem::size_of::<*const i32>()); -/// assert_eq!(mem::size_of::<&i32>(), mem::size_of::>()); -/// assert_eq!(mem::size_of::<&i32>(), mem::size_of::>()); -/// assert_eq!(mem::size_of::>(), mem::size_of::>>()); -/// ``` -/// -/// Using `#[repr(C)]`. -/// -/// ``` -/// use std::mem; -/// -/// #[repr(C)] -/// struct FieldStruct { -/// first: u8, -/// second: u16, -/// third: u8 -/// } -/// -/// // The size of the first field is 1, so add 1 to the size. Size is 1. -/// // The alignment of the second field is 2, so add 1 to the size for padding. Size is 2. -/// // The size of the second field is 2, so add 2 to the size. Size is 4. -/// // The alignment of the third field is 1, so add 0 to the size for padding. Size is 4. -/// // The size of the third field is 1, so add 1 to the size. Size is 5. -/// // Finally, the alignment of the struct is 2 (because the largest alignment amongst its -/// // fields is 2), so add 1 to the size for padding. Size is 6. -/// assert_eq!(6, mem::size_of::()); -/// -/// #[repr(C)] -/// struct TupleStruct(u8, u16, u8); -/// -/// // Tuple structs follow the same rules. -/// assert_eq!(6, mem::size_of::()); -/// -/// // Note that reordering the fields can lower the size. We can remove both padding bytes -/// // by putting `third` before `second`. -/// #[repr(C)] -/// struct FieldStructOptimized { -/// first: u8, -/// third: u8, -/// second: u16 -/// } -/// -/// assert_eq!(4, mem::size_of::()); -/// -/// // Union size is the size of the largest field. -/// #[repr(C)] -/// union ExampleUnion { -/// smaller: u8, -/// larger: u16 -/// } -/// -/// assert_eq!(2, mem::size_of::()); -/// ``` -/// -/// [alignment]: ./fn.align_of.html -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_promotable] -pub const fn size_of() -> usize { - intrinsics::size_of::() -} - -/// Returns the size of the pointed-to value in bytes. -/// -/// This is usually the same as `size_of::()`. However, when `T` *has* no -/// statically-known size, e.g., a slice [`[T]`][slice] or a [trait object], -/// then `size_of_val` can be used to get the dynamically-known size. -/// -/// [slice]: ../../std/primitive.slice.html -/// [trait object]: ../../book/ch17-02-trait-objects.html -/// -/// # Examples -/// -/// ``` -/// use std::mem; -/// -/// assert_eq!(4, mem::size_of_val(&5i32)); -/// -/// let x: [u8; 13] = [0; 13]; -/// let y: &[u8] = &x; -/// assert_eq!(13, mem::size_of_val(y)); -/// ``` -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub fn size_of_val(val: &T) -> usize { - unsafe { intrinsics::size_of_val(val) } -} - -/// Returns the [ABI]-required minimum alignment of a type. -/// -/// Every reference to a value of the type `T` must be a multiple of this number. -/// -/// This is the alignment used for struct fields. It may be smaller than the preferred alignment. -/// -/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface -/// -/// # Examples -/// -/// ``` -/// # #![allow(deprecated)] -/// use std::mem; -/// -/// assert_eq!(4, mem::min_align_of::()); -/// ``` -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated(reason = "use `align_of` instead", since = "1.2.0")] -pub fn min_align_of() -> usize { - intrinsics::min_align_of::() -} - -/// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to. -/// -/// Every reference to a value of the type `T` must be a multiple of this number. -/// -/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface -/// -/// # Examples -/// -/// ``` -/// # #![allow(deprecated)] -/// use std::mem; -/// -/// assert_eq!(4, mem::min_align_of_val(&5i32)); -/// ``` -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated(reason = "use `align_of_val` instead", since = "1.2.0")] -pub fn min_align_of_val(val: &T) -> usize { - unsafe { intrinsics::min_align_of_val(val) } -} - -/// Returns the [ABI]-required minimum alignment of a type. -/// -/// Every reference to a value of the type `T` must be a multiple of this number. -/// -/// This is the alignment used for struct fields. It may be smaller than the preferred alignment. -/// -/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface -/// -/// # Examples -/// -/// ``` -/// use std::mem; -/// -/// assert_eq!(4, mem::align_of::()); -/// ``` -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_promotable] -pub const fn align_of() -> usize { - intrinsics::min_align_of::() -} - -/// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to. -/// -/// Every reference to a value of the type `T` must be a multiple of this number. -/// -/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface -/// -/// # Examples -/// -/// ``` -/// use std::mem; -/// -/// assert_eq!(4, mem::align_of_val(&5i32)); -/// ``` -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub fn align_of_val(val: &T) -> usize { - unsafe { intrinsics::min_align_of_val(val) } -} - -/// Returns `true` if dropping values of type `T` matters. -/// -/// This is purely an optimization hint, and may be implemented conservatively: -/// it may return `true` for types that don't actually need to be dropped. -/// As such always returning `true` would be a valid implementation of -/// this function. However if this function actually returns `false`, then you -/// can be certain dropping `T` has no side effect. -/// -/// Low level implementations of things like collections, which need to manually -/// drop their data, should use this function to avoid unnecessarily -/// trying to drop all their contents when they are destroyed. This might not -/// make a difference in release builds (where a loop that has no side-effects -/// is easily detected and eliminated), but is often a big win for debug builds. -/// -/// Note that `ptr::drop_in_place` already performs this check, so if your workload -/// can be reduced to some small number of drop_in_place calls, using this is -/// unnecessary. In particular note that you can drop_in_place a slice, and that -/// will do a single needs_drop check for all the values. -/// -/// Types like Vec therefore just `drop_in_place(&mut self[..])` without using -/// needs_drop explicitly. Types like HashMap, on the other hand, have to drop -/// values one at a time and should use this API. -/// -/// -/// # Examples -/// -/// Here's an example of how a collection might make use of needs_drop: -/// -/// ``` -/// use std::{mem, ptr}; -/// -/// pub struct MyCollection { -/// # data: [T; 1], -/// /* ... */ -/// } -/// # impl MyCollection { -/// # fn iter_mut(&mut self) -> &mut [T] { &mut self.data } -/// # fn free_buffer(&mut self) {} -/// # } -/// -/// impl Drop for MyCollection { -/// fn drop(&mut self) { -/// unsafe { -/// // drop the data -/// if mem::needs_drop::() { -/// for x in self.iter_mut() { -/// ptr::drop_in_place(x); -/// } -/// } -/// self.free_buffer(); -/// } -/// } -/// } -/// ``` -#[inline] -#[stable(feature = "needs_drop", since = "1.21.0")] -pub const fn needs_drop() -> bool { - intrinsics::needs_drop::() -} - -/// Creates a value whose bytes are all zero. -/// -/// This has the same effect as [`MaybeUninit::zeroed().assume_init()`][zeroed]. -/// It is useful for FFI sometimes, but should generally be avoided. -/// -/// There is no guarantee that an all-zero byte-pattern represents a valid value of -/// some type `T`. For example, the all-zero byte-pattern is not a valid value -/// for reference types (`&T` and `&mut T`). Using `zeroed` on such types -/// causes immediate [undefined behavior][ub] because [the Rust compiler assumes][inv] -/// that there always is a valid value in a variable it considers initialized. -/// -/// [zeroed]: union.MaybeUninit.html#method.zeroed -/// [ub]: ../../reference/behavior-considered-undefined.html -/// [inv]: union.MaybeUninit.html#initialization-invariant -/// -/// # Examples -/// -/// Correct usage of this function: initializing an integer with zero. -/// -/// ``` -/// use std::mem; -/// -/// let x: i32 = unsafe { mem::zeroed() }; -/// assert_eq!(0, x); -/// ``` -/// -/// *Incorrect* usage of this function: initializing a reference with zero. -/// -/// ```no_run -/// use std::mem; -/// -/// let _x: &i32 = unsafe { mem::zeroed() }; // Undefined behavior! -/// ``` -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub unsafe fn zeroed() -> T { - intrinsics::panic_if_uninhabited::(); - intrinsics::init() -} - -/// Bypasses Rust's normal memory-initialization checks by pretending to -/// produce a value of type `T`, while doing nothing at all. -/// -/// **This functon is deprecated.** Use [`MaybeUninit`] instead. -/// -/// The reason for deprecation is that the function basically cannot be used -/// correctly: [the Rust compiler assumes][inv] that values are properly initialized. -/// As a consequence, calling e.g. `mem::uninitialized::()` causes immediate -/// undefined behavior for returning a `bool` that is not definitely either `true` -/// or `false`. Worse, truly uninitialized memory like what gets returned here -/// is special in that the compiler knows that it does not have a fixed value. -/// This makes it undefined behavior to have uninitialized data in a variable even -/// if that variable has an integer type. -/// (Notice that the rules around uninitialized integers are not finalized yet, but -/// until they are, it is advisable to avoid them.) -/// -/// [`MaybeUninit`]: union.MaybeUninit.html -/// [inv]: union.MaybeUninit.html#initialization-invariant -#[inline] -#[rustc_deprecated(since = "1.38.0", reason = "use `mem::MaybeUninit` instead")] -#[stable(feature = "rust1", since = "1.0.0")] -pub unsafe fn uninitialized() -> T { - intrinsics::panic_if_uninhabited::(); - intrinsics::uninit() -} - -/// Swaps the values at two mutable locations, without deinitializing either one. -/// -/// # Examples -/// -/// ``` -/// use std::mem; -/// -/// let mut x = 5; -/// let mut y = 42; -/// -/// mem::swap(&mut x, &mut y); -/// -/// assert_eq!(42, x); -/// assert_eq!(5, y); -/// ``` -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub fn swap(x: &mut T, y: &mut T) { - unsafe { - ptr::swap_nonoverlapping_one(x, y); - } -} - -/// Moves `src` into the referenced `dest`, returning the previous `dest` value. -/// -/// Neither value is dropped. -/// -/// # Examples -/// -/// A simple example: -/// -/// ``` -/// use std::mem; -/// -/// let mut v: Vec = vec![1, 2]; -/// -/// let old_v = mem::replace(&mut v, vec![3, 4, 5]); -/// assert_eq!(vec![1, 2], old_v); -/// assert_eq!(vec![3, 4, 5], v); -/// ``` -/// -/// `replace` allows consumption of a struct field by replacing it with another value. -/// Without `replace` you can run into issues like these: -/// -/// ```compile_fail,E0507 -/// struct Buffer { buf: Vec } -/// -/// impl Buffer { -/// fn get_and_reset(&mut self) -> Vec { -/// // error: cannot move out of dereference of `&mut`-pointer -/// let buf = self.buf; -/// self.buf = Vec::new(); -/// buf -/// } -/// } -/// ``` -/// -/// Note that `T` does not necessarily implement [`Clone`], so it can't even clone and reset -/// `self.buf`. But `replace` can be used to disassociate the original value of `self.buf` from -/// `self`, allowing it to be returned: -/// -/// ``` -/// # #![allow(dead_code)] -/// use std::mem; -/// -/// # struct Buffer { buf: Vec } -/// impl Buffer { -/// fn get_and_reset(&mut self) -> Vec { -/// mem::replace(&mut self.buf, Vec::new()) -/// } -/// } -/// ``` -/// -/// [`Clone`]: ../../std/clone/trait.Clone.html -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub fn replace(dest: &mut T, mut src: T) -> T { - swap(dest, &mut src); - src -} - -/// Disposes of a value. -/// -/// This does call the argument's implementation of [`Drop`][drop]. -/// -/// This effectively does nothing for types which implement `Copy`, e.g. -/// integers. Such values are copied and _then_ moved into the function, so the -/// value persists after this function call. -/// -/// This function is not magic; it is literally defined as -/// -/// ``` -/// pub fn drop(_x: T) { } -/// ``` -/// -/// Because `_x` is moved into the function, it is automatically dropped before -/// the function returns. -/// -/// [drop]: ../ops/trait.Drop.html -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// let v = vec![1, 2, 3]; -/// -/// drop(v); // explicitly drop the vector -/// ``` -/// -/// Since [`RefCell`] enforces the borrow rules at runtime, `drop` can -/// release a [`RefCell`] borrow: -/// -/// ``` -/// use std::cell::RefCell; -/// -/// let x = RefCell::new(1); -/// -/// let mut mutable_borrow = x.borrow_mut(); -/// *mutable_borrow = 1; -/// -/// drop(mutable_borrow); // relinquish the mutable borrow on this slot -/// -/// let borrow = x.borrow(); -/// println!("{}", *borrow); -/// ``` -/// -/// Integers and other types implementing [`Copy`] are unaffected by `drop`. -/// -/// ``` -/// #[derive(Copy, Clone)] -/// struct Foo(u8); -/// -/// let x = 1; -/// let y = Foo(2); -/// drop(x); // a copy of `x` is moved and dropped -/// drop(y); // a copy of `y` is moved and dropped -/// -/// println!("x: {}, y: {}", x, y.0); // still available -/// ``` -/// -/// [`RefCell`]: ../../std/cell/struct.RefCell.html -/// [`Copy`]: ../../std/marker/trait.Copy.html -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub fn drop(_x: T) { } - -/// Interprets `src` as having type `&U`, and then reads `src` without moving -/// the contained value. -/// -/// This function will unsafely assume the pointer `src` is valid for -/// [`size_of::`][size_of] bytes by transmuting `&T` to `&U` and then reading -/// the `&U`. It will also unsafely create a copy of the contained value instead of -/// moving out of `src`. -/// -/// It is not a compile-time error if `T` and `U` have different sizes, but it -/// is highly encouraged to only invoke this function where `T` and `U` have the -/// same size. This function triggers [undefined behavior][ub] if `U` is larger than -/// `T`. -/// -/// [ub]: ../../reference/behavior-considered-undefined.html -/// [size_of]: fn.size_of.html -/// -/// # Examples -/// -/// ``` -/// use std::mem; -/// -/// #[repr(packed)] -/// struct Foo { -/// bar: u8, -/// } -/// -/// let foo_slice = [10u8]; -/// -/// unsafe { -/// // Copy the data from 'foo_slice' and treat it as a 'Foo' -/// let mut foo_struct: Foo = mem::transmute_copy(&foo_slice); -/// assert_eq!(foo_struct.bar, 10); -/// -/// // Modify the copied data -/// foo_struct.bar = 20; -/// assert_eq!(foo_struct.bar, 20); -/// } -/// -/// // The contents of 'foo_slice' should not have changed -/// assert_eq!(foo_slice, [10]); -/// ``` -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub unsafe fn transmute_copy(src: &T) -> U { - ptr::read_unaligned(src as *const T as *const U) -} - -/// Opaque type representing the discriminant of an enum. -/// -/// See the [`discriminant`] function in this module for more information. -/// -/// [`discriminant`]: fn.discriminant.html -#[stable(feature = "discriminant_value", since = "1.21.0")] -pub struct Discriminant(u64, PhantomData T>); - -// N.B. These trait implementations cannot be derived because we don't want any bounds on T. - -#[stable(feature = "discriminant_value", since = "1.21.0")] -impl Copy for Discriminant {} - -#[stable(feature = "discriminant_value", since = "1.21.0")] -impl clone::Clone for Discriminant { - fn clone(&self) -> Self { - *self - } -} - -#[stable(feature = "discriminant_value", since = "1.21.0")] -impl cmp::PartialEq for Discriminant { - fn eq(&self, rhs: &Self) -> bool { - self.0 == rhs.0 - } -} - -#[stable(feature = "discriminant_value", since = "1.21.0")] -impl cmp::Eq for Discriminant {} - -#[stable(feature = "discriminant_value", since = "1.21.0")] -impl hash::Hash for Discriminant { - fn hash(&self, state: &mut H) { - self.0.hash(state); - } -} - -#[stable(feature = "discriminant_value", since = "1.21.0")] -impl fmt::Debug for Discriminant { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_tuple("Discriminant") - .field(&self.0) - .finish() - } -} - -/// Returns a value uniquely identifying the enum variant in `v`. -/// -/// If `T` is not an enum, calling this function will not result in undefined behavior, but the -/// return value is unspecified. -/// -/// # Stability -/// -/// The discriminant of an enum variant may change if the enum definition changes. A discriminant -/// of some variant will not change between compilations with the same compiler. -/// -/// # Examples -/// -/// This can be used to compare enums that carry data, while disregarding -/// the actual data: -/// -/// ``` -/// use std::mem; -/// -/// enum Foo { A(&'static str), B(i32), C(i32) } -/// -/// assert!(mem::discriminant(&Foo::A("bar")) == mem::discriminant(&Foo::A("baz"))); -/// assert!(mem::discriminant(&Foo::B(1)) == mem::discriminant(&Foo::B(2))); -/// assert!(mem::discriminant(&Foo::B(3)) != mem::discriminant(&Foo::C(3))); -/// ``` -#[stable(feature = "discriminant_value", since = "1.21.0")] -pub fn discriminant(v: &T) -> Discriminant { - unsafe { - Discriminant(intrinsics::discriminant_value(v), PhantomData) - } -} - -/// A wrapper to inhibit compiler from automatically calling `T`’s destructor. -/// -/// This wrapper is 0-cost. -/// -/// `ManuallyDrop` is subject to the same layout optimizations as `T`. -/// As a consequence, it has *no effect* on the assumptions that the compiler makes -/// about all values being initialized at their type. In particular, initializing -/// a `ManuallyDrop<&mut T>` with [`mem::zeroed`] is undefined behavior. -/// If you need to handle uninitialized data, use [`MaybeUninit`] instead. -/// -/// # Examples -/// -/// This wrapper helps with explicitly documenting the drop order dependencies between fields of -/// the type: -/// -/// ```rust -/// use std::mem::ManuallyDrop; -/// struct Peach; -/// struct Banana; -/// struct Melon; -/// struct FruitBox { -/// // Immediately clear there’s something non-trivial going on with these fields. -/// peach: ManuallyDrop, -/// melon: Melon, // Field that’s independent of the other two. -/// banana: ManuallyDrop, -/// } -/// -/// impl Drop for FruitBox { -/// fn drop(&mut self) { -/// unsafe { -/// // Explicit ordering in which field destructors are run specified in the intuitive -/// // location – the destructor of the structure containing the fields. -/// // Moreover, one can now reorder fields within the struct however much they want. -/// ManuallyDrop::drop(&mut self.peach); -/// ManuallyDrop::drop(&mut self.banana); -/// } -/// // After destructor for `FruitBox` runs (this function), the destructor for Melon gets -/// // invoked in the usual manner, as it is not wrapped in `ManuallyDrop`. -/// } -/// } -/// ``` -/// -/// [`mem::zeroed`]: fn.zeroed.html -/// [`MaybeUninit`]: union.MaybeUninit.html -#[stable(feature = "manually_drop", since = "1.20.0")] -#[lang = "manually_drop"] -#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[repr(transparent)] -pub struct ManuallyDrop { - value: T, -} - -impl ManuallyDrop { - /// Wrap a value to be manually dropped. - /// - /// # Examples - /// - /// ```rust - /// use std::mem::ManuallyDrop; - /// ManuallyDrop::new(Box::new(())); - /// ``` - #[stable(feature = "manually_drop", since = "1.20.0")] - #[inline(always)] - pub const fn new(value: T) -> ManuallyDrop { - ManuallyDrop { value } - } - - /// Extracts the value from the `ManuallyDrop` container. - /// - /// This allows the value to be dropped again. - /// - /// # Examples - /// - /// ```rust - /// use std::mem::ManuallyDrop; - /// let x = ManuallyDrop::new(Box::new(())); - /// let _: Box<()> = ManuallyDrop::into_inner(x); // This drops the `Box`. - /// ``` - #[stable(feature = "manually_drop", since = "1.20.0")] - #[inline(always)] - pub const fn into_inner(slot: ManuallyDrop) -> T { - slot.value - } - - /// Takes the contained value out. - /// - /// This method is primarily intended for moving out values in drop. - /// Instead of using [`ManuallyDrop::drop`] to manually drop the value, - /// you can use this method to take the value and use it however desired. - /// `Drop` will be invoked on the returned value following normal end-of-scope rules. - /// - /// If you have ownership of the container, you can use [`ManuallyDrop::into_inner`] instead. - /// - /// # Safety - /// - /// This function semantically moves out the contained value without preventing further usage. - /// It is up to the user of this method to ensure that this container is not used again. - /// - /// [`ManuallyDrop::drop`]: #method.drop - /// [`ManuallyDrop::into_inner`]: #method.into_inner - #[must_use = "if you don't need the value, you can use `ManuallyDrop::drop` instead"] - #[unstable(feature = "manually_drop_take", issue = "55422")] - #[inline] - pub unsafe fn take(slot: &mut ManuallyDrop) -> T { - ManuallyDrop::into_inner(ptr::read(slot)) - } -} - -impl ManuallyDrop { - /// Manually drops the contained value. - /// - /// If you have ownership of the value, you can use [`ManuallyDrop::into_inner`] instead. - /// - /// # Safety - /// - /// This function runs the destructor of the contained value and thus the wrapped value - /// now represents uninitialized data. It is up to the user of this method to ensure the - /// uninitialized data is not actually used. - /// - /// [`ManuallyDrop::into_inner`]: #method.into_inner - #[stable(feature = "manually_drop", since = "1.20.0")] - #[inline] - pub unsafe fn drop(slot: &mut ManuallyDrop) { - ptr::drop_in_place(&mut slot.value) - } -} - -#[stable(feature = "manually_drop", since = "1.20.0")] -impl Deref for ManuallyDrop { - type Target = T; - #[inline(always)] - fn deref(&self) -> &T { - &self.value - } -} - -#[stable(feature = "manually_drop", since = "1.20.0")] -impl DerefMut for ManuallyDrop { - #[inline(always)] - fn deref_mut(&mut self) -> &mut T { - &mut self.value - } -} - -/// A wrapper type to construct uninitialized instances of `T`. -/// -/// # Initialization invariant -/// -/// The compiler, in general, assumes that variables are properly initialized -/// at their respective type. For example, a variable of reference type must -/// be aligned and non-NULL. This is an invariant that must *always* be upheld, -/// even in unsafe code. As a consequence, zero-initializing a variable of reference -/// type causes instantaneous [undefined behavior][ub], no matter whether that reference -/// ever gets used to access memory: -/// -/// ```rust,no_run -/// use std::mem::{self, MaybeUninit}; -/// -/// let x: &i32 = unsafe { mem::zeroed() }; // undefined behavior! -/// // The equivalent code with `MaybeUninit<&i32>`: -/// let x: &i32 = unsafe { MaybeUninit::zeroed().assume_init() }; // undefined behavior! -/// ``` -/// -/// This is exploited by the compiler for various optimizations, such as eliding -/// run-time checks and optimizing `enum` layout. -/// -/// Similarly, entirely uninitialized memory may have any content, while a `bool` must -/// always be `true` or `false`. Hence, creating an uninitialized `bool` is undefined behavior: -/// -/// ```rust,no_run -/// use std::mem::{self, MaybeUninit}; -/// -/// let b: bool = unsafe { mem::uninitialized() }; // undefined behavior! -/// // The equivalent code with `MaybeUninit`: -/// let b: bool = unsafe { MaybeUninit::uninit().assume_init() }; // undefined behavior! -/// ``` -/// -/// Moreover, uninitialized memory is special in that the compiler knows that -/// it does not have a fixed value. This makes it undefined behavior to have -/// uninitialized data in a variable even if that variable has an integer type, -/// which otherwise can hold any *fixed* bit pattern: -/// -/// ```rust,no_run -/// use std::mem::{self, MaybeUninit}; -/// -/// let x: i32 = unsafe { mem::uninitialized() }; // undefined behavior! -/// // The equivalent code with `MaybeUninit`: -/// let x: i32 = unsafe { MaybeUninit::uninit().assume_init() }; // undefined behavior! -/// ``` -/// (Notice that the rules around uninitialized integers are not finalized yet, but -/// until they are, it is advisable to avoid them.) -/// -/// On top of that, remember that most types have additional invariants beyond merely -/// being considered initialized at the type level. For example, a `1`-initialized [`Vec`] -/// is considered initialized because the only requirement the compiler knows about it -/// is that the data pointer must be non-null. Creating such a `Vec` does not cause -/// *immediate* undefined behavior, but will cause undefined behavior with most -/// safe operations (including dropping it). -/// -/// [`Vec`]: ../../std/vec/struct.Vec.html -/// -/// # Examples -/// -/// `MaybeUninit` serves to enable unsafe code to deal with uninitialized data. -/// It is a signal to the compiler indicating that the data here might *not* -/// be initialized: -/// -/// ```rust -/// use std::mem::MaybeUninit; -/// -/// // Create an explicitly uninitialized reference. The compiler knows that data inside -/// // a `MaybeUninit` may be invalid, and hence this is not UB: -/// let mut x = MaybeUninit::<&i32>::uninit(); -/// // Set it to a valid value. -/// unsafe { x.as_mut_ptr().write(&0); } -/// // Extract the initialized data -- this is only allowed *after* properly -/// // initializing `x`! -/// let x = unsafe { x.assume_init() }; -/// ``` -/// -/// The compiler then knows to not make any incorrect assumptions or optimizations on this code. -/// -/// You can think of `MaybeUninit` as being a bit like `Option` but without -/// any of the run-time tracking and without any of the safety checks. -/// -/// ## out-pointers -/// -/// You can use `MaybeUninit` to implement "out-pointers": instead of returning data -/// from a function, pass it a pointer to some (uninitialized) memory to put the -/// result into. This can be useful when it is important for the caller to control -/// how the memory the result is stored in gets allocated, and you want to avoid -/// unnecessary moves. -/// -/// ``` -/// use std::mem::MaybeUninit; -/// -/// unsafe fn make_vec(out: *mut Vec) { -/// // `write` does not drop the old contents, which is important. -/// out.write(vec![1, 2, 3]); -/// } -/// -/// let mut v = MaybeUninit::uninit(); -/// unsafe { make_vec(v.as_mut_ptr()); } -/// // Now we know `v` is initialized! This also makes sure the vector gets -/// // properly dropped. -/// let v = unsafe { v.assume_init() }; -/// assert_eq!(&v, &[1, 2, 3]); -/// ``` -/// -/// ## Initializing an array element-by-element -/// -/// `MaybeUninit` can be used to initialize a large array element-by-element: -/// -/// ``` -/// use std::mem::{self, MaybeUninit}; -/// use std::ptr; -/// -/// let data = { -/// // Create an uninitialized array of `MaybeUninit`. The `assume_init` is -/// // safe because the type we are claiming to have initialized here is a -/// // bunch of `MaybeUninit`s, which do not require initialization. -/// let mut data: [MaybeUninit>; 1000] = unsafe { -/// MaybeUninit::uninit().assume_init() -/// }; -/// -/// // Dropping a `MaybeUninit` does nothing, so if there is a panic during this loop, -/// // we have a memory leak, but there is no memory safety issue. -/// for elem in &mut data[..] { -/// unsafe { ptr::write(elem.as_mut_ptr(), vec![42]); } -/// } -/// -/// // Everything is initialized. Transmute the array to the -/// // initialized type. -/// unsafe { mem::transmute::<_, [Vec; 1000]>(data) } -/// }; -/// -/// assert_eq!(&data[0], &[42]); -/// ``` -/// -/// You can also work with partially initialized arrays, which could -/// be found in low-level datastructures. -/// -/// ``` -/// use std::mem::MaybeUninit; -/// use std::ptr; -/// -/// // Create an uninitialized array of `MaybeUninit`. The `assume_init` is -/// // safe because the type we are claiming to have initialized here is a -/// // bunch of `MaybeUninit`s, which do not require initialization. -/// let mut data: [MaybeUninit; 1000] = unsafe { MaybeUninit::uninit().assume_init() }; -/// // Count the number of elements we have assigned. -/// let mut data_len: usize = 0; -/// -/// for elem in &mut data[0..500] { -/// unsafe { ptr::write(elem.as_mut_ptr(), String::from("hello")); } -/// data_len += 1; -/// } -/// -/// // For each item in the array, drop if we allocated it. -/// for elem in &mut data[0..data_len] { -/// unsafe { ptr::drop_in_place(elem.as_mut_ptr()); } -/// } -/// ``` -/// -/// ## Initializing a struct field-by-field -/// -/// There is currently no supported way to create a raw pointer or reference -/// to a field of a struct inside `MaybeUninit`. That means it is not possible -/// to create a struct by calling `MaybeUninit::uninit::()` and then writing -/// to its fields. -/// -/// [ub]: ../../reference/behavior-considered-undefined.html -/// -/// # Layout -/// -/// `MaybeUninit` is guaranteed to have the same size and alignment as `T`: -/// -/// ```rust -/// use std::mem::{MaybeUninit, size_of, align_of}; -/// assert_eq!(size_of::>(), size_of::()); -/// assert_eq!(align_of::>(), align_of::()); -/// ``` -/// -/// However remember that a type *containing* a `MaybeUninit` is not necessarily the same -/// layout; Rust does not in general guarantee that the fields of a `Foo` have the same order as -/// a `Foo` even if `T` and `U` have the same size and alignment. Furthermore because any bit -/// value is valid for a `MaybeUninit` the compiler can't apply non-zero/niche-filling -/// optimizations, potentially resulting in a larger size: -/// -/// ```rust -/// # use std::mem::{MaybeUninit, size_of}; -/// assert_eq!(size_of::>(), 1); -/// assert_eq!(size_of::>>(), 2); -/// ``` -#[allow(missing_debug_implementations)] -#[stable(feature = "maybe_uninit", since = "1.36.0")] -#[derive(Copy)] -pub union MaybeUninit { - uninit: (), - value: ManuallyDrop, -} - -#[stable(feature = "maybe_uninit", since = "1.36.0")] -impl Clone for MaybeUninit { - #[inline(always)] - fn clone(&self) -> Self { - // Not calling `T::clone()`, we cannot know if we are initialized enough for that. - *self - } -} - -impl MaybeUninit { - /// Creates a new `MaybeUninit` initialized with the given value. - /// It is safe to call [`assume_init`] on the return value of this function. - /// - /// Note that dropping a `MaybeUninit` will never call `T`'s drop code. - /// It is your responsibility to make sure `T` gets dropped if it got initialized. - /// - /// [`assume_init`]: #method.assume_init - #[stable(feature = "maybe_uninit", since = "1.36.0")] - #[inline(always)] - pub const fn new(val: T) -> MaybeUninit { - MaybeUninit { value: ManuallyDrop::new(val) } - } - - /// Creates a new `MaybeUninit` in an uninitialized state. - /// - /// Note that dropping a `MaybeUninit` will never call `T`'s drop code. - /// It is your responsibility to make sure `T` gets dropped if it got initialized. - /// - /// See the [type-level documentation][type] for some examples. - /// - /// [type]: union.MaybeUninit.html - #[stable(feature = "maybe_uninit", since = "1.36.0")] - #[inline(always)] - pub const fn uninit() -> MaybeUninit { - MaybeUninit { uninit: () } - } - - /// Creates a new `MaybeUninit` in an uninitialized state, with the memory being - /// filled with `0` bytes. It depends on `T` whether that already makes for - /// proper initialization. For example, `MaybeUninit::zeroed()` is initialized, - /// but `MaybeUninit<&'static i32>::zeroed()` is not because references must not - /// be null. - /// - /// Note that dropping a `MaybeUninit` will never call `T`'s drop code. - /// It is your responsibility to make sure `T` gets dropped if it got initialized. - /// - /// # Example - /// - /// Correct usage of this function: initializing a struct with zero, where all - /// fields of the struct can hold the bit-pattern 0 as a valid value. - /// - /// ```rust - /// use std::mem::MaybeUninit; - /// - /// let x = MaybeUninit::<(u8, bool)>::zeroed(); - /// let x = unsafe { x.assume_init() }; - /// assert_eq!(x, (0, false)); - /// ``` - /// - /// *Incorrect* usage of this function: initializing a struct with zero, where some fields - /// cannot hold 0 as a valid value. - /// - /// ```rust,no_run - /// use std::mem::MaybeUninit; - /// - /// enum NotZero { One = 1, Two = 2 }; - /// - /// let x = MaybeUninit::<(u8, NotZero)>::zeroed(); - /// let x = unsafe { x.assume_init() }; - /// // Inside a pair, we create a `NotZero` that does not have a valid discriminant. - /// // This is undefined behavior. - /// ``` - #[stable(feature = "maybe_uninit", since = "1.36.0")] - #[inline] - pub fn zeroed() -> MaybeUninit { - let mut u = MaybeUninit::::uninit(); - unsafe { - u.as_mut_ptr().write_bytes(0u8, 1); - } - u - } - - /// Sets the value of the `MaybeUninit`. This overwrites any previous value - /// without dropping it, so be careful not to use this twice unless you want to - /// skip running the destructor. For your convenience, this also returns a mutable - /// reference to the (now safely initialized) contents of `self`. - #[unstable(feature = "maybe_uninit_extra", issue = "53491")] - #[inline(always)] - pub fn write(&mut self, val: T) -> &mut T { - unsafe { - self.value = ManuallyDrop::new(val); - self.get_mut() - } - } - - /// Gets a pointer to the contained value. Reading from this pointer or turning it - /// into a reference is undefined behavior unless the `MaybeUninit` is initialized. - /// Writing to memory that this pointer (non-transitively) points to is undefined behavior - /// (except inside an `UnsafeCell`). - /// - /// # Examples - /// - /// Correct usage of this method: - /// - /// ```rust - /// use std::mem::MaybeUninit; - /// - /// let mut x = MaybeUninit::>::uninit(); - /// unsafe { x.as_mut_ptr().write(vec![0,1,2]); } - /// // Create a reference into the `MaybeUninit`. This is okay because we initialized it. - /// let x_vec = unsafe { &*x.as_ptr() }; - /// assert_eq!(x_vec.len(), 3); - /// ``` - /// - /// *Incorrect* usage of this method: - /// - /// ```rust,no_run - /// use std::mem::MaybeUninit; - /// - /// let x = MaybeUninit::>::uninit(); - /// let x_vec = unsafe { &*x.as_ptr() }; - /// // We have created a reference to an uninitialized vector! This is undefined behavior. - /// ``` - /// - /// (Notice that the rules around references to uninitialized data are not finalized yet, but - /// until they are, it is advisable to avoid them.) - #[stable(feature = "maybe_uninit", since = "1.36.0")] - #[inline(always)] - pub fn as_ptr(&self) -> *const T { - unsafe { &*self.value as *const T } - } - - /// Gets a mutable pointer to the contained value. Reading from this pointer or turning it - /// into a reference is undefined behavior unless the `MaybeUninit` is initialized. - /// - /// # Examples - /// - /// Correct usage of this method: - /// - /// ```rust - /// use std::mem::MaybeUninit; - /// - /// let mut x = MaybeUninit::>::uninit(); - /// unsafe { x.as_mut_ptr().write(vec![0,1,2]); } - /// // Create a reference into the `MaybeUninit>`. - /// // This is okay because we initialized it. - /// let x_vec = unsafe { &mut *x.as_mut_ptr() }; - /// x_vec.push(3); - /// assert_eq!(x_vec.len(), 4); - /// ``` - /// - /// *Incorrect* usage of this method: - /// - /// ```rust,no_run - /// use std::mem::MaybeUninit; - /// - /// let mut x = MaybeUninit::>::uninit(); - /// let x_vec = unsafe { &mut *x.as_mut_ptr() }; - /// // We have created a reference to an uninitialized vector! This is undefined behavior. - /// ``` - /// - /// (Notice that the rules around references to uninitialized data are not finalized yet, but - /// until they are, it is advisable to avoid them.) - #[stable(feature = "maybe_uninit", since = "1.36.0")] - #[inline(always)] - pub fn as_mut_ptr(&mut self) -> *mut T { - unsafe { &mut *self.value as *mut T } - } - - /// Extracts the value from the `MaybeUninit` container. This is a great way - /// to ensure that the data will get dropped, because the resulting `T` is - /// subject to the usual drop handling. - /// - /// # Safety - /// - /// It is up to the caller to guarantee that the `MaybeUninit` really is in an initialized - /// state. Calling this when the content is not yet fully initialized causes immediate undefined - /// behavior. The [type-level documentation][inv] contains more information about - /// this initialization invariant. - /// - /// [inv]: #initialization-invariant - /// - /// # Examples - /// - /// Correct usage of this method: - /// - /// ```rust - /// use std::mem::MaybeUninit; - /// - /// let mut x = MaybeUninit::::uninit(); - /// unsafe { x.as_mut_ptr().write(true); } - /// let x_init = unsafe { x.assume_init() }; - /// assert_eq!(x_init, true); - /// ``` - /// - /// *Incorrect* usage of this method: - /// - /// ```rust,no_run - /// use std::mem::MaybeUninit; - /// - /// let x = MaybeUninit::>::uninit(); - /// let x_init = unsafe { x.assume_init() }; - /// // `x` had not been initialized yet, so this last line caused undefined behavior. - /// ``` - #[stable(feature = "maybe_uninit", since = "1.36.0")] - #[inline(always)] - pub unsafe fn assume_init(self) -> T { - intrinsics::panic_if_uninhabited::(); - ManuallyDrop::into_inner(self.value) - } - - /// Reads the value from the `MaybeUninit` container. The resulting `T` is subject - /// to the usual drop handling. - /// - /// Whenever possible, it is preferrable to use [`assume_init`] instead, which - /// prevents duplicating the content of the `MaybeUninit`. - /// - /// # Safety - /// - /// It is up to the caller to guarantee that the `MaybeUninit` really is in an initialized - /// state. Calling this when the content is not yet fully initialized causes undefined - /// behavior. The [type-level documentation][inv] contains more information about - /// this initialization invariant. - /// - /// Moreover, this leaves a copy of the same data behind in the `MaybeUninit`. When using - /// multiple copies of the data (by calling `read` multiple times, or first - /// calling `read` and then [`assume_init`]), it is your responsibility - /// to ensure that that data may indeed be duplicated. - /// - /// [inv]: #initialization-invariant - /// [`assume_init`]: #method.assume_init - /// - /// # Examples - /// - /// Correct usage of this method: - /// - /// ```rust - /// #![feature(maybe_uninit_extra)] - /// use std::mem::MaybeUninit; - /// - /// let mut x = MaybeUninit::::uninit(); - /// x.write(13); - /// let x1 = unsafe { x.read() }; - /// // `u32` is `Copy`, so we may read multiple times. - /// let x2 = unsafe { x.read() }; - /// assert_eq!(x1, x2); - /// - /// let mut x = MaybeUninit::>>::uninit(); - /// x.write(None); - /// let x1 = unsafe { x.read() }; - /// // Duplicating a `None` value is okay, so we may read multiple times. - /// let x2 = unsafe { x.read() }; - /// assert_eq!(x1, x2); - /// ``` - /// - /// *Incorrect* usage of this method: - /// - /// ```rust,no_run - /// #![feature(maybe_uninit_extra)] - /// use std::mem::MaybeUninit; - /// - /// let mut x = MaybeUninit::>>::uninit(); - /// x.write(Some(vec![0,1,2])); - /// let x1 = unsafe { x.read() }; - /// let x2 = unsafe { x.read() }; - /// // We now created two copies of the same vector, leading to a double-free when - /// // they both get dropped! - /// ``` - #[unstable(feature = "maybe_uninit_extra", issue = "53491")] - #[inline(always)] - pub unsafe fn read(&self) -> T { - intrinsics::panic_if_uninhabited::(); - self.as_ptr().read() - } - - /// Gets a reference to the contained value. - /// - /// # Safety - /// - /// It is up to the caller to guarantee that the `MaybeUninit` really is in an initialized - /// state. Calling this when the content is not yet fully initialized causes undefined - /// behavior. - #[unstable(feature = "maybe_uninit_ref", issue = "53491")] - #[inline(always)] - pub unsafe fn get_ref(&self) -> &T { - &*self.value - } - - /// Gets a mutable reference to the contained value. - /// - /// # Safety - /// - /// It is up to the caller to guarantee that the `MaybeUninit` really is in an initialized - /// state. Calling this when the content is not yet fully initialized causes undefined - /// behavior. - // FIXME(#53491): We currently rely on the above being incorrect, i.e., we have references - // to uninitialized data (e.g., in `libcore/fmt/float.rs`). We should make - // a final decision about the rules before stabilization. - #[unstable(feature = "maybe_uninit_ref", issue = "53491")] - #[inline(always)] - pub unsafe fn get_mut(&mut self) -> &mut T { - &mut *self.value - } - - /// Gets a pointer to the first element of the array. - #[unstable(feature = "maybe_uninit_slice", issue = "53491")] - #[inline(always)] - pub fn first_ptr(this: &[MaybeUninit]) -> *const T { - this as *const [MaybeUninit] as *const T - } - - /// Gets a mutable pointer to the first element of the array. - #[unstable(feature = "maybe_uninit_slice", issue = "53491")] - #[inline(always)] - pub fn first_ptr_mut(this: &mut [MaybeUninit]) -> *mut T { - this as *mut [MaybeUninit] as *mut T - } -} diff --git a/src/libcore/mem/manually_drop.rs b/src/libcore/mem/manually_drop.rs new file mode 100644 index 0000000000000..3ad1223e331ec --- /dev/null +++ b/src/libcore/mem/manually_drop.rs @@ -0,0 +1,146 @@ +use crate::ptr; +use crate::ops::{Deref, DerefMut}; + +/// A wrapper to inhibit compiler from automatically calling `T`’s destructor. +/// +/// This wrapper is 0-cost. +/// +/// `ManuallyDrop` is subject to the same layout optimizations as `T`. +/// As a consequence, it has *no effect* on the assumptions that the compiler makes +/// about all values being initialized at their type. In particular, initializing +/// a `ManuallyDrop<&mut T>` with [`mem::zeroed`] is undefined behavior. +/// If you need to handle uninitialized data, use [`MaybeUninit`] instead. +/// +/// # Examples +/// +/// This wrapper helps with explicitly documenting the drop order dependencies between fields of +/// the type: +/// +/// ```rust +/// use std::mem::ManuallyDrop; +/// struct Peach; +/// struct Banana; +/// struct Melon; +/// struct FruitBox { +/// // Immediately clear there’s something non-trivial going on with these fields. +/// peach: ManuallyDrop, +/// melon: Melon, // Field that’s independent of the other two. +/// banana: ManuallyDrop, +/// } +/// +/// impl Drop for FruitBox { +/// fn drop(&mut self) { +/// unsafe { +/// // Explicit ordering in which field destructors are run specified in the intuitive +/// // location – the destructor of the structure containing the fields. +/// // Moreover, one can now reorder fields within the struct however much they want. +/// ManuallyDrop::drop(&mut self.peach); +/// ManuallyDrop::drop(&mut self.banana); +/// } +/// // After destructor for `FruitBox` runs (this function), the destructor for Melon gets +/// // invoked in the usual manner, as it is not wrapped in `ManuallyDrop`. +/// } +/// } +/// ``` +/// +/// [`mem::zeroed`]: fn.zeroed.html +/// [`MaybeUninit`]: union.MaybeUninit.html +#[stable(feature = "manually_drop", since = "1.20.0")] +#[lang = "manually_drop"] +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(transparent)] +pub struct ManuallyDrop { + value: T, +} + +impl ManuallyDrop { + /// Wrap a value to be manually dropped. + /// + /// # Examples + /// + /// ```rust + /// use std::mem::ManuallyDrop; + /// ManuallyDrop::new(Box::new(())); + /// ``` + #[stable(feature = "manually_drop", since = "1.20.0")] + #[inline(always)] + pub const fn new(value: T) -> ManuallyDrop { + ManuallyDrop { value } + } + + /// Extracts the value from the `ManuallyDrop` container. + /// + /// This allows the value to be dropped again. + /// + /// # Examples + /// + /// ```rust + /// use std::mem::ManuallyDrop; + /// let x = ManuallyDrop::new(Box::new(())); + /// let _: Box<()> = ManuallyDrop::into_inner(x); // This drops the `Box`. + /// ``` + #[stable(feature = "manually_drop", since = "1.20.0")] + #[inline(always)] + pub const fn into_inner(slot: ManuallyDrop) -> T { + slot.value + } + + /// Takes the contained value out. + /// + /// This method is primarily intended for moving out values in drop. + /// Instead of using [`ManuallyDrop::drop`] to manually drop the value, + /// you can use this method to take the value and use it however desired. + /// `Drop` will be invoked on the returned value following normal end-of-scope rules. + /// + /// If you have ownership of the container, you can use [`ManuallyDrop::into_inner`] instead. + /// + /// # Safety + /// + /// This function semantically moves out the contained value without preventing further usage. + /// It is up to the user of this method to ensure that this container is not used again. + /// + /// [`ManuallyDrop::drop`]: #method.drop + /// [`ManuallyDrop::into_inner`]: #method.into_inner + #[must_use = "if you don't need the value, you can use `ManuallyDrop::drop` instead"] + #[unstable(feature = "manually_drop_take", issue = "55422")] + #[inline] + pub unsafe fn take(slot: &mut ManuallyDrop) -> T { + ManuallyDrop::into_inner(ptr::read(slot)) + } +} + +impl ManuallyDrop { + /// Manually drops the contained value. + /// + /// If you have ownership of the value, you can use [`ManuallyDrop::into_inner`] instead. + /// + /// # Safety + /// + /// This function runs the destructor of the contained value and thus the wrapped value + /// now represents uninitialized data. It is up to the user of this method to ensure the + /// uninitialized data is not actually used. + /// + /// [`ManuallyDrop::into_inner`]: #method.into_inner + #[stable(feature = "manually_drop", since = "1.20.0")] + #[inline] + pub unsafe fn drop(slot: &mut ManuallyDrop) { + ptr::drop_in_place(&mut slot.value) + } +} + +#[stable(feature = "manually_drop", since = "1.20.0")] +impl Deref for ManuallyDrop { + type Target = T; + #[inline(always)] + fn deref(&self) -> &T { + &self.value + } +} + +#[stable(feature = "manually_drop", since = "1.20.0")] +impl DerefMut for ManuallyDrop { + #[inline(always)] + fn deref_mut(&mut self) -> &mut T { + &mut self.value + } +} diff --git a/src/libcore/mem/maybe_uninit.rs b/src/libcore/mem/maybe_uninit.rs new file mode 100644 index 0000000000000..eeff9d0303a3b --- /dev/null +++ b/src/libcore/mem/maybe_uninit.rs @@ -0,0 +1,519 @@ +use crate::intrinsics; +use crate::mem::ManuallyDrop; + +/// A wrapper type to construct uninitialized instances of `T`. +/// +/// # Initialization invariant +/// +/// The compiler, in general, assumes that variables are properly initialized +/// at their respective type. For example, a variable of reference type must +/// be aligned and non-NULL. This is an invariant that must *always* be upheld, +/// even in unsafe code. As a consequence, zero-initializing a variable of reference +/// type causes instantaneous [undefined behavior][ub], no matter whether that reference +/// ever gets used to access memory: +/// +/// ```rust,no_run +/// use std::mem::{self, MaybeUninit}; +/// +/// let x: &i32 = unsafe { mem::zeroed() }; // undefined behavior! +/// // The equivalent code with `MaybeUninit<&i32>`: +/// let x: &i32 = unsafe { MaybeUninit::zeroed().assume_init() }; // undefined behavior! +/// ``` +/// +/// This is exploited by the compiler for various optimizations, such as eliding +/// run-time checks and optimizing `enum` layout. +/// +/// Similarly, entirely uninitialized memory may have any content, while a `bool` must +/// always be `true` or `false`. Hence, creating an uninitialized `bool` is undefined behavior: +/// +/// ```rust,no_run +/// use std::mem::{self, MaybeUninit}; +/// +/// let b: bool = unsafe { mem::uninitialized() }; // undefined behavior! +/// // The equivalent code with `MaybeUninit`: +/// let b: bool = unsafe { MaybeUninit::uninit().assume_init() }; // undefined behavior! +/// ``` +/// +/// Moreover, uninitialized memory is special in that the compiler knows that +/// it does not have a fixed value. This makes it undefined behavior to have +/// uninitialized data in a variable even if that variable has an integer type, +/// which otherwise can hold any *fixed* bit pattern: +/// +/// ```rust,no_run +/// use std::mem::{self, MaybeUninit}; +/// +/// let x: i32 = unsafe { mem::uninitialized() }; // undefined behavior! +/// // The equivalent code with `MaybeUninit`: +/// let x: i32 = unsafe { MaybeUninit::uninit().assume_init() }; // undefined behavior! +/// ``` +/// (Notice that the rules around uninitialized integers are not finalized yet, but +/// until they are, it is advisable to avoid them.) +/// +/// On top of that, remember that most types have additional invariants beyond merely +/// being considered initialized at the type level. For example, a `1`-initialized [`Vec`] +/// is considered initialized because the only requirement the compiler knows about it +/// is that the data pointer must be non-null. Creating such a `Vec` does not cause +/// *immediate* undefined behavior, but will cause undefined behavior with most +/// safe operations (including dropping it). +/// +/// [`Vec`]: ../../std/vec/struct.Vec.html +/// +/// # Examples +/// +/// `MaybeUninit` serves to enable unsafe code to deal with uninitialized data. +/// It is a signal to the compiler indicating that the data here might *not* +/// be initialized: +/// +/// ```rust +/// use std::mem::MaybeUninit; +/// +/// // Create an explicitly uninitialized reference. The compiler knows that data inside +/// // a `MaybeUninit` may be invalid, and hence this is not UB: +/// let mut x = MaybeUninit::<&i32>::uninit(); +/// // Set it to a valid value. +/// unsafe { x.as_mut_ptr().write(&0); } +/// // Extract the initialized data -- this is only allowed *after* properly +/// // initializing `x`! +/// let x = unsafe { x.assume_init() }; +/// ``` +/// +/// The compiler then knows to not make any incorrect assumptions or optimizations on this code. +/// +/// You can think of `MaybeUninit` as being a bit like `Option` but without +/// any of the run-time tracking and without any of the safety checks. +/// +/// ## out-pointers +/// +/// You can use `MaybeUninit` to implement "out-pointers": instead of returning data +/// from a function, pass it a pointer to some (uninitialized) memory to put the +/// result into. This can be useful when it is important for the caller to control +/// how the memory the result is stored in gets allocated, and you want to avoid +/// unnecessary moves. +/// +/// ``` +/// use std::mem::MaybeUninit; +/// +/// unsafe fn make_vec(out: *mut Vec) { +/// // `write` does not drop the old contents, which is important. +/// out.write(vec![1, 2, 3]); +/// } +/// +/// let mut v = MaybeUninit::uninit(); +/// unsafe { make_vec(v.as_mut_ptr()); } +/// // Now we know `v` is initialized! This also makes sure the vector gets +/// // properly dropped. +/// let v = unsafe { v.assume_init() }; +/// assert_eq!(&v, &[1, 2, 3]); +/// ``` +/// +/// ## Initializing an array element-by-element +/// +/// `MaybeUninit` can be used to initialize a large array element-by-element: +/// +/// ``` +/// use std::mem::{self, MaybeUninit}; +/// use std::ptr; +/// +/// let data = { +/// // Create an uninitialized array of `MaybeUninit`. The `assume_init` is +/// // safe because the type we are claiming to have initialized here is a +/// // bunch of `MaybeUninit`s, which do not require initialization. +/// let mut data: [MaybeUninit>; 1000] = unsafe { +/// MaybeUninit::uninit().assume_init() +/// }; +/// +/// // Dropping a `MaybeUninit` does nothing, so if there is a panic during this loop, +/// // we have a memory leak, but there is no memory safety issue. +/// for elem in &mut data[..] { +/// unsafe { ptr::write(elem.as_mut_ptr(), vec![42]); } +/// } +/// +/// // Everything is initialized. Transmute the array to the +/// // initialized type. +/// unsafe { mem::transmute::<_, [Vec; 1000]>(data) } +/// }; +/// +/// assert_eq!(&data[0], &[42]); +/// ``` +/// +/// You can also work with partially initialized arrays, which could +/// be found in low-level datastructures. +/// +/// ``` +/// use std::mem::MaybeUninit; +/// use std::ptr; +/// +/// // Create an uninitialized array of `MaybeUninit`. The `assume_init` is +/// // safe because the type we are claiming to have initialized here is a +/// // bunch of `MaybeUninit`s, which do not require initialization. +/// let mut data: [MaybeUninit; 1000] = unsafe { MaybeUninit::uninit().assume_init() }; +/// // Count the number of elements we have assigned. +/// let mut data_len: usize = 0; +/// +/// for elem in &mut data[0..500] { +/// unsafe { ptr::write(elem.as_mut_ptr(), String::from("hello")); } +/// data_len += 1; +/// } +/// +/// // For each item in the array, drop if we allocated it. +/// for elem in &mut data[0..data_len] { +/// unsafe { ptr::drop_in_place(elem.as_mut_ptr()); } +/// } +/// ``` +/// +/// ## Initializing a struct field-by-field +/// +/// There is currently no supported way to create a raw pointer or reference +/// to a field of a struct inside `MaybeUninit`. That means it is not possible +/// to create a struct by calling `MaybeUninit::uninit::()` and then writing +/// to its fields. +/// +/// [ub]: ../../reference/behavior-considered-undefined.html +/// +/// # Layout +/// +/// `MaybeUninit` is guaranteed to have the same size and alignment as `T`: +/// +/// ```rust +/// use std::mem::{MaybeUninit, size_of, align_of}; +/// assert_eq!(size_of::>(), size_of::()); +/// assert_eq!(align_of::>(), align_of::()); +/// ``` +/// +/// However remember that a type *containing* a `MaybeUninit` is not necessarily the same +/// layout; Rust does not in general guarantee that the fields of a `Foo` have the same order as +/// a `Foo` even if `T` and `U` have the same size and alignment. Furthermore because any bit +/// value is valid for a `MaybeUninit` the compiler can't apply non-zero/niche-filling +/// optimizations, potentially resulting in a larger size: +/// +/// ```rust +/// # use std::mem::{MaybeUninit, size_of}; +/// assert_eq!(size_of::>(), 1); +/// assert_eq!(size_of::>>(), 2); +/// ``` +#[allow(missing_debug_implementations)] +#[stable(feature = "maybe_uninit", since = "1.36.0")] +#[derive(Copy)] +pub union MaybeUninit { + uninit: (), + value: ManuallyDrop, +} + +#[stable(feature = "maybe_uninit", since = "1.36.0")] +impl Clone for MaybeUninit { + #[inline(always)] + fn clone(&self) -> Self { + // Not calling `T::clone()`, we cannot know if we are initialized enough for that. + *self + } +} + +impl MaybeUninit { + /// Creates a new `MaybeUninit` initialized with the given value. + /// It is safe to call [`assume_init`] on the return value of this function. + /// + /// Note that dropping a `MaybeUninit` will never call `T`'s drop code. + /// It is your responsibility to make sure `T` gets dropped if it got initialized. + /// + /// [`assume_init`]: #method.assume_init + #[stable(feature = "maybe_uninit", since = "1.36.0")] + #[inline(always)] + pub const fn new(val: T) -> MaybeUninit { + MaybeUninit { value: ManuallyDrop::new(val) } + } + + /// Creates a new `MaybeUninit` in an uninitialized state. + /// + /// Note that dropping a `MaybeUninit` will never call `T`'s drop code. + /// It is your responsibility to make sure `T` gets dropped if it got initialized. + /// + /// See the [type-level documentation][type] for some examples. + /// + /// [type]: union.MaybeUninit.html + #[stable(feature = "maybe_uninit", since = "1.36.0")] + #[inline(always)] + pub const fn uninit() -> MaybeUninit { + MaybeUninit { uninit: () } + } + + /// Creates a new `MaybeUninit` in an uninitialized state, with the memory being + /// filled with `0` bytes. It depends on `T` whether that already makes for + /// proper initialization. For example, `MaybeUninit::zeroed()` is initialized, + /// but `MaybeUninit<&'static i32>::zeroed()` is not because references must not + /// be null. + /// + /// Note that dropping a `MaybeUninit` will never call `T`'s drop code. + /// It is your responsibility to make sure `T` gets dropped if it got initialized. + /// + /// # Example + /// + /// Correct usage of this function: initializing a struct with zero, where all + /// fields of the struct can hold the bit-pattern 0 as a valid value. + /// + /// ```rust + /// use std::mem::MaybeUninit; + /// + /// let x = MaybeUninit::<(u8, bool)>::zeroed(); + /// let x = unsafe { x.assume_init() }; + /// assert_eq!(x, (0, false)); + /// ``` + /// + /// *Incorrect* usage of this function: initializing a struct with zero, where some fields + /// cannot hold 0 as a valid value. + /// + /// ```rust,no_run + /// use std::mem::MaybeUninit; + /// + /// enum NotZero { One = 1, Two = 2 }; + /// + /// let x = MaybeUninit::<(u8, NotZero)>::zeroed(); + /// let x = unsafe { x.assume_init() }; + /// // Inside a pair, we create a `NotZero` that does not have a valid discriminant. + /// // This is undefined behavior. + /// ``` + #[stable(feature = "maybe_uninit", since = "1.36.0")] + #[inline] + pub fn zeroed() -> MaybeUninit { + let mut u = MaybeUninit::::uninit(); + unsafe { + u.as_mut_ptr().write_bytes(0u8, 1); + } + u + } + + /// Sets the value of the `MaybeUninit`. This overwrites any previous value + /// without dropping it, so be careful not to use this twice unless you want to + /// skip running the destructor. For your convenience, this also returns a mutable + /// reference to the (now safely initialized) contents of `self`. + #[unstable(feature = "maybe_uninit_extra", issue = "53491")] + #[inline(always)] + pub fn write(&mut self, val: T) -> &mut T { + unsafe { + self.value = ManuallyDrop::new(val); + self.get_mut() + } + } + + /// Gets a pointer to the contained value. Reading from this pointer or turning it + /// into a reference is undefined behavior unless the `MaybeUninit` is initialized. + /// Writing to memory that this pointer (non-transitively) points to is undefined behavior + /// (except inside an `UnsafeCell`). + /// + /// # Examples + /// + /// Correct usage of this method: + /// + /// ```rust + /// use std::mem::MaybeUninit; + /// + /// let mut x = MaybeUninit::>::uninit(); + /// unsafe { x.as_mut_ptr().write(vec![0,1,2]); } + /// // Create a reference into the `MaybeUninit`. This is okay because we initialized it. + /// let x_vec = unsafe { &*x.as_ptr() }; + /// assert_eq!(x_vec.len(), 3); + /// ``` + /// + /// *Incorrect* usage of this method: + /// + /// ```rust,no_run + /// use std::mem::MaybeUninit; + /// + /// let x = MaybeUninit::>::uninit(); + /// let x_vec = unsafe { &*x.as_ptr() }; + /// // We have created a reference to an uninitialized vector! This is undefined behavior. + /// ``` + /// + /// (Notice that the rules around references to uninitialized data are not finalized yet, but + /// until they are, it is advisable to avoid them.) + #[stable(feature = "maybe_uninit", since = "1.36.0")] + #[inline(always)] + pub fn as_ptr(&self) -> *const T { + unsafe { &*self.value as *const T } + } + + /// Gets a mutable pointer to the contained value. Reading from this pointer or turning it + /// into a reference is undefined behavior unless the `MaybeUninit` is initialized. + /// + /// # Examples + /// + /// Correct usage of this method: + /// + /// ```rust + /// use std::mem::MaybeUninit; + /// + /// let mut x = MaybeUninit::>::uninit(); + /// unsafe { x.as_mut_ptr().write(vec![0,1,2]); } + /// // Create a reference into the `MaybeUninit>`. + /// // This is okay because we initialized it. + /// let x_vec = unsafe { &mut *x.as_mut_ptr() }; + /// x_vec.push(3); + /// assert_eq!(x_vec.len(), 4); + /// ``` + /// + /// *Incorrect* usage of this method: + /// + /// ```rust,no_run + /// use std::mem::MaybeUninit; + /// + /// let mut x = MaybeUninit::>::uninit(); + /// let x_vec = unsafe { &mut *x.as_mut_ptr() }; + /// // We have created a reference to an uninitialized vector! This is undefined behavior. + /// ``` + /// + /// (Notice that the rules around references to uninitialized data are not finalized yet, but + /// until they are, it is advisable to avoid them.) + #[stable(feature = "maybe_uninit", since = "1.36.0")] + #[inline(always)] + pub fn as_mut_ptr(&mut self) -> *mut T { + unsafe { &mut *self.value as *mut T } + } + + /// Extracts the value from the `MaybeUninit` container. This is a great way + /// to ensure that the data will get dropped, because the resulting `T` is + /// subject to the usual drop handling. + /// + /// # Safety + /// + /// It is up to the caller to guarantee that the `MaybeUninit` really is in an initialized + /// state. Calling this when the content is not yet fully initialized causes immediate undefined + /// behavior. The [type-level documentation][inv] contains more information about + /// this initialization invariant. + /// + /// [inv]: #initialization-invariant + /// + /// # Examples + /// + /// Correct usage of this method: + /// + /// ```rust + /// use std::mem::MaybeUninit; + /// + /// let mut x = MaybeUninit::::uninit(); + /// unsafe { x.as_mut_ptr().write(true); } + /// let x_init = unsafe { x.assume_init() }; + /// assert_eq!(x_init, true); + /// ``` + /// + /// *Incorrect* usage of this method: + /// + /// ```rust,no_run + /// use std::mem::MaybeUninit; + /// + /// let x = MaybeUninit::>::uninit(); + /// let x_init = unsafe { x.assume_init() }; + /// // `x` had not been initialized yet, so this last line caused undefined behavior. + /// ``` + #[stable(feature = "maybe_uninit", since = "1.36.0")] + #[inline(always)] + pub unsafe fn assume_init(self) -> T { + intrinsics::panic_if_uninhabited::(); + ManuallyDrop::into_inner(self.value) + } + + /// Reads the value from the `MaybeUninit` container. The resulting `T` is subject + /// to the usual drop handling. + /// + /// Whenever possible, it is preferrable to use [`assume_init`] instead, which + /// prevents duplicating the content of the `MaybeUninit`. + /// + /// # Safety + /// + /// It is up to the caller to guarantee that the `MaybeUninit` really is in an initialized + /// state. Calling this when the content is not yet fully initialized causes undefined + /// behavior. The [type-level documentation][inv] contains more information about + /// this initialization invariant. + /// + /// Moreover, this leaves a copy of the same data behind in the `MaybeUninit`. When using + /// multiple copies of the data (by calling `read` multiple times, or first + /// calling `read` and then [`assume_init`]), it is your responsibility + /// to ensure that that data may indeed be duplicated. + /// + /// [inv]: #initialization-invariant + /// [`assume_init`]: #method.assume_init + /// + /// # Examples + /// + /// Correct usage of this method: + /// + /// ```rust + /// #![feature(maybe_uninit_extra)] + /// use std::mem::MaybeUninit; + /// + /// let mut x = MaybeUninit::::uninit(); + /// x.write(13); + /// let x1 = unsafe { x.read() }; + /// // `u32` is `Copy`, so we may read multiple times. + /// let x2 = unsafe { x.read() }; + /// assert_eq!(x1, x2); + /// + /// let mut x = MaybeUninit::>>::uninit(); + /// x.write(None); + /// let x1 = unsafe { x.read() }; + /// // Duplicating a `None` value is okay, so we may read multiple times. + /// let x2 = unsafe { x.read() }; + /// assert_eq!(x1, x2); + /// ``` + /// + /// *Incorrect* usage of this method: + /// + /// ```rust,no_run + /// #![feature(maybe_uninit_extra)] + /// use std::mem::MaybeUninit; + /// + /// let mut x = MaybeUninit::>>::uninit(); + /// x.write(Some(vec![0,1,2])); + /// let x1 = unsafe { x.read() }; + /// let x2 = unsafe { x.read() }; + /// // We now created two copies of the same vector, leading to a double-free when + /// // they both get dropped! + /// ``` + #[unstable(feature = "maybe_uninit_extra", issue = "53491")] + #[inline(always)] + pub unsafe fn read(&self) -> T { + intrinsics::panic_if_uninhabited::(); + self.as_ptr().read() + } + + /// Gets a reference to the contained value. + /// + /// # Safety + /// + /// It is up to the caller to guarantee that the `MaybeUninit` really is in an initialized + /// state. Calling this when the content is not yet fully initialized causes undefined + /// behavior. + #[unstable(feature = "maybe_uninit_ref", issue = "53491")] + #[inline(always)] + pub unsafe fn get_ref(&self) -> &T { + &*self.value + } + + /// Gets a mutable reference to the contained value. + /// + /// # Safety + /// + /// It is up to the caller to guarantee that the `MaybeUninit` really is in an initialized + /// state. Calling this when the content is not yet fully initialized causes undefined + /// behavior. + // FIXME(#53491): We currently rely on the above being incorrect, i.e., we have references + // to uninitialized data (e.g., in `libcore/fmt/float.rs`). We should make + // a final decision about the rules before stabilization. + #[unstable(feature = "maybe_uninit_ref", issue = "53491")] + #[inline(always)] + pub unsafe fn get_mut(&mut self) -> &mut T { + &mut *self.value + } + + /// Gets a pointer to the first element of the array. + #[unstable(feature = "maybe_uninit_slice", issue = "53491")] + #[inline(always)] + pub fn first_ptr(this: &[MaybeUninit]) -> *const T { + this as *const [MaybeUninit] as *const T + } + + /// Gets a mutable pointer to the first element of the array. + #[unstable(feature = "maybe_uninit_slice", issue = "53491")] + #[inline(always)] + pub fn first_ptr_mut(this: &mut [MaybeUninit]) -> *mut T { + this as *mut [MaybeUninit] as *mut T + } +} diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs new file mode 100644 index 0000000000000..91449f09936aa --- /dev/null +++ b/src/libcore/mem/mod.rs @@ -0,0 +1,752 @@ +//! Basic functions for dealing with memory. +//! +//! This module contains functions for querying the size and alignment of +//! types, initializing and manipulating memory. + +#![stable(feature = "rust1", since = "1.0.0")] + +use crate::clone; +use crate::cmp; +use crate::fmt; +use crate::hash; +use crate::intrinsics; +use crate::marker::{Copy, PhantomData, Sized}; +use crate::ptr; + +mod manually_drop; +#[stable(feature = "manually_drop", since = "1.20.0")] +pub use manually_drop::ManuallyDrop; + +mod maybe_uninit; +#[stable(feature = "maybe_uninit", since = "1.36.0")] +pub use maybe_uninit::MaybeUninit; + +#[stable(feature = "rust1", since = "1.0.0")] +#[doc(inline)] +pub use crate::intrinsics::transmute; + +/// Takes ownership and "forgets" about the value **without running its destructor**. +/// +/// Any resources the value manages, such as heap memory or a file handle, will linger +/// forever in an unreachable state. However, it does not guarantee that pointers +/// to this memory will remain valid. +/// +/// * If you want to leak memory, see [`Box::leak`][leak]. +/// * If you want to obtain a raw pointer to the memory, see [`Box::into_raw`][into_raw]. +/// * If you want to dispose of a value properly, running its destructor, see +/// [`mem::drop`][drop]. +/// +/// # Safety +/// +/// `forget` is not marked as `unsafe`, because Rust's safety guarantees +/// do not include a guarantee that destructors will always run. For example, +/// a program can create a reference cycle using [`Rc`][rc], or call +/// [`process::exit`][exit] to exit without running destructors. Thus, allowing +/// `mem::forget` from safe code does not fundamentally change Rust's safety +/// guarantees. +/// +/// That said, leaking resources such as memory or I/O objects is usually undesirable, +/// so `forget` is only recommended for specialized use cases like those shown below. +/// +/// Because forgetting a value is allowed, any `unsafe` code you write must +/// allow for this possibility. You cannot return a value and expect that the +/// caller will necessarily run the value's destructor. +/// +/// [rc]: ../../std/rc/struct.Rc.html +/// [exit]: ../../std/process/fn.exit.html +/// +/// # Examples +/// +/// Leak an I/O object, never closing the file: +/// +/// ```no_run +/// use std::mem; +/// use std::fs::File; +/// +/// let file = File::open("foo.txt").unwrap(); +/// mem::forget(file); +/// ``` +/// +/// The practical use cases for `forget` are rather specialized and mainly come +/// up in unsafe or FFI code. +/// +/// [drop]: fn.drop.html +/// [uninit]: fn.uninitialized.html +/// [clone]: ../clone/trait.Clone.html +/// [swap]: fn.swap.html +/// [box]: ../../std/boxed/struct.Box.html +/// [leak]: ../../std/boxed/struct.Box.html#method.leak +/// [into_raw]: ../../std/boxed/struct.Box.html#method.into_raw +/// [ub]: ../../reference/behavior-considered-undefined.html +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub fn forget(t: T) { + ManuallyDrop::new(t); +} + +/// Like [`forget`], but also accepts unsized values. +/// +/// This function is just a shim intended to be removed when the `unsized_locals` feature gets +/// stabilized. +/// +/// [`forget`]: fn.forget.html +#[inline] +#[unstable(feature = "forget_unsized", issue = "0")] +pub fn forget_unsized(t: T) { + unsafe { intrinsics::forget(t) } +} + +/// Returns the size of a type in bytes. +/// +/// More specifically, this is the offset in bytes between successive elements +/// in an array with that item type including alignment padding. Thus, for any +/// type `T` and length `n`, `[T; n]` has a size of `n * size_of::()`. +/// +/// In general, the size of a type is not stable across compilations, but +/// specific types such as primitives are. +/// +/// The following table gives the size for primitives. +/// +/// Type | size_of::\() +/// ---- | --------------- +/// () | 0 +/// bool | 1 +/// u8 | 1 +/// u16 | 2 +/// u32 | 4 +/// u64 | 8 +/// u128 | 16 +/// i8 | 1 +/// i16 | 2 +/// i32 | 4 +/// i64 | 8 +/// i128 | 16 +/// f32 | 4 +/// f64 | 8 +/// char | 4 +/// +/// Furthermore, `usize` and `isize` have the same size. +/// +/// The types `*const T`, `&T`, `Box`, `Option<&T>`, and `Option>` all have +/// the same size. If `T` is Sized, all of those types have the same size as `usize`. +/// +/// The mutability of a pointer does not change its size. As such, `&T` and `&mut T` +/// have the same size. Likewise for `*const T` and `*mut T`. +/// +/// # Size of `#[repr(C)]` items +/// +/// The `C` representation for items has a defined layout. With this layout, +/// the size of items is also stable as long as all fields have a stable size. +/// +/// ## Size of Structs +/// +/// For `structs`, the size is determined by the following algorithm. +/// +/// For each field in the struct ordered by declaration order: +/// +/// 1. Add the size of the field. +/// 2. Round up the current size to the nearest multiple of the next field's [alignment]. +/// +/// Finally, round the size of the struct to the nearest multiple of its [alignment]. +/// The alignment of the struct is usually the largest alignment of all its +/// fields; this can be changed with the use of `repr(align(N))`. +/// +/// Unlike `C`, zero sized structs are not rounded up to one byte in size. +/// +/// ## Size of Enums +/// +/// Enums that carry no data other than the discriminant have the same size as C enums +/// on the platform they are compiled for. +/// +/// ## Size of Unions +/// +/// The size of a union is the size of its largest field. +/// +/// Unlike `C`, zero sized unions are not rounded up to one byte in size. +/// +/// # Examples +/// +/// ``` +/// use std::mem; +/// +/// // Some primitives +/// assert_eq!(4, mem::size_of::()); +/// assert_eq!(8, mem::size_of::()); +/// assert_eq!(0, mem::size_of::<()>()); +/// +/// // Some arrays +/// assert_eq!(8, mem::size_of::<[i32; 2]>()); +/// assert_eq!(12, mem::size_of::<[i32; 3]>()); +/// assert_eq!(0, mem::size_of::<[i32; 0]>()); +/// +/// +/// // Pointer size equality +/// assert_eq!(mem::size_of::<&i32>(), mem::size_of::<*const i32>()); +/// assert_eq!(mem::size_of::<&i32>(), mem::size_of::>()); +/// assert_eq!(mem::size_of::<&i32>(), mem::size_of::>()); +/// assert_eq!(mem::size_of::>(), mem::size_of::>>()); +/// ``` +/// +/// Using `#[repr(C)]`. +/// +/// ``` +/// use std::mem; +/// +/// #[repr(C)] +/// struct FieldStruct { +/// first: u8, +/// second: u16, +/// third: u8 +/// } +/// +/// // The size of the first field is 1, so add 1 to the size. Size is 1. +/// // The alignment of the second field is 2, so add 1 to the size for padding. Size is 2. +/// // The size of the second field is 2, so add 2 to the size. Size is 4. +/// // The alignment of the third field is 1, so add 0 to the size for padding. Size is 4. +/// // The size of the third field is 1, so add 1 to the size. Size is 5. +/// // Finally, the alignment of the struct is 2 (because the largest alignment amongst its +/// // fields is 2), so add 1 to the size for padding. Size is 6. +/// assert_eq!(6, mem::size_of::()); +/// +/// #[repr(C)] +/// struct TupleStruct(u8, u16, u8); +/// +/// // Tuple structs follow the same rules. +/// assert_eq!(6, mem::size_of::()); +/// +/// // Note that reordering the fields can lower the size. We can remove both padding bytes +/// // by putting `third` before `second`. +/// #[repr(C)] +/// struct FieldStructOptimized { +/// first: u8, +/// third: u8, +/// second: u16 +/// } +/// +/// assert_eq!(4, mem::size_of::()); +/// +/// // Union size is the size of the largest field. +/// #[repr(C)] +/// union ExampleUnion { +/// smaller: u8, +/// larger: u16 +/// } +/// +/// assert_eq!(2, mem::size_of::()); +/// ``` +/// +/// [alignment]: ./fn.align_of.html +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_promotable] +pub const fn size_of() -> usize { + intrinsics::size_of::() +} + +/// Returns the size of the pointed-to value in bytes. +/// +/// This is usually the same as `size_of::()`. However, when `T` *has* no +/// statically-known size, e.g., a slice [`[T]`][slice] or a [trait object], +/// then `size_of_val` can be used to get the dynamically-known size. +/// +/// [slice]: ../../std/primitive.slice.html +/// [trait object]: ../../book/ch17-02-trait-objects.html +/// +/// # Examples +/// +/// ``` +/// use std::mem; +/// +/// assert_eq!(4, mem::size_of_val(&5i32)); +/// +/// let x: [u8; 13] = [0; 13]; +/// let y: &[u8] = &x; +/// assert_eq!(13, mem::size_of_val(y)); +/// ``` +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub fn size_of_val(val: &T) -> usize { + unsafe { intrinsics::size_of_val(val) } +} + +/// Returns the [ABI]-required minimum alignment of a type. +/// +/// Every reference to a value of the type `T` must be a multiple of this number. +/// +/// This is the alignment used for struct fields. It may be smaller than the preferred alignment. +/// +/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface +/// +/// # Examples +/// +/// ``` +/// # #![allow(deprecated)] +/// use std::mem; +/// +/// assert_eq!(4, mem::min_align_of::()); +/// ``` +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_deprecated(reason = "use `align_of` instead", since = "1.2.0")] +pub fn min_align_of() -> usize { + intrinsics::min_align_of::() +} + +/// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to. +/// +/// Every reference to a value of the type `T` must be a multiple of this number. +/// +/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface +/// +/// # Examples +/// +/// ``` +/// # #![allow(deprecated)] +/// use std::mem; +/// +/// assert_eq!(4, mem::min_align_of_val(&5i32)); +/// ``` +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_deprecated(reason = "use `align_of_val` instead", since = "1.2.0")] +pub fn min_align_of_val(val: &T) -> usize { + unsafe { intrinsics::min_align_of_val(val) } +} + +/// Returns the [ABI]-required minimum alignment of a type. +/// +/// Every reference to a value of the type `T` must be a multiple of this number. +/// +/// This is the alignment used for struct fields. It may be smaller than the preferred alignment. +/// +/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface +/// +/// # Examples +/// +/// ``` +/// use std::mem; +/// +/// assert_eq!(4, mem::align_of::()); +/// ``` +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_promotable] +pub const fn align_of() -> usize { + intrinsics::min_align_of::() +} + +/// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to. +/// +/// Every reference to a value of the type `T` must be a multiple of this number. +/// +/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface +/// +/// # Examples +/// +/// ``` +/// use std::mem; +/// +/// assert_eq!(4, mem::align_of_val(&5i32)); +/// ``` +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub fn align_of_val(val: &T) -> usize { + unsafe { intrinsics::min_align_of_val(val) } +} + +/// Returns `true` if dropping values of type `T` matters. +/// +/// This is purely an optimization hint, and may be implemented conservatively: +/// it may return `true` for types that don't actually need to be dropped. +/// As such always returning `true` would be a valid implementation of +/// this function. However if this function actually returns `false`, then you +/// can be certain dropping `T` has no side effect. +/// +/// Low level implementations of things like collections, which need to manually +/// drop their data, should use this function to avoid unnecessarily +/// trying to drop all their contents when they are destroyed. This might not +/// make a difference in release builds (where a loop that has no side-effects +/// is easily detected and eliminated), but is often a big win for debug builds. +/// +/// Note that `ptr::drop_in_place` already performs this check, so if your workload +/// can be reduced to some small number of drop_in_place calls, using this is +/// unnecessary. In particular note that you can drop_in_place a slice, and that +/// will do a single needs_drop check for all the values. +/// +/// Types like Vec therefore just `drop_in_place(&mut self[..])` without using +/// needs_drop explicitly. Types like HashMap, on the other hand, have to drop +/// values one at a time and should use this API. +/// +/// +/// # Examples +/// +/// Here's an example of how a collection might make use of needs_drop: +/// +/// ``` +/// use std::{mem, ptr}; +/// +/// pub struct MyCollection { +/// # data: [T; 1], +/// /* ... */ +/// } +/// # impl MyCollection { +/// # fn iter_mut(&mut self) -> &mut [T] { &mut self.data } +/// # fn free_buffer(&mut self) {} +/// # } +/// +/// impl Drop for MyCollection { +/// fn drop(&mut self) { +/// unsafe { +/// // drop the data +/// if mem::needs_drop::() { +/// for x in self.iter_mut() { +/// ptr::drop_in_place(x); +/// } +/// } +/// self.free_buffer(); +/// } +/// } +/// } +/// ``` +#[inline] +#[stable(feature = "needs_drop", since = "1.21.0")] +pub const fn needs_drop() -> bool { + intrinsics::needs_drop::() +} + +/// Creates a value whose bytes are all zero. +/// +/// This has the same effect as [`MaybeUninit::zeroed().assume_init()`][zeroed]. +/// It is useful for FFI sometimes, but should generally be avoided. +/// +/// There is no guarantee that an all-zero byte-pattern represents a valid value of +/// some type `T`. For example, the all-zero byte-pattern is not a valid value +/// for reference types (`&T` and `&mut T`). Using `zeroed` on such types +/// causes immediate [undefined behavior][ub] because [the Rust compiler assumes][inv] +/// that there always is a valid value in a variable it considers initialized. +/// +/// [zeroed]: union.MaybeUninit.html#method.zeroed +/// [ub]: ../../reference/behavior-considered-undefined.html +/// [inv]: union.MaybeUninit.html#initialization-invariant +/// +/// # Examples +/// +/// Correct usage of this function: initializing an integer with zero. +/// +/// ``` +/// use std::mem; +/// +/// let x: i32 = unsafe { mem::zeroed() }; +/// assert_eq!(0, x); +/// ``` +/// +/// *Incorrect* usage of this function: initializing a reference with zero. +/// +/// ```no_run +/// use std::mem; +/// +/// let _x: &i32 = unsafe { mem::zeroed() }; // Undefined behavior! +/// ``` +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub unsafe fn zeroed() -> T { + intrinsics::panic_if_uninhabited::(); + intrinsics::init() +} + +/// Bypasses Rust's normal memory-initialization checks by pretending to +/// produce a value of type `T`, while doing nothing at all. +/// +/// **This functon is deprecated.** Use [`MaybeUninit`] instead. +/// +/// The reason for deprecation is that the function basically cannot be used +/// correctly: [the Rust compiler assumes][inv] that values are properly initialized. +/// As a consequence, calling e.g. `mem::uninitialized::()` causes immediate +/// undefined behavior for returning a `bool` that is not definitely either `true` +/// or `false`. Worse, truly uninitialized memory like what gets returned here +/// is special in that the compiler knows that it does not have a fixed value. +/// This makes it undefined behavior to have uninitialized data in a variable even +/// if that variable has an integer type. +/// (Notice that the rules around uninitialized integers are not finalized yet, but +/// until they are, it is advisable to avoid them.) +/// +/// [`MaybeUninit`]: union.MaybeUninit.html +/// [inv]: union.MaybeUninit.html#initialization-invariant +#[inline] +#[rustc_deprecated(since = "1.38.0", reason = "use `mem::MaybeUninit` instead")] +#[stable(feature = "rust1", since = "1.0.0")] +pub unsafe fn uninitialized() -> T { + intrinsics::panic_if_uninhabited::(); + intrinsics::uninit() +} + +/// Swaps the values at two mutable locations, without deinitializing either one. +/// +/// # Examples +/// +/// ``` +/// use std::mem; +/// +/// let mut x = 5; +/// let mut y = 42; +/// +/// mem::swap(&mut x, &mut y); +/// +/// assert_eq!(42, x); +/// assert_eq!(5, y); +/// ``` +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub fn swap(x: &mut T, y: &mut T) { + unsafe { + ptr::swap_nonoverlapping_one(x, y); + } +} + +/// Moves `src` into the referenced `dest`, returning the previous `dest` value. +/// +/// Neither value is dropped. +/// +/// # Examples +/// +/// A simple example: +/// +/// ``` +/// use std::mem; +/// +/// let mut v: Vec = vec![1, 2]; +/// +/// let old_v = mem::replace(&mut v, vec![3, 4, 5]); +/// assert_eq!(vec![1, 2], old_v); +/// assert_eq!(vec![3, 4, 5], v); +/// ``` +/// +/// `replace` allows consumption of a struct field by replacing it with another value. +/// Without `replace` you can run into issues like these: +/// +/// ```compile_fail,E0507 +/// struct Buffer { buf: Vec } +/// +/// impl Buffer { +/// fn get_and_reset(&mut self) -> Vec { +/// // error: cannot move out of dereference of `&mut`-pointer +/// let buf = self.buf; +/// self.buf = Vec::new(); +/// buf +/// } +/// } +/// ``` +/// +/// Note that `T` does not necessarily implement [`Clone`], so it can't even clone and reset +/// `self.buf`. But `replace` can be used to disassociate the original value of `self.buf` from +/// `self`, allowing it to be returned: +/// +/// ``` +/// # #![allow(dead_code)] +/// use std::mem; +/// +/// # struct Buffer { buf: Vec } +/// impl Buffer { +/// fn get_and_reset(&mut self) -> Vec { +/// mem::replace(&mut self.buf, Vec::new()) +/// } +/// } +/// ``` +/// +/// [`Clone`]: ../../std/clone/trait.Clone.html +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub fn replace(dest: &mut T, mut src: T) -> T { + swap(dest, &mut src); + src +} + +/// Disposes of a value. +/// +/// This does call the argument's implementation of [`Drop`][drop]. +/// +/// This effectively does nothing for types which implement `Copy`, e.g. +/// integers. Such values are copied and _then_ moved into the function, so the +/// value persists after this function call. +/// +/// This function is not magic; it is literally defined as +/// +/// ``` +/// pub fn drop(_x: T) { } +/// ``` +/// +/// Because `_x` is moved into the function, it is automatically dropped before +/// the function returns. +/// +/// [drop]: ../ops/trait.Drop.html +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// let v = vec![1, 2, 3]; +/// +/// drop(v); // explicitly drop the vector +/// ``` +/// +/// Since [`RefCell`] enforces the borrow rules at runtime, `drop` can +/// release a [`RefCell`] borrow: +/// +/// ``` +/// use std::cell::RefCell; +/// +/// let x = RefCell::new(1); +/// +/// let mut mutable_borrow = x.borrow_mut(); +/// *mutable_borrow = 1; +/// +/// drop(mutable_borrow); // relinquish the mutable borrow on this slot +/// +/// let borrow = x.borrow(); +/// println!("{}", *borrow); +/// ``` +/// +/// Integers and other types implementing [`Copy`] are unaffected by `drop`. +/// +/// ``` +/// #[derive(Copy, Clone)] +/// struct Foo(u8); +/// +/// let x = 1; +/// let y = Foo(2); +/// drop(x); // a copy of `x` is moved and dropped +/// drop(y); // a copy of `y` is moved and dropped +/// +/// println!("x: {}, y: {}", x, y.0); // still available +/// ``` +/// +/// [`RefCell`]: ../../std/cell/struct.RefCell.html +/// [`Copy`]: ../../std/marker/trait.Copy.html +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub fn drop(_x: T) { } + +/// Interprets `src` as having type `&U`, and then reads `src` without moving +/// the contained value. +/// +/// This function will unsafely assume the pointer `src` is valid for +/// [`size_of::`][size_of] bytes by transmuting `&T` to `&U` and then reading +/// the `&U`. It will also unsafely create a copy of the contained value instead of +/// moving out of `src`. +/// +/// It is not a compile-time error if `T` and `U` have different sizes, but it +/// is highly encouraged to only invoke this function where `T` and `U` have the +/// same size. This function triggers [undefined behavior][ub] if `U` is larger than +/// `T`. +/// +/// [ub]: ../../reference/behavior-considered-undefined.html +/// [size_of]: fn.size_of.html +/// +/// # Examples +/// +/// ``` +/// use std::mem; +/// +/// #[repr(packed)] +/// struct Foo { +/// bar: u8, +/// } +/// +/// let foo_slice = [10u8]; +/// +/// unsafe { +/// // Copy the data from 'foo_slice' and treat it as a 'Foo' +/// let mut foo_struct: Foo = mem::transmute_copy(&foo_slice); +/// assert_eq!(foo_struct.bar, 10); +/// +/// // Modify the copied data +/// foo_struct.bar = 20; +/// assert_eq!(foo_struct.bar, 20); +/// } +/// +/// // The contents of 'foo_slice' should not have changed +/// assert_eq!(foo_slice, [10]); +/// ``` +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub unsafe fn transmute_copy(src: &T) -> U { + ptr::read_unaligned(src as *const T as *const U) +} + +/// Opaque type representing the discriminant of an enum. +/// +/// See the [`discriminant`] function in this module for more information. +/// +/// [`discriminant`]: fn.discriminant.html +#[stable(feature = "discriminant_value", since = "1.21.0")] +pub struct Discriminant(u64, PhantomData T>); + +// N.B. These trait implementations cannot be derived because we don't want any bounds on T. + +#[stable(feature = "discriminant_value", since = "1.21.0")] +impl Copy for Discriminant {} + +#[stable(feature = "discriminant_value", since = "1.21.0")] +impl clone::Clone for Discriminant { + fn clone(&self) -> Self { + *self + } +} + +#[stable(feature = "discriminant_value", since = "1.21.0")] +impl cmp::PartialEq for Discriminant { + fn eq(&self, rhs: &Self) -> bool { + self.0 == rhs.0 + } +} + +#[stable(feature = "discriminant_value", since = "1.21.0")] +impl cmp::Eq for Discriminant {} + +#[stable(feature = "discriminant_value", since = "1.21.0")] +impl hash::Hash for Discriminant { + fn hash(&self, state: &mut H) { + self.0.hash(state); + } +} + +#[stable(feature = "discriminant_value", since = "1.21.0")] +impl fmt::Debug for Discriminant { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple("Discriminant") + .field(&self.0) + .finish() + } +} + +/// Returns a value uniquely identifying the enum variant in `v`. +/// +/// If `T` is not an enum, calling this function will not result in undefined behavior, but the +/// return value is unspecified. +/// +/// # Stability +/// +/// The discriminant of an enum variant may change if the enum definition changes. A discriminant +/// of some variant will not change between compilations with the same compiler. +/// +/// # Examples +/// +/// This can be used to compare enums that carry data, while disregarding +/// the actual data: +/// +/// ``` +/// use std::mem; +/// +/// enum Foo { A(&'static str), B(i32), C(i32) } +/// +/// assert!(mem::discriminant(&Foo::A("bar")) == mem::discriminant(&Foo::A("baz"))); +/// assert!(mem::discriminant(&Foo::B(1)) == mem::discriminant(&Foo::B(2))); +/// assert!(mem::discriminant(&Foo::B(3)) != mem::discriminant(&Foo::C(3))); +/// ``` +#[stable(feature = "discriminant_value", since = "1.21.0")] +pub fn discriminant(v: &T) -> Discriminant { + unsafe { + Discriminant(intrinsics::discriminant_value(v), PhantomData) + } +} From 3f3087bb7f78426d033e95c3d2dcecce8878d02e Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 29 May 2019 12:12:09 +0200 Subject: [PATCH 10/11] Simplify Set1::insert. --- src/librustc/middle/resolve_lifetime.rs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 736b4633b38f9..593a09b6866db 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -170,16 +170,11 @@ pub enum Set1 { impl Set1 { pub fn insert(&mut self, value: T) { - if let Set1::Empty = *self { - *self = Set1::One(value); - return; - } - if let Set1::One(ref old) = *self { - if *old == value { - return; - } - } - *self = Set1::Many; + *self = match self { + Set1::Empty => Set1::One(value), + Set1::One(old) if *old == value => return, + _ => Set1::Many, + }; } } From d0b37744904fb73244f36c69c8898eef2c4b566f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 May 2019 12:28:45 +0200 Subject: [PATCH 11/11] bless you --- src/test/ui/consts/const-size_of-cycle.stderr | 2 +- src/test/ui/type_length_limit.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/ui/consts/const-size_of-cycle.stderr b/src/test/ui/consts/const-size_of-cycle.stderr index 3762f5e3d6ad8..113ec29239616 100644 --- a/src/test/ui/consts/const-size_of-cycle.stderr +++ b/src/test/ui/consts/const-size_of-cycle.stderr @@ -5,7 +5,7 @@ LL | bytes: [u8; std::mem::size_of::()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: ...which requires const-evaluating `Foo::bytes::{{constant}}#0`... - --> $SRC_DIR/libcore/mem.rs:LL:COL + --> $SRC_DIR/libcore/mem/mod.rs:LL:COL | LL | intrinsics::size_of::() | ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/type_length_limit.stderr b/src/test/ui/type_length_limit.stderr index 9d07c86356b67..7e308f107ba00 100644 --- a/src/test/ui/type_length_limit.stderr +++ b/src/test/ui/type_length_limit.stderr @@ -1,5 +1,5 @@ error: reached the type-length limit while instantiating `std::mem::drop::>` - --> $SRC_DIR/libcore/mem.rs:LL:COL + --> $SRC_DIR/libcore/mem/mod.rs:LL:COL | LL | pub fn drop(_x: T) { } | ^^^^^^^^^^^^^^^^^^^^^^^^^