From dbe6a09a8b8ab8c2c2b422df1e10db8306b1a481 Mon Sep 17 00:00:00 2001 From: ubsan Date: Fri, 24 Jun 2016 15:27:22 -0700 Subject: [PATCH 01/28] First commit, fix ABI string docs in reference.md --- src/doc/reference.md | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/doc/reference.md b/src/doc/reference.md index fb8ea0f5661d3..d564b19e1001c 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -1631,14 +1631,41 @@ the Rust ABI and the foreign ABI. A number of [attributes](#ffi-attributes) control the behavior of external blocks. By default external blocks assume that the library they are calling uses the -standard C "cdecl" ABI. Other ABIs may be specified using an `abi` string, as -shown here: +standard C ABI on the specific platform. Other ABIs may be specified using an +`abi` string, as shown here: ```ignore // Interface to the Windows API extern "stdcall" { } ``` +There are three ABI strings which are cross-platform, and which all compilers +are guaranteed to support: + +* `extern "Rust"` -- The default ABI when you write a normal `fn foo()` in any + Rust code. +* `extern "C"` -- This is the same as `extern fn foo()`; whatever the default + your C compiler supports. +* `extern "system"` -- Usually the same as `extern "C"`, except on Win32, in + which case it's `"stdcall"`, or what you should use to link to the Windows API + itself + +There are also some platform-specific ABI strings: + +* `extern "cdecl"` -- The default for x86\_32 C code. +* `extern "stdcall"` -- The default for the Win32 API on x86\_32. +* `extern "win64"` -- The default for C code on x86\_64 Windows. +* `extern "aapcs"` -- The default for ARM. +* `extern "fastcall"` +* `extern "vectorcall"` + +Finally, there are some rustc-specific ABI strings: + +* `extern "rust-intrinsic"` -- The ABI of rustc intrinsics. +* `extern "rust-call"` -- The ABI of the Fn::call trait functions. +* `extern "platform-intrinsic"` -- Specific platform intrinsics -- like, for + example, `sqrt` -- have this ABI. You should never have to deal with it. + The `link` attribute allows the name of the library to be specified. When specified the compiler will attempt to link against the native library of the specified name. From 1e899fde015c29f53642b6b8e582a8547b6e3b1d Mon Sep 17 00:00:00 2001 From: ubsan Date: Sat, 25 Jun 2016 11:53:46 -0700 Subject: [PATCH 02/28] Add vectorcall and fastcall explanation --- src/doc/reference.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/doc/reference.md b/src/doc/reference.md index d564b19e1001c..fa6014a3d6cee 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -1656,8 +1656,10 @@ There are also some platform-specific ABI strings: * `extern "stdcall"` -- The default for the Win32 API on x86\_32. * `extern "win64"` -- The default for C code on x86\_64 Windows. * `extern "aapcs"` -- The default for ARM. -* `extern "fastcall"` -* `extern "vectorcall"` +* `extern "fastcall"` -- The `fastcall` ABI -- corresponds to MSVC's + `__fastcall` and GCC and clang's `__attribute__((fastcall))` +* `extern "vectorcall"` -- The `vectorcall` ABI -- corresponds to MSVC's + `__vectorcall` and clang's `__attribute__((vectorcall))` Finally, there are some rustc-specific ABI strings: From 3d03f7541e37fe4728149f6466d4c8aba51d7ec0 Mon Sep 17 00:00:00 2001 From: ubsan Date: Fri, 1 Jul 2016 23:33:44 -0700 Subject: [PATCH 03/28] Add more docs - mostly warnings - to std::mem::transmute --- src/libcore/intrinsics.rs | 99 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 95 insertions(+), 4 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index edb965c1962e3..1b52ea33d375a 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -278,18 +278,109 @@ extern "rust-intrinsic" { /// Moves a value out of scope without running drop glue. pub fn forget(_: T) -> (); - /// Unsafely transforms a value of one type into a value of another type. + /// Bitcasts a value of one type to another. Both types must have the same + /// size. /// - /// Both types must have the same size. + /// `transmute::(t)` is semantically equivalent to the following: + /// + /// ``` + /// fn transmute(t: T) -> U { + /// let u: U = std::mem::uninitialized(); + /// std::ptr::copy_nonoverlapping(&t as *const T as *const u8, + /// &mut u as *mut U as *mut u8, + /// std::mem::size_of::()); + /// std::mem::forget(t); + /// u + /// } + /// ``` + /// + /// `transmute` is incredibly unsafe. There are an incredible number of ways + /// to cause undefined behavior with this function. `transmute` should be + /// the absolute last resort. + /// + /// The following is more complete documentation. Read it before using + /// `transmute`: + /// [nomicon](https://doc.rust-lang.org/nomicon/transmutes.html) /// /// # Examples /// /// ``` /// use std::mem; /// - /// let array: &[u8] = unsafe { mem::transmute("Rust") }; - /// assert_eq!(array, [82, 117, 115, 116]); + /// let slice: &[u8] = unsafe { mem::transmute::<&str, &[u8]>("Rust") }; + /// assert_eq!(slice, [82, 117, 115, 116]); + /// // this is not a good way to do this. + /// // use .as_bytes() + /// let slice = "Rust".as_bytes(); + /// assert_eq!(slice, [82, 117, 115, 116]); + /// // Or, just use a byte string + /// assert_eq!(b"Rust", [82, 117, 116, 116]); + /// ``` + /// + /// There are very few good cases for `transmute`. Most can be achieved + /// through other means. Some commone uses, and the less unsafe way, are as + /// follows: + /// + /// ``` + /// // Turning a *mut T into an &mut T + /// let ptr: *mut i32 = &mut 0; + /// let reF_transmuted = std::mem::transmute::<*mut i32, &mut i32>(ptr); + /// let ref_casted = &mut *ptr; + /// ``` + /// /// ``` + /// // Turning an &mut T into an &mut U + /// let ptr = &mut 0; + /// let val_transmuted = std::mem::transmute::<&mut i32, &mut u32>(ptr); + /// // There is a better way, using `as` and reborrowing: + /// let val_casts = &mut *(ptr as *mut T as *mut U); + /// ``` + /// + /// ``` + /// // Copying an `&mut T` to reslice: + /// fn split_at_mut_transmute(slice: &mut [T], index: usize) + /// -> (&mut [T], &mut [T]) { + /// let len = slice.len(); + /// assert!(index < len); + /// let slice2 = std::mem::transmute::<&mut [T], &mut [T]>(slice); + /// (slice[0..index], slice2[index..len]) + /// } + /// // or: + /// fn split_at_mut_casts(slice: &mut [T], index: usize) + /// -> (&mut [T], &mut [T]) { + /// let len = slice.len(); + /// assert!(index < len); + /// let slice2 = &mut *(slice as *mut [T]); // actually typesafe! + /// (slice[0..index], slice2[index..len]) + /// } + /// ``` + /// + /// There are valid uses of transmute. + /// + /// ``` + /// // getting the bitpattern of a floating point type + /// let x = std::mem::transmute::(0.0/0.0) + /// + /// // turning a pointer into a function pointer + /// // in file.c: `int foo(void) { ... }` + /// let handle: *mut libc::c_void = libc::dlopen( + /// b"file.so\0".as_ptr() as *const libc::c_char, libc::RTLD_LAZY); + /// let foo: *mut libc::c_void = libc::dlsym( + /// handle, + /// b"foo\0".as_ptr() as *const libc::c_char); + /// let foo = std::mem::transmute::<*mut libc::c_void, + /// extern fn() -> libc::c_int>(foo); + /// println!("{}", foo()); + /// + /// // extending an invariant lifetime; this is advanced, very unsafe rust + /// struct T<'a>(&'a i32); + /// let value = 0; + /// let t = T::new(&value); + /// let ptr = &mut t; + /// let ptr_extended = std::mem::transmute::<&mut T, &mut T<'static>>(ptr); + /// ``` + /// + /// But these are few and far between. #[stable(feature = "rust1", since = "1.0.0")] pub fn transmute(e: T) -> U; From 233b45f0d714e0fd48b297a531bc57138d524a3a Mon Sep 17 00:00:00 2001 From: ubsan Date: Fri, 1 Jul 2016 23:57:10 -0700 Subject: [PATCH 04/28] Fix up some things which scott mentioned --- src/libcore/intrinsics.rs | 81 ++++++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 35 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 1b52ea33d375a..c7ea5e9da640b 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -278,65 +278,74 @@ extern "rust-intrinsic" { /// Moves a value out of scope without running drop glue. pub fn forget(_: T) -> (); - /// Bitcasts a value of one type to another. Both types must have the same - /// size. + /// Reinterprets the bits of a value of one type as another type. Both types + /// must have the same size. Neither the original, nor the result, may be an + /// invalid value, or else you'll have UB on your hands. /// /// `transmute::(t)` is semantically equivalent to the following: /// /// ``` + /// // assuming that T and U are the same size /// fn transmute(t: T) -> U { - /// let u: U = std::mem::uninitialized(); - /// std::ptr::copy_nonoverlapping(&t as *const T as *const u8, - /// &mut u as *mut U as *mut u8, - /// std::mem::size_of::()); - /// std::mem::forget(t); - /// u + /// let u: U = std::mem::uninitialized(); + /// std::ptr::copy_nonoverlapping(&t as *const T as *const u8, + /// &mut u as *mut U as *mut u8, + /// std::mem::size_of::()); + /// std::mem::forget(t); + /// u /// } /// ``` /// - /// `transmute` is incredibly unsafe. There are an incredible number of ways - /// to cause undefined behavior with this function. `transmute` should be + /// `transmute` is incredibly unsafe. There are a vast number of ways to + /// cause undefined behavior with this function. `transmute` should be /// the absolute last resort. /// /// The following is more complete documentation. Read it before using /// `transmute`: /// [nomicon](https://doc.rust-lang.org/nomicon/transmutes.html) /// - /// # Examples + /// # Alternatives + /// + /// There are very few good cases for `transmute`. Most can be achieved + /// through other means. Some more or less common uses, and a better way, + /// are as follows: /// /// ``` /// use std::mem; /// - /// let slice: &[u8] = unsafe { mem::transmute::<&str, &[u8]>("Rust") }; - /// assert_eq!(slice, [82, 117, 115, 116]); - /// // this is not a good way to do this. - /// // use .as_bytes() - /// let slice = "Rust".as_bytes(); - /// assert_eq!(slice, [82, 117, 115, 116]); - /// // Or, just use a byte string - /// assert_eq!(b"Rust", [82, 117, 116, 116]); - /// ``` + /// // turning a pointer into a usize + /// let ptr = &0; + /// let ptr_num_transmute = std::mem::transmute::<&i32, usize>(ptr); + /// // now with more `as` + /// let ptr_num_cast = ptr as *const i32 as usize; /// - /// There are very few good cases for `transmute`. Most can be achieved - /// through other means. Some commone uses, and the less unsafe way, are as - /// follows: /// - /// ``` /// // Turning a *mut T into an &mut T /// let ptr: *mut i32 = &mut 0; - /// let reF_transmuted = std::mem::transmute::<*mut i32, &mut i32>(ptr); + /// let ref_transmuted = std::mem::transmute::<*mut i32, &mut i32>(ptr); + /// // Use reborrows /// let ref_casted = &mut *ptr; - /// ``` /// - /// ``` + /// /// // Turning an &mut T into an &mut U /// let ptr = &mut 0; /// let val_transmuted = std::mem::transmute::<&mut i32, &mut u32>(ptr); - /// // There is a better way, using `as` and reborrowing: - /// let val_casts = &mut *(ptr as *mut T as *mut U); - /// ``` + /// // Reborrowing continues to play a role here, but now we add `as` casts + /// let val_casts = &mut *(ptr as *mut i32 as *mut u32); + /// + /// + /// // Turning an `&str` into an `&[u8]` + /// let slice = unsafe { mem::transmute::<&str, &[u8]>("Rust") }; + /// assert_eq!(slice, [82, 117, 115, 116]); + /// // this is not a good way to do this. + /// // use .as_bytes() + /// let slice = "Rust".as_bytes(); + /// assert_eq!(slice, [82, 117, 115, 116]); + /// // Or, just use a byte string, if you have control over the string + /// // literal + /// assert_eq!(b"Rust", [82, 117, 116, 116]); + /// /// - /// ``` /// // Copying an `&mut T` to reslice: /// fn split_at_mut_transmute(slice: &mut [T], index: usize) /// -> (&mut [T], &mut [T]) { @@ -345,7 +354,7 @@ extern "rust-intrinsic" { /// let slice2 = std::mem::transmute::<&mut [T], &mut [T]>(slice); /// (slice[0..index], slice2[index..len]) /// } - /// // or: + /// // Again, use `as` and reborrowing /// fn split_at_mut_casts(slice: &mut [T], index: usize) /// -> (&mut [T], &mut [T]) { /// let len = slice.len(); @@ -355,12 +364,15 @@ extern "rust-intrinsic" { /// } /// ``` /// - /// There are valid uses of transmute. + /// # Examples + /// + /// There are valid uses of transmute, though they are few and far between. /// /// ``` /// // getting the bitpattern of a floating point type /// let x = std::mem::transmute::(0.0/0.0) /// + /// /// // turning a pointer into a function pointer /// // in file.c: `int foo(void) { ... }` /// let handle: *mut libc::c_void = libc::dlopen( @@ -372,6 +384,7 @@ extern "rust-intrinsic" { /// extern fn() -> libc::c_int>(foo); /// println!("{}", foo()); /// + /// /// // extending an invariant lifetime; this is advanced, very unsafe rust /// struct T<'a>(&'a i32); /// let value = 0; @@ -379,8 +392,6 @@ extern "rust-intrinsic" { /// let ptr = &mut t; /// let ptr_extended = std::mem::transmute::<&mut T, &mut T<'static>>(ptr); /// ``` - /// - /// But these are few and far between. #[stable(feature = "rust1", since = "1.0.0")] pub fn transmute(e: T) -> U; From 6928bbba3a51db12aceb90d3c99dbec1383ce2dc Mon Sep 17 00:00:00 2001 From: ubsan Date: Sat, 2 Jul 2016 00:00:04 -0700 Subject: [PATCH 05/28] Fix some other small nits --- src/libcore/intrinsics.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index c7ea5e9da640b..3cc113f5e0a7a 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -316,7 +316,7 @@ extern "rust-intrinsic" { /// // turning a pointer into a usize /// let ptr = &0; /// let ptr_num_transmute = std::mem::transmute::<&i32, usize>(ptr); - /// // now with more `as` + /// // Use `as` casts instead /// let ptr_num_cast = ptr as *const i32 as usize; /// /// @@ -330,15 +330,15 @@ extern "rust-intrinsic" { /// // Turning an &mut T into an &mut U /// let ptr = &mut 0; /// let val_transmuted = std::mem::transmute::<&mut i32, &mut u32>(ptr); - /// // Reborrowing continues to play a role here, but now we add `as` casts + /// // Now let's put together `as` and reborrowing /// let val_casts = &mut *(ptr as *mut i32 as *mut u32); /// /// /// // Turning an `&str` into an `&[u8]` + /// // this is not a good way to do this. /// let slice = unsafe { mem::transmute::<&str, &[u8]>("Rust") }; /// assert_eq!(slice, [82, 117, 115, 116]); - /// // this is not a good way to do this. - /// // use .as_bytes() + /// // You could use `str::as_bytes` /// let slice = "Rust".as_bytes(); /// assert_eq!(slice, [82, 117, 115, 116]); /// // Or, just use a byte string, if you have control over the string From 2413b52b886bc9ba4db6c5bc5eb0712c6e4f554a Mon Sep 17 00:00:00 2001 From: ubsan Date: Sat, 2 Jul 2016 00:07:36 -0700 Subject: [PATCH 06/28] More nits :P --- src/libcore/intrinsics.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 3cc113f5e0a7a..d2bf9d94399ea 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -280,7 +280,8 @@ extern "rust-intrinsic" { /// Reinterprets the bits of a value of one type as another type. Both types /// must have the same size. Neither the original, nor the result, may be an - /// invalid value, or else you'll have UB on your hands. + /// [invalid value] + /// (https://doc.rust-lang.org/nomicon/meet-safe-and-unsafe.html). /// /// `transmute::(t)` is semantically equivalent to the following: /// @@ -300,9 +301,8 @@ extern "rust-intrinsic" { /// cause undefined behavior with this function. `transmute` should be /// the absolute last resort. /// - /// The following is more complete documentation. Read it before using - /// `transmute`: - /// [nomicon](https://doc.rust-lang.org/nomicon/transmutes.html) + /// The [nomicon](https://doc.rust-lang.org/nomicon/transmutes.html) has + /// more complete documentation. Read it before using `transmute`. /// /// # Alternatives /// From 377bbfe96b9d5f20ca6aec84f68ad8161f307ab5 Mon Sep 17 00:00:00 2001 From: ubsan Date: Sat, 2 Jul 2016 08:45:01 -0700 Subject: [PATCH 07/28] Add a new alternative --- src/libcore/intrinsics.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index d2bf9d94399ea..5bd35ae1ac25c 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -346,6 +346,29 @@ extern "rust-intrinsic" { /// assert_eq!(b"Rust", [82, 117, 116, 116]); /// /// + /// // Turning a Vec<&T> into a Vec> + /// let store = [0, 1, 2, 3]; + /// let v_orig = store.iter().collect::>(); + /// // Using transmute; Undefined Behavior + /// let v_transmuted = mem::transmute::, Vec>>( + /// v_orig); + /// // The suggested, safe way + /// let v_collected = v_orig.into_iter() + /// .map(|r| Some(r)) + /// .collect::>>(); + /// // The no-copy, unsafe way, still using transmute, but not UB + /// let v_no_copy = Vec::from_raw_parts(v_orig.as_mut_ptr(), + /// v_orig.len(), + /// v_orig.capacity()); + /// mem::forget(v_orig); + /// // This is equivalent to the original, but safer, and reuses the same + /// // Vec internals. Therefore the new inner type must have the exact same + /// // size, and the same or lesser alignment, as the old type. + /// // The same caveats exist for this method as transmute, for the original + /// // inner type (`&i32`) to the converted inner type (`Option<&i32>`), so + /// // read the nomicon page linked above. + /// + /// /// // Copying an `&mut T` to reslice: /// fn split_at_mut_transmute(slice: &mut [T], index: usize) /// -> (&mut [T], &mut [T]) { From 9e94ebf268385686299b6838b41e8e04a874259f Mon Sep 17 00:00:00 2001 From: ubsan Date: Sat, 2 Jul 2016 22:55:30 -0700 Subject: [PATCH 08/28] Make sure the documentation compiles --- src/libcore/intrinsics.rs | 169 +++++++++++++++++++++----------------- 1 file changed, 92 insertions(+), 77 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 5bd35ae1ac25c..ce87bd3ba326c 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -287,12 +287,12 @@ extern "rust-intrinsic" { /// /// ``` /// // assuming that T and U are the same size - /// fn transmute(t: T) -> U { - /// let u: U = std::mem::uninitialized(); + /// unsafe fn transmute(t: T) -> U { + /// let u: U = mem::uninitialized(); /// std::ptr::copy_nonoverlapping(&t as *const T as *const u8, /// &mut u as *mut U as *mut u8, - /// std::mem::size_of::()); - /// std::mem::forget(t); + /// mem::size_of::()); + /// mem::forget(t); /// u /// } /// ``` @@ -314,76 +314,85 @@ extern "rust-intrinsic" { /// use std::mem; /// /// // turning a pointer into a usize - /// let ptr = &0; - /// let ptr_num_transmute = std::mem::transmute::<&i32, usize>(ptr); - /// // Use `as` casts instead - /// let ptr_num_cast = ptr as *const i32 as usize; - /// + /// { + /// let ptr = &0; + /// let ptr_num_transmute = mem::transmute::<&i32, usize>(ptr); + /// // Use `as` casts instead + /// let ptr_num_cast = ptr as *const i32 as usize; + /// } /// /// // Turning a *mut T into an &mut T - /// let ptr: *mut i32 = &mut 0; - /// let ref_transmuted = std::mem::transmute::<*mut i32, &mut i32>(ptr); - /// // Use reborrows - /// let ref_casted = &mut *ptr; - /// + /// { + /// let ptr: *mut i32 = &mut 0; + /// let ref_transmuted = mem::transmute::<*mut i32, &mut i32>(ptr); + /// // Use reborrows + /// let ref_casted = &mut *ptr; + /// } /// /// // Turning an &mut T into an &mut U - /// let ptr = &mut 0; - /// let val_transmuted = std::mem::transmute::<&mut i32, &mut u32>(ptr); - /// // Now let's put together `as` and reborrowing - /// let val_casts = &mut *(ptr as *mut i32 as *mut u32); - /// + /// { + /// let ptr = &mut 0; + /// let val_transmuted = mem::transmute::<&mut i32, &mut u32>(ptr); + /// // Now let's put together `as` and reborrowing + /// let val_casts = &mut *(ptr as *mut i32 as *mut u32); + /// } /// /// // Turning an `&str` into an `&[u8]` - /// // this is not a good way to do this. - /// let slice = unsafe { mem::transmute::<&str, &[u8]>("Rust") }; - /// assert_eq!(slice, [82, 117, 115, 116]); - /// // You could use `str::as_bytes` - /// let slice = "Rust".as_bytes(); - /// assert_eq!(slice, [82, 117, 115, 116]); - /// // Or, just use a byte string, if you have control over the string - /// // literal - /// assert_eq!(b"Rust", [82, 117, 116, 116]); - /// + /// { + /// // this is not a good way to do this. + /// let slice = unsafe { mem::transmute::<&str, &[u8]>("Rust") }; + /// assert_eq!(slice, [82, 117, 115, 116]); + /// // You could use `str::as_bytes` + /// let slice = "Rust".as_bytes(); + /// assert_eq!(slice, [82, 117, 115, 116]); + /// // Or, just use a byte string, if you have control over the string + /// // literal + /// assert_eq!(b"Rust", [82, 117, 116, 116]); + /// } /// /// // Turning a Vec<&T> into a Vec> - /// let store = [0, 1, 2, 3]; - /// let v_orig = store.iter().collect::>(); - /// // Using transmute; Undefined Behavior - /// let v_transmuted = mem::transmute::, Vec>>( - /// v_orig); - /// // The suggested, safe way - /// let v_collected = v_orig.into_iter() - /// .map(|r| Some(r)) - /// .collect::>>(); - /// // The no-copy, unsafe way, still using transmute, but not UB - /// let v_no_copy = Vec::from_raw_parts(v_orig.as_mut_ptr(), - /// v_orig.len(), - /// v_orig.capacity()); - /// mem::forget(v_orig); - /// // This is equivalent to the original, but safer, and reuses the same - /// // Vec internals. Therefore the new inner type must have the exact same - /// // size, and the same or lesser alignment, as the old type. - /// // The same caveats exist for this method as transmute, for the original - /// // inner type (`&i32`) to the converted inner type (`Option<&i32>`), so - /// // read the nomicon page linked above. + /// { + /// let store = [0, 1, 2, 3]; + /// let v_orig = store.iter().collect::>(); + /// // Using transmute; Undefined Behavior + /// let v_transmuted = mem::transmute::, Vec>>( + /// v_orig.clone()); + /// // The suggested, safe way + /// let v_collected = v_orig.clone() + /// .into_iter() + /// .map(|r| Some(r)) + /// .collect::>>(); + /// // The no-copy, unsafe way, still using transmute, but not UB + /// // This is equivalent to the original, but safer, and reuses the + /// // same Vec internals. Therefore the new inner type must have the + /// // exact same size, and the same or lesser alignment, as the old + /// // type. The same caveats exist for this method as transmute, for + /// // the original inner type (`&i32`) to the converted inner type + /// // (`Option<&i32>`), so read the nomicon page linked above. + /// let v_no_copy = Vec::from_raw_parts(v_orig.as_mut_ptr(), + /// v_orig.len(), + /// v_orig.capacity()); + /// mem::forget(v_orig); + /// } /// /// /// // Copying an `&mut T` to reslice: - /// fn split_at_mut_transmute(slice: &mut [T], index: usize) + /// { + /// fn split_at_mut_transmute(slice: &mut [T], index: usize) + /// -> (&mut [T], &mut [T]) { + /// let len = slice.len(); + /// assert!(index < len); + /// let slice2 = mem::transmute::<&mut [T], &mut [T]>(slice); + /// (slice[0..index], slice2[index..len]) + /// } + /// // Again, use `as` and reborrowing + /// fn split_at_mut_casts(slice: &mut [T], index: usize) /// -> (&mut [T], &mut [T]) { - /// let len = slice.len(); - /// assert!(index < len); - /// let slice2 = std::mem::transmute::<&mut [T], &mut [T]>(slice); - /// (slice[0..index], slice2[index..len]) - /// } - /// // Again, use `as` and reborrowing - /// fn split_at_mut_casts(slice: &mut [T], index: usize) - /// -> (&mut [T], &mut [T]) { - /// let len = slice.len(); - /// assert!(index < len); - /// let slice2 = &mut *(slice as *mut [T]); // actually typesafe! - /// (slice[0..index], slice2[index..len]) + /// let len = slice.len(); + /// assert!(index < len); + /// let slice2 = &mut *(slice as *mut [T]); // actually typesafe! + /// (slice[0..index], slice2[index..len]) + /// } /// } /// ``` /// @@ -393,27 +402,33 @@ extern "rust-intrinsic" { /// /// ``` /// // getting the bitpattern of a floating point type - /// let x = std::mem::transmute::(0.0/0.0) + /// { + /// let x = mem::transmute::(0.0/0.0) + /// } /// /// /// // turning a pointer into a function pointer - /// // in file.c: `int foo(void) { ... }` - /// let handle: *mut libc::c_void = libc::dlopen( - /// b"file.so\0".as_ptr() as *const libc::c_char, libc::RTLD_LAZY); - /// let foo: *mut libc::c_void = libc::dlsym( - /// handle, - /// b"foo\0".as_ptr() as *const libc::c_char); - /// let foo = std::mem::transmute::<*mut libc::c_void, - /// extern fn() -> libc::c_int>(foo); - /// println!("{}", foo()); + /// { + /// // in file.c: `int foo(void) { ... }` + /// let handle: *mut libc::c_void = libc::dlopen( + /// b"file.so\0".as_ptr() as *const libc::c_char, libc::RTLD_LAZY); + /// let foo: *mut libc::c_void = libc::dlsym( + /// handle, + /// b"foo\0".as_ptr() as *const libc::c_char); + /// let foo = mem::transmute::<*mut libc::c_void, + /// extern fn() -> libc::c_int>(foo); + /// println!("{}", foo()); + /// } /// /// /// // extending an invariant lifetime; this is advanced, very unsafe rust - /// struct T<'a>(&'a i32); - /// let value = 0; - /// let t = T::new(&value); - /// let ptr = &mut t; - /// let ptr_extended = std::mem::transmute::<&mut T, &mut T<'static>>(ptr); + /// { + /// struct T<'a>(&'a i32); + /// let value = 0; + /// let t = T::new(&value); + /// let ptr = &mut t; + /// let ptr_extended = mem::transmute::<&mut T, &mut T<'static>>(ptr); + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn transmute(e: T) -> U; From 7ec44e6c7b0e5fb2ddbc281aa74b515f8ea4e16b Mon Sep 17 00:00:00 2001 From: ubsan Date: Tue, 5 Jul 2016 10:40:59 -0700 Subject: [PATCH 09/28] Fix tests --- src/libcore/intrinsics.rs | 238 ++++++++++++++++++++++---------------- 1 file changed, 138 insertions(+), 100 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index ce87bd3ba326c..fd23598a84715 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -286,12 +286,13 @@ extern "rust-intrinsic" { /// `transmute::(t)` is semantically equivalent to the following: /// /// ``` + /// use std::{mem, ptr}; /// // assuming that T and U are the same size /// unsafe fn transmute(t: T) -> U { - /// let u: U = mem::uninitialized(); - /// std::ptr::copy_nonoverlapping(&t as *const T as *const u8, - /// &mut u as *mut U as *mut u8, - /// mem::size_of::()); + /// let mut u: U = mem::uninitialized(); + /// ptr::copy_nonoverlapping(&t as *const T as *const u8, + /// &mut u as *mut U as *mut u8, + /// mem::size_of::()); /// mem::forget(t); /// u /// } @@ -310,88 +311,115 @@ extern "rust-intrinsic" { /// through other means. Some more or less common uses, and a better way, /// are as follows: /// + /// Turning a pointer into a `usize`: + /// ``` + /// let ptr = &0; + /// let ptr_num_transmute = mem::transmute::<&i32, usize>(ptr); + /// // Use `as` casts instead + /// let ptr_num_cast = ptr as *const i32 as usize; /// ``` - /// use std::mem; - /// - /// // turning a pointer into a usize - /// { - /// let ptr = &0; - /// let ptr_num_transmute = mem::transmute::<&i32, usize>(ptr); - /// // Use `as` casts instead - /// let ptr_num_cast = ptr as *const i32 as usize; - /// } - /// - /// // Turning a *mut T into an &mut T - /// { - /// let ptr: *mut i32 = &mut 0; - /// let ref_transmuted = mem::transmute::<*mut i32, &mut i32>(ptr); - /// // Use reborrows - /// let ref_casted = &mut *ptr; - /// } /// - /// // Turning an &mut T into an &mut U - /// { - /// let ptr = &mut 0; - /// let val_transmuted = mem::transmute::<&mut i32, &mut u32>(ptr); - /// // Now let's put together `as` and reborrowing - /// let val_casts = &mut *(ptr as *mut i32 as *mut u32); - /// } + /// Turning a `*mut T` into an `&mut T`: + /// ``` + /// let ptr: *mut i32 = &mut 0; + /// let ref_transmuted = mem::transmute::<*mut i32, &mut i32>(ptr); + /// // Use reborrows + /// let ref_casted = &mut *ptr; + /// ``` /// - /// // Turning an `&str` into an `&[u8]` - /// { - /// // this is not a good way to do this. - /// let slice = unsafe { mem::transmute::<&str, &[u8]>("Rust") }; - /// assert_eq!(slice, [82, 117, 115, 116]); - /// // You could use `str::as_bytes` - /// let slice = "Rust".as_bytes(); - /// assert_eq!(slice, [82, 117, 115, 116]); - /// // Or, just use a byte string, if you have control over the string - /// // literal - /// assert_eq!(b"Rust", [82, 117, 116, 116]); - /// } + /// Turning an `&mut T` into an `&mut U`: + /// ``` + /// let ptr = &mut 0; + /// let val_transmuted = mem::transmute::<&mut i32, &mut u32>(ptr); + /// // Now let's put together `as` and reborrowing + /// let val_casts = &mut *(ptr as *mut i32 as *mut u32); + /// ``` /// - /// // Turning a Vec<&T> into a Vec> - /// { - /// let store = [0, 1, 2, 3]; - /// let v_orig = store.iter().collect::>(); - /// // Using transmute; Undefined Behavior - /// let v_transmuted = mem::transmute::, Vec>>( - /// v_orig.clone()); - /// // The suggested, safe way - /// let v_collected = v_orig.clone() - /// .into_iter() - /// .map(|r| Some(r)) - /// .collect::>>(); - /// // The no-copy, unsafe way, still using transmute, but not UB - /// // This is equivalent to the original, but safer, and reuses the - /// // same Vec internals. Therefore the new inner type must have the - /// // exact same size, and the same or lesser alignment, as the old - /// // type. The same caveats exist for this method as transmute, for - /// // the original inner type (`&i32`) to the converted inner type - /// // (`Option<&i32>`), so read the nomicon page linked above. - /// let v_no_copy = Vec::from_raw_parts(v_orig.as_mut_ptr(), - /// v_orig.len(), - /// v_orig.capacity()); - /// mem::forget(v_orig); - /// } + /// Turning an `&str` into an `&[u8]`: + /// ``` + /// // this is not a good way to do this. + /// let slice = unsafe { mem::transmute::<&str, &[u8]>("Rust") }; + /// assert_eq!(slice, [82, 117, 115, 116]); + /// // You could use `str::as_bytes` + /// let slice = "Rust".as_bytes(); + /// assert_eq!(slice, [82, 117, 115, 116]); + /// // Or, just use a byte string, if you have control over the string + /// // literal + /// assert_eq!(b"Rust", [82, 117, 116, 116]); + /// ``` /// + /// Turning a `Vec<&T>` into a `Vec>`: + /// ``` + /// let store = [0, 1, 2, 3]; + /// let v_orig = store.iter().collect::>(); + /// // Using transmute: this is Undefined Behavior, and a bad idea + /// // However, it is no-copy + /// let v_transmuted = mem::transmute::, Vec>>( + /// v_orig.clone()); + /// // This is the suggested, safe way + /// // It does copy the entire Vector, though, into a new array + /// let v_collected = v_orig.clone() + /// .into_iter() + /// .map(|r| Some(r)) + /// .collect::>>(); + /// // The no-copy, unsafe way, still using transmute, but not UB + /// // This is equivalent to the original, but safer, and reuses the + /// // same Vec internals. Therefore the new inner type must have the + /// // exact same size, and the same or lesser alignment, as the old + /// // type. The same caveats exist for this method as transmute, for + /// // the original inner type (`&i32`) to the converted inner type + /// // (`Option<&i32>`), so read the nomicon page linked above. + /// let v_from_raw = Vec::from_raw_parts(v_orig.as_mut_ptr(), + /// v_orig.len(), + /// v_orig.capacity()); + /// mem::forget(v_orig); + /// ``` /// - /// // Copying an `&mut T` to reslice: - /// { - /// fn split_at_mut_transmute(slice: &mut [T], index: usize) - /// -> (&mut [T], &mut [T]) { - /// let len = slice.len(); - /// assert!(index < len); + /// Implemententing `split_at_mut`: + /// ``` + /// use std::{slice, mem}; + /// // There are multiple ways to do this; and there are multiple problems + /// // with the following, transmute, way + /// fn split_at_mut_transmute(slice: &mut [T], index: usize) + /// -> (&mut [T], &mut [T]) { + /// let len = slice.len(); + /// assert!(index < len); + /// unsafe { /// let slice2 = mem::transmute::<&mut [T], &mut [T]>(slice); - /// (slice[0..index], slice2[index..len]) + /// // first: transmute is not typesafe; all it checks is that T and + /// // U are of the same size. Second, right here, you have two + /// // mutable references pointing to the same memory + /// (&mut slice[0..index], &mut slice2[index..len]) /// } - /// // Again, use `as` and reborrowing - /// fn split_at_mut_casts(slice: &mut [T], index: usize) - /// -> (&mut [T], &mut [T]) { - /// let len = slice.len(); - /// assert!(index < len); - /// let slice2 = &mut *(slice as *mut [T]); // actually typesafe! - /// (slice[0..index], slice2[index..len]) + /// } + /// // This gets rid of the typesafety problems; `&mut *` will *only* give + /// // you an &mut T from an &mut T or *mut T + /// fn split_at_mut_casts(slice: &mut [T], index: usize) + /// -> (&mut [T], &mut [T]) { + /// let len = slice.len(); + /// assert!(index < len); + /// unsafe { + /// let slice2 = &mut *(slice as *mut [T]); + /// // however, you still have two mutable references pointing to + /// // the same memory + /// (&mut slice[0..index], &mut slice2[index..len]) + /// } + /// } + /// // This is how the standard library does it. This is the best method, if + /// // you need to do something like this + /// fn split_at_stdlib(slice: &mut [T], index: usize) + /// -> (&mut [T], &mut [T]) { + /// let len = self.len(); + /// let ptr = self.as_mut_ptr(); + /// unsafe { + /// assert!(mid <= len); + /// // This now has three mutable references pointing at the same + /// // memory. `slice`, the rvalue ret.0, and the rvalue ret.1. + /// // However, `slice` is never used after `let ptr = ...`, and so + /// // one can treat it as "dead", and therefore, you only have two + /// // real mutable slices. + /// (slice::from_raw_parts_mut(ptr, mid), + /// slice::from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) /// } /// } /// ``` @@ -400,39 +428,49 @@ extern "rust-intrinsic" { /// /// There are valid uses of transmute, though they are few and far between. /// + /// Getting the bitpattern of a floating point type: + /// ``` + /// let bitpattern = std::mem::transmute::(1.0); + /// assert_eq!(bitpattern, 0x3F800000); /// ``` - /// // getting the bitpattern of a floating point type - /// { - /// let x = mem::transmute::(0.0/0.0) + /// + /// Turning a pointer into a function pointer (this isn't guaranteed to + /// work in Rust, although, for example, Linux does make this guarantee): + /// ``` + /// fn foo() -> i32 { + /// 0 /// } + /// let pointer = foo as *const (); + /// let function = std::mem::transmute::<*const (), fn() -> i32>(pointer) + /// assert_eq!(function(), 0); + /// ``` /// + /// Extending a lifetime, or shortening an invariant an invariant lifetime; + /// this is advanced, very unsafe rust: + /// ``` + /// use std::mem; /// - /// // turning a pointer into a function pointer - /// { - /// // in file.c: `int foo(void) { ... }` - /// let handle: *mut libc::c_void = libc::dlopen( - /// b"file.so\0".as_ptr() as *const libc::c_char, libc::RTLD_LAZY); - /// let foo: *mut libc::c_void = libc::dlsym( - /// handle, - /// b"foo\0".as_ptr() as *const libc::c_char); - /// let foo = mem::transmute::<*mut libc::c_void, - /// extern fn() -> libc::c_int>(foo); - /// println!("{}", foo()); + /// struct R<'a>(&'a i32); + /// unsafe fn extend_lifetime<'b>(r: R<'b>) -> R<'static> { + /// mem::transmute::, R<'static>>(ptr); /// } /// - /// - /// // extending an invariant lifetime; this is advanced, very unsafe rust - /// { - /// struct T<'a>(&'a i32); - /// let value = 0; - /// let t = T::new(&value); - /// let ptr = &mut t; - /// let ptr_extended = mem::transmute::<&mut T, &mut T<'static>>(ptr); + /// unsafe fn shorten_invariant<'b, 'c>(r: &'b mut R<'static>) + /// -> &'b R<'c> { + /// let ref_to_original = + /// mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>( + /// ref_to_extended); /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn transmute(e: T) -> U; + /// Gives the address for the return value of the enclosing function. + /// + /// Using this intrinsic in a function that does not use an out pointer + /// will trigger a compiler error. + pub fn return_address() -> *const u8; + /// Returns `true` if the actual type given as `T` requires drop /// glue; returns `false` if the actual type provided for `T` /// implements `Copy`. From 8c7668a903fb31f8bd767ed5c2a1e1fd3c778915 Mon Sep 17 00:00:00 2001 From: ubsan Date: Tue, 5 Jul 2016 15:15:33 -0700 Subject: [PATCH 10/28] Fix nits --- src/libcore/intrinsics.rs | 41 ++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index fd23598a84715..1ccdbb3411c8d 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -312,30 +312,34 @@ extern "rust-intrinsic" { /// are as follows: /// /// Turning a pointer into a `usize`: + /// /// ``` /// let ptr = &0; /// let ptr_num_transmute = mem::transmute::<&i32, usize>(ptr); - /// // Use `as` casts instead + /// // Use an `as` cast instead /// let ptr_num_cast = ptr as *const i32 as usize; /// ``` /// /// Turning a `*mut T` into an `&mut T`: + /// /// ``` /// let ptr: *mut i32 = &mut 0; /// let ref_transmuted = mem::transmute::<*mut i32, &mut i32>(ptr); - /// // Use reborrows + /// // Use a reborrow instead /// let ref_casted = &mut *ptr; /// ``` /// /// Turning an `&mut T` into an `&mut U`: + /// /// ``` /// let ptr = &mut 0; /// let val_transmuted = mem::transmute::<&mut i32, &mut u32>(ptr); - /// // Now let's put together `as` and reborrowing + /// // Now, put together `as` and reborrowing /// let val_casts = &mut *(ptr as *mut i32 as *mut u32); /// ``` /// /// Turning an `&str` into an `&[u8]`: + /// /// ``` /// // this is not a good way to do this. /// let slice = unsafe { mem::transmute::<&str, &[u8]>("Rust") }; @@ -349,20 +353,21 @@ extern "rust-intrinsic" { /// ``` /// /// Turning a `Vec<&T>` into a `Vec>`: + /// /// ``` /// let store = [0, 1, 2, 3]; /// let v_orig = store.iter().collect::>(); - /// // Using transmute: this is Undefined Behavior, and a bad idea - /// // However, it is no-copy + /// // Using transmute: this is Undefined Behavior, and a bad idea. + /// // However, it is no-copy. /// let v_transmuted = mem::transmute::, Vec>>( /// v_orig.clone()); - /// // This is the suggested, safe way - /// // It does copy the entire Vector, though, into a new array + /// // This is the suggested, safe way. + /// // It does copy the entire Vector, though, into a new array. /// let v_collected = v_orig.clone() /// .into_iter() /// .map(|r| Some(r)) /// .collect::>>(); - /// // The no-copy, unsafe way, still using transmute, but not UB + /// // The no-copy, unsafe way, still using transmute, but not UB. /// // This is equivalent to the original, but safer, and reuses the /// // same Vec internals. Therefore the new inner type must have the /// // exact same size, and the same or lesser alignment, as the old @@ -375,11 +380,12 @@ extern "rust-intrinsic" { /// mem::forget(v_orig); /// ``` /// - /// Implemententing `split_at_mut`: + /// Implementing `split_at_mut`: + /// /// ``` /// use std::{slice, mem}; /// // There are multiple ways to do this; and there are multiple problems - /// // with the following, transmute, way + /// // with the following, transmute, way. /// fn split_at_mut_transmute(slice: &mut [T], index: usize) /// -> (&mut [T], &mut [T]) { /// let len = slice.len(); @@ -388,12 +394,12 @@ extern "rust-intrinsic" { /// let slice2 = mem::transmute::<&mut [T], &mut [T]>(slice); /// // first: transmute is not typesafe; all it checks is that T and /// // U are of the same size. Second, right here, you have two - /// // mutable references pointing to the same memory + /// // mutable references pointing to the same memory. /// (&mut slice[0..index], &mut slice2[index..len]) /// } /// } /// // This gets rid of the typesafety problems; `&mut *` will *only* give - /// // you an &mut T from an &mut T or *mut T + /// // you an `&mut T` from an `&mut T` or `*mut T`. /// fn split_at_mut_casts(slice: &mut [T], index: usize) /// -> (&mut [T], &mut [T]) { /// let len = slice.len(); @@ -401,7 +407,7 @@ extern "rust-intrinsic" { /// unsafe { /// let slice2 = &mut *(slice as *mut [T]); /// // however, you still have two mutable references pointing to - /// // the same memory + /// // the same memory. /// (&mut slice[0..index], &mut slice2[index..len]) /// } /// } @@ -415,9 +421,9 @@ extern "rust-intrinsic" { /// assert!(mid <= len); /// // This now has three mutable references pointing at the same /// // memory. `slice`, the rvalue ret.0, and the rvalue ret.1. - /// // However, `slice` is never used after `let ptr = ...`, and so - /// // one can treat it as "dead", and therefore, you only have two - /// // real mutable slices. + /// // `slice` is never used after `let ptr = ...`, and so one can + /// // treat it as "dead", and therefore, you only have two real + /// // mutable slices. /// (slice::from_raw_parts_mut(ptr, mid), /// slice::from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) /// } @@ -429,6 +435,7 @@ extern "rust-intrinsic" { /// There are valid uses of transmute, though they are few and far between. /// /// Getting the bitpattern of a floating point type: + /// /// ``` /// let bitpattern = std::mem::transmute::(1.0); /// assert_eq!(bitpattern, 0x3F800000); @@ -436,6 +443,7 @@ extern "rust-intrinsic" { /// /// Turning a pointer into a function pointer (this isn't guaranteed to /// work in Rust, although, for example, Linux does make this guarantee): + /// /// ``` /// fn foo() -> i32 { /// 0 @@ -447,6 +455,7 @@ extern "rust-intrinsic" { /// /// Extending a lifetime, or shortening an invariant an invariant lifetime; /// this is advanced, very unsafe rust: + /// /// ``` /// use std::mem; /// From 15a49fefcb29590554d69081a7e26fcf4bfa0f65 Mon Sep 17 00:00:00 2001 From: ubsan Date: Tue, 5 Jul 2016 15:42:48 -0700 Subject: [PATCH 11/28] Tone it down a little --- src/libcore/intrinsics.rs | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 1ccdbb3411c8d..fd2d9cdb0d4b9 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -283,7 +283,7 @@ extern "rust-intrinsic" { /// [invalid value] /// (https://doc.rust-lang.org/nomicon/meet-safe-and-unsafe.html). /// - /// `transmute::(t)` is semantically equivalent to the following: + /// `transmute` is semantically equivalent to the following: /// /// ``` /// use std::{mem, ptr}; @@ -303,7 +303,7 @@ extern "rust-intrinsic" { /// the absolute last resort. /// /// The [nomicon](https://doc.rust-lang.org/nomicon/transmutes.html) has - /// more complete documentation. Read it before using `transmute`. + /// additional documentation. /// /// # Alternatives /// @@ -343,13 +343,13 @@ extern "rust-intrinsic" { /// ``` /// // this is not a good way to do this. /// let slice = unsafe { mem::transmute::<&str, &[u8]>("Rust") }; - /// assert_eq!(slice, [82, 117, 115, 116]); + /// assert_eq!(slice, &[82, 117, 115, 116]); /// // You could use `str::as_bytes` /// let slice = "Rust".as_bytes(); - /// assert_eq!(slice, [82, 117, 115, 116]); + /// assert_eq!(slice, &[82, 117, 115, 116]); /// // Or, just use a byte string, if you have control over the string /// // literal - /// assert_eq!(b"Rust", [82, 117, 116, 116]); + /// assert_eq!(b"Rust", &[82, 117, 116, 116]); /// ``` /// /// Turning a `Vec<&T>` into a `Vec>`: @@ -373,7 +373,7 @@ extern "rust-intrinsic" { /// // exact same size, and the same or lesser alignment, as the old /// // type. The same caveats exist for this method as transmute, for /// // the original inner type (`&i32`) to the converted inner type - /// // (`Option<&i32>`), so read the nomicon page linked above. + /// // (`Option<&i32>`), so read the nomicon pages linked above. /// let v_from_raw = Vec::from_raw_parts(v_orig.as_mut_ptr(), /// v_orig.len(), /// v_orig.capacity()); @@ -441,7 +441,7 @@ extern "rust-intrinsic" { /// assert_eq!(bitpattern, 0x3F800000); /// ``` /// - /// Turning a pointer into a function pointer (this isn't guaranteed to + /// Turning a pointer into a function pointer (this is not guaranteed to /// work in Rust, although, for example, Linux does make this guarantee): /// /// ``` @@ -453,8 +453,8 @@ extern "rust-intrinsic" { /// assert_eq!(function(), 0); /// ``` /// - /// Extending a lifetime, or shortening an invariant an invariant lifetime; - /// this is advanced, very unsafe rust: + /// Extending a lifetime, or shortening an invariant lifetime; this is + /// advanced, very unsafe rust: /// /// ``` /// use std::mem; @@ -464,11 +464,10 @@ extern "rust-intrinsic" { /// mem::transmute::, R<'static>>(ptr); /// } /// - /// unsafe fn shorten_invariant<'b, 'c>(r: &'b mut R<'static>) - /// -> &'b R<'c> { - /// let ref_to_original = - /// mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>( - /// ref_to_extended); + /// unsafe fn shorten_invariant_lifetime<'b, 'c>(r: &'b mut R<'static>) + /// -> &'b mut R<'c> { + /// mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>( + /// ref_to_extended) /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] From 451af791dadf5a38da2fe63d578c083b95d6c10a Mon Sep 17 00:00:00 2001 From: ubsan Date: Tue, 5 Jul 2016 16:04:58 -0700 Subject: [PATCH 12/28] Fix links, change example to english --- src/libcore/intrinsics.rs | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index fd2d9cdb0d4b9..875fa08f78980 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -278,32 +278,21 @@ extern "rust-intrinsic" { /// Moves a value out of scope without running drop glue. pub fn forget(_: T) -> (); - /// Reinterprets the bits of a value of one type as another type. Both types + /// Reinterprets the bits of a value of one type as another type; both types /// must have the same size. Neither the original, nor the result, may be an - /// [invalid value] - /// (https://doc.rust-lang.org/nomicon/meet-safe-and-unsafe.html). + /// [invalid value] (../../nomicon/meet-safe-and-unsafe.html). /// - /// `transmute` is semantically equivalent to the following: - /// - /// ``` - /// use std::{mem, ptr}; - /// // assuming that T and U are the same size - /// unsafe fn transmute(t: T) -> U { - /// let mut u: U = mem::uninitialized(); - /// ptr::copy_nonoverlapping(&t as *const T as *const u8, - /// &mut u as *mut U as *mut u8, - /// mem::size_of::()); - /// mem::forget(t); - /// u - /// } - /// ``` + /// `transmute` is semantically equivalent to a bitwise move of one type + /// into another. It copies the bits from the destination type into the + /// source type, then forgets the original. If you know C or C++, it's like + /// `memcpy` under the hood. /// /// `transmute` is incredibly unsafe. There are a vast number of ways to /// cause undefined behavior with this function. `transmute` should be /// the absolute last resort. /// - /// The [nomicon](https://doc.rust-lang.org/nomicon/transmutes.html) has - /// additional documentation. + /// The [nomicon](../../nomicon/transmutes.html) has additional + /// documentation. /// /// # Alternatives /// From 7eabff5b5ade1cdef3e4b4d3479c45798425ff6a Mon Sep 17 00:00:00 2001 From: ubsan Date: Tue, 5 Jul 2016 23:54:34 -0700 Subject: [PATCH 13/28] Hopefully, it now works --- src/libcore/intrinsics.rs | 73 ++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 31 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 875fa08f78980..953173f8aace8 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -304,7 +304,9 @@ extern "rust-intrinsic" { /// /// ``` /// let ptr = &0; - /// let ptr_num_transmute = mem::transmute::<&i32, usize>(ptr); + /// let ptr_num_transmute = unsafe { + /// std::mem::transmute::<&i32, usize>(ptr) + /// }; /// // Use an `as` cast instead /// let ptr_num_cast = ptr as *const i32 as usize; /// ``` @@ -313,43 +315,49 @@ extern "rust-intrinsic" { /// /// ``` /// let ptr: *mut i32 = &mut 0; - /// let ref_transmuted = mem::transmute::<*mut i32, &mut i32>(ptr); + /// let ref_transmuted = unsafe { + /// std::mem::transmute::<*mut i32, &mut i32>(ptr) + /// }; /// // Use a reborrow instead - /// let ref_casted = &mut *ptr; + /// let ref_casted = unsafe { &mut *ptr }; /// ``` /// /// Turning an `&mut T` into an `&mut U`: /// /// ``` /// let ptr = &mut 0; - /// let val_transmuted = mem::transmute::<&mut i32, &mut u32>(ptr); + /// let val_transmuted = unsafe { + /// std::mem::transmute::<&mut i32, &mut u32>(ptr) + /// }; /// // Now, put together `as` and reborrowing - /// let val_casts = &mut *(ptr as *mut i32 as *mut u32); + /// let val_casts = unsafe { &mut *(ptr as *mut i32 as *mut u32) }; /// ``` /// /// Turning an `&str` into an `&[u8]`: /// /// ``` /// // this is not a good way to do this. - /// let slice = unsafe { mem::transmute::<&str, &[u8]>("Rust") }; + /// let slice = unsafe { std::mem::transmute::<&str, &[u8]>("Rust") }; /// assert_eq!(slice, &[82, 117, 115, 116]); /// // You could use `str::as_bytes` /// let slice = "Rust".as_bytes(); /// assert_eq!(slice, &[82, 117, 115, 116]); /// // Or, just use a byte string, if you have control over the string /// // literal - /// assert_eq!(b"Rust", &[82, 117, 116, 116]); + /// assert_eq!(b"Rust", &[82, 117, 115, 116]); /// ``` /// /// Turning a `Vec<&T>` into a `Vec>`: /// /// ``` /// let store = [0, 1, 2, 3]; - /// let v_orig = store.iter().collect::>(); + /// let mut v_orig = store.iter().collect::>(); /// // Using transmute: this is Undefined Behavior, and a bad idea. /// // However, it is no-copy. - /// let v_transmuted = mem::transmute::, Vec>>( - /// v_orig.clone()); + /// let v_transmuted = unsafe { + /// std::mem::transmute::, Vec>>( + /// v_orig.clone()) + /// }; /// // This is the suggested, safe way. /// // It does copy the entire Vector, though, into a new array. /// let v_collected = v_orig.clone() @@ -363,10 +371,12 @@ extern "rust-intrinsic" { /// // type. The same caveats exist for this method as transmute, for /// // the original inner type (`&i32`) to the converted inner type /// // (`Option<&i32>`), so read the nomicon pages linked above. - /// let v_from_raw = Vec::from_raw_parts(v_orig.as_mut_ptr(), - /// v_orig.len(), - /// v_orig.capacity()); - /// mem::forget(v_orig); + /// let v_from_raw = unsafe { + /// Vec::from_raw_parts(v_orig.as_mut_ptr(), + /// v_orig.len(), + /// v_orig.capacity()) + /// }; + /// std::mem::forget(v_orig); /// ``` /// /// Implementing `split_at_mut`: @@ -375,39 +385,39 @@ extern "rust-intrinsic" { /// use std::{slice, mem}; /// // There are multiple ways to do this; and there are multiple problems /// // with the following, transmute, way. - /// fn split_at_mut_transmute(slice: &mut [T], index: usize) + /// fn split_at_mut_transmute(slice: &mut [T], mid: usize) /// -> (&mut [T], &mut [T]) { /// let len = slice.len(); - /// assert!(index < len); + /// assert!(mid <= len); /// unsafe { /// let slice2 = mem::transmute::<&mut [T], &mut [T]>(slice); /// // first: transmute is not typesafe; all it checks is that T and /// // U are of the same size. Second, right here, you have two /// // mutable references pointing to the same memory. - /// (&mut slice[0..index], &mut slice2[index..len]) + /// (&mut slice[0..mid], &mut slice2[mid..len]) /// } /// } /// // This gets rid of the typesafety problems; `&mut *` will *only* give /// // you an `&mut T` from an `&mut T` or `*mut T`. - /// fn split_at_mut_casts(slice: &mut [T], index: usize) + /// fn split_at_mut_casts(slice: &mut [T], mid: usize) /// -> (&mut [T], &mut [T]) { /// let len = slice.len(); - /// assert!(index < len); + /// assert!(mid <= len); /// unsafe { /// let slice2 = &mut *(slice as *mut [T]); /// // however, you still have two mutable references pointing to /// // the same memory. - /// (&mut slice[0..index], &mut slice2[index..len]) + /// (&mut slice[0..mid], &mut slice2[mid..len]) /// } /// } /// // This is how the standard library does it. This is the best method, if /// // you need to do something like this - /// fn split_at_stdlib(slice: &mut [T], index: usize) + /// fn split_at_stdlib(slice: &mut [T], mid: usize) /// -> (&mut [T], &mut [T]) { - /// let len = self.len(); - /// let ptr = self.as_mut_ptr(); + /// let len = slice.len(); + /// assert!(mid <= len); /// unsafe { - /// assert!(mid <= len); + /// let ptr = slice.as_mut_ptr(); /// // This now has three mutable references pointing at the same /// // memory. `slice`, the rvalue ret.0, and the rvalue ret.1. /// // `slice` is never used after `let ptr = ...`, and so one can @@ -426,7 +436,9 @@ extern "rust-intrinsic" { /// Getting the bitpattern of a floating point type: /// /// ``` - /// let bitpattern = std::mem::transmute::(1.0); + /// let bitpattern = unsafe { + /// std::mem::transmute::(1.0) + /// }; /// assert_eq!(bitpattern, 0x3F800000); /// ``` /// @@ -438,7 +450,9 @@ extern "rust-intrinsic" { /// 0 /// } /// let pointer = foo as *const (); - /// let function = std::mem::transmute::<*const (), fn() -> i32>(pointer) + /// let function = unsafe { + /// std::mem::transmute::<*const (), fn() -> i32>(pointer) + /// }; /// assert_eq!(function(), 0); /// ``` /// @@ -446,17 +460,14 @@ extern "rust-intrinsic" { /// advanced, very unsafe rust: /// /// ``` - /// use std::mem; - /// /// struct R<'a>(&'a i32); /// unsafe fn extend_lifetime<'b>(r: R<'b>) -> R<'static> { - /// mem::transmute::, R<'static>>(ptr); + /// std::mem::transmute::, R<'static>>(r) /// } /// /// unsafe fn shorten_invariant_lifetime<'b, 'c>(r: &'b mut R<'static>) /// -> &'b mut R<'c> { - /// mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>( - /// ref_to_extended) + /// std::mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>(r) /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] From b4ff6b028ed6ae2e67d97604ad6bfbd235bb4f74 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Fri, 8 Jul 2016 23:14:32 -0400 Subject: [PATCH 14/28] document DoubleEndedIterator::next_back fixes #34726 --- src/libcore/iter/traits.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index 9b5c2128f1eaf..43360b91fdaaa 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -386,10 +386,11 @@ pub trait Extend { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait DoubleEndedIterator: Iterator { - /// An iterator able to yield elements from both ends. + /// Removes and returns an element from the end of the iterator. /// - /// As this is the only method for this trait, the [trait-level] docs - /// contain more details. + /// Returns `None` when there are no more elements. + /// + /// The [trait-level] docs contain more details. /// /// [trait-level]: trait.DoubleEndedIterator.html /// From 97003e56991d3e475f2d4bb18a88c768018041e9 Mon Sep 17 00:00:00 2001 From: ubsan Date: Sun, 10 Jul 2016 06:13:34 +0200 Subject: [PATCH 15/28] Switch around Examples and Alternatives --- src/libcore/intrinsics.rs | 93 ++++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 45 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 953173f8aace8..ab7545d37dc9e 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -294,11 +294,56 @@ extern "rust-intrinsic" { /// The [nomicon](../../nomicon/transmutes.html) has additional /// documentation. /// + /// # Examples + /// + /// There are a few things that `transmute` is really useful for. + /// + /// Getting the bitpattern of a floating point type (or, more generally, + /// type punning, when T and U aren't pointers): + /// + /// ``` + /// let bitpattern = unsafe { + /// std::mem::transmute::(1.0) + /// }; + /// assert_eq!(bitpattern, 0x3F800000); + /// ``` + /// + /// Turning a pointer into a function pointer: + /// + /// ``` + /// fn foo() -> i32 { + /// 0 + /// } + /// let pointer = foo as *const (); + /// let function = unsafe { + /// std::mem::transmute::<*const (), fn() -> i32>(pointer) + /// }; + /// assert_eq!(function(), 0); + /// ``` + /// + /// Extending a lifetime, or shortening an invariant lifetime; this is + /// advanced, very unsafe rust: + /// + /// ``` + /// struct R<'a>(&'a i32); + /// unsafe fn extend_lifetime<'b>(r: R<'b>) -> R<'static> { + /// std::mem::transmute::, R<'static>>(r) + /// } + /// + /// unsafe fn shorten_invariant_lifetime<'b, 'c>(r: &'b mut R<'static>) + /// -> &'b mut R<'c> { + /// std::mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>(r) + /// } + /// ``` + /// /// # Alternatives /// - /// There are very few good cases for `transmute`. Most can be achieved - /// through other means. Some more or less common uses, and a better way, - /// are as follows: + /// However, many uses of `transmute` can be achieved through other means. + /// This is unfortunate because either `transmute` isn't guaranteed to work + /// in that case, and only does because of rustc's current implemenation; + /// or, more commonly, `transmute` is just too powerful. It can transform + /// any type into any other, with just the caveat that they're the same + /// size. Some more or less common uses, and a better way, are as follows: /// /// Turning a pointer into a `usize`: /// @@ -428,48 +473,6 @@ extern "rust-intrinsic" { /// } /// } /// ``` - /// - /// # Examples - /// - /// There are valid uses of transmute, though they are few and far between. - /// - /// Getting the bitpattern of a floating point type: - /// - /// ``` - /// let bitpattern = unsafe { - /// std::mem::transmute::(1.0) - /// }; - /// assert_eq!(bitpattern, 0x3F800000); - /// ``` - /// - /// Turning a pointer into a function pointer (this is not guaranteed to - /// work in Rust, although, for example, Linux does make this guarantee): - /// - /// ``` - /// fn foo() -> i32 { - /// 0 - /// } - /// let pointer = foo as *const (); - /// let function = unsafe { - /// std::mem::transmute::<*const (), fn() -> i32>(pointer) - /// }; - /// assert_eq!(function(), 0); - /// ``` - /// - /// Extending a lifetime, or shortening an invariant lifetime; this is - /// advanced, very unsafe rust: - /// - /// ``` - /// struct R<'a>(&'a i32); - /// unsafe fn extend_lifetime<'b>(r: R<'b>) -> R<'static> { - /// std::mem::transmute::, R<'static>>(r) - /// } - /// - /// unsafe fn shorten_invariant_lifetime<'b, 'c>(r: &'b mut R<'static>) - /// -> &'b mut R<'c> { - /// std::mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>(r) - /// } - /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn transmute(e: T) -> U; From c0bee60adbf979ae624cfcdc7610044c357794a0 Mon Sep 17 00:00:00 2001 From: ubsan Date: Sun, 10 Jul 2016 23:17:02 +0200 Subject: [PATCH 16/28] Make it nicer from @alexandermerritt --- src/libcore/intrinsics.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index ab7545d37dc9e..d6fb1816b5fa0 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -339,11 +339,11 @@ extern "rust-intrinsic" { /// # Alternatives /// /// However, many uses of `transmute` can be achieved through other means. - /// This is unfortunate because either `transmute` isn't guaranteed to work - /// in that case, and only does because of rustc's current implemenation; - /// or, more commonly, `transmute` is just too powerful. It can transform + /// `transmute` can transform /// any type into any other, with just the caveat that they're the same - /// size. Some more or less common uses, and a better way, are as follows: + /// size, and it sometimes results in interesting results. Below are common + /// applications of `transmute` which can be replaced with safe applications + /// of `as`: /// /// Turning a pointer into a `usize`: /// @@ -374,7 +374,8 @@ extern "rust-intrinsic" { /// let val_transmuted = unsafe { /// std::mem::transmute::<&mut i32, &mut u32>(ptr) /// }; - /// // Now, put together `as` and reborrowing + /// // Now, put together `as` and reborrowing - note the chaining of `as` + /// // `as` is not transitive /// let val_casts = unsafe { &mut *(ptr as *mut i32 as *mut u32) }; /// ``` /// From 010e479fa270c8e93237cbacbef8fec37f57cf73 Mon Sep 17 00:00:00 2001 From: Ryan Scheel Date: Sun, 17 Jul 2016 16:47:38 -0700 Subject: [PATCH 17/28] Merge guidelines from RFC 1567 into UX Guidelines. This is a partial fix for issue #34808. Most of the wording was copied verbatim from the RFC. Main difference is that I moved the actual template to the top of the section. It also makes the error explanations the longest section in the guidelines doc for now. --- src/doc/rustc-ux-guidelines.md | 122 +++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) diff --git a/src/doc/rustc-ux-guidelines.md b/src/doc/rustc-ux-guidelines.md index 15b3bfebfac2e..3e8f304d9e3d2 100644 --- a/src/doc/rustc-ux-guidelines.md +++ b/src/doc/rustc-ux-guidelines.md @@ -56,6 +56,10 @@ Error explanations are long form descriptions of error messages provided with the compiler. They are accessible via the `--explain` flag. Each explanation comes with an example of how to trigger it and advice on how to fix it. +Long error codes explanations are a very important part of Rust. Having an +explanation of what failed helps to understand the error and is appreciated by +Rust developers of all skill levels. + * All of them are accessible [online](http://doc.rust-lang.org/error-index.html), which are auto-generated from rustc source code in different places: [librustc](https://github.com/rust-lang/rust/blob/master/src/librustc/diagnostics.rs), @@ -74,6 +78,124 @@ code with backticks. * When talking about the compiler, call it `the compiler`, not `Rust` or `rustc`. +Note: The following sections are mostly a repaste of [RFC 1567](https://github.com/rust-lang/rfcs/blob/master/text/1567-long-error-codes-explanation-normalization.md). + +### Template + +Long error descriptions should match the following template. The next few +sections of this document describe what each section is about. + +```rust +E000: r##" +[Error description] + +Example of erroneous code: + +\```compile_fail +[Minimal example] +\``` + +[Error explanation] + +\``` +[How to fix the problem] +\``` + +[Optional Additional information] +``` + +### Error description + +Provide a more detailed error message. For example: + +```rust +extern crate a; +extern crate b as a; +``` + +We get the `E0259` error code which says "an extern crate named `a` has already been imported in this module" and the error explanation says: "The name chosen for an external crate conflicts with another external crate that has been imported into the current module.". + +### Minimal example + +Provide an erroneous code example which directly follows `Error description`. The erroneous example will be helpful for the `How to fix the problem`. Making it as simple as possible is really important in order to help readers to understand what the error is about. A comment should be added with the error on the same line where the errors occur. Example: + +```rust +type X = u32; // error: type parameters are not allowed on this type +``` + +If the error comments is too long to fit 80 columns, split it up like this, so the next line start at the same column of the previous line: + +```rust +type X = u32<'static>; // error: lifetime parameters are not allowed on + // this type +``` + +And if the sample code is too long to write an effective comment, place your comment on the line before the sample code: + +```rust +// error: lifetime parameters are not allowed on this type +fn super_long_function_name_and_thats_problematic() {} +``` + +Of course, it the comment is too long, the split rules still applies. + +### Error explanation + +Provide a full explanation about "__why__ you get the error" and some leads on __how__ to fix it. If needed, use additional code snippets to improve your explanations. + +### How to fix the problem + +This part will show how to fix the error that we saw previously in the `Minimal example`, with comments explaining how it was fixed. + +### Additional information + +Some details which might be useful for the users, let's take back `E0109` example. At the end, the supplementary explanation is the following: "Note that type parameters for enum-variant constructors go after the variant, not after the enum (`Option::None::`, not `Option::::None`).". It provides more information, not directly linked to the error, but it might help user to avoid doing another error. + +### Full Example + +Now let's take a full example: + +> E0409: r##" +> An "or" pattern was used where the variable bindings are not consistently bound +> across patterns. +> +> Example of erroneous code: +> +> ```compile_fail +> let x = (0, 2); +> match x { +> (0, ref y) | (y, 0) => { /* use y */} // error: variable `y` is bound with +> // different mode in pattern #2 +> // than in pattern #1 +> _ => () +> } +> ``` +> +> Here, `y` is bound by-value in one case and by-reference in the other. +> +> To fix this error, just use the same mode in both cases. +> Generally using `ref` or `ref mut` where not already used will fix this: +> +> ```ignore +> let x = (0, 2); +> match x { +> (0, ref y) | (ref y, 0) => { /* use y */} +> _ => () +> } +> ``` +> +> Alternatively, split the pattern: +> +> ``` +> let x = (0, 2); +> match x { +> (y, 0) => { /* use y */ } +> (0, ref y) => { /* use y */} +> _ => () +> } +> ``` +> "##, + ## Compiler Flags * Flags should be orthogonal to each other. For example, if we'd have a From b0de62064cc2ccba33a141bbde169e88b81d0b86 Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Sat, 16 Jul 2016 11:18:53 +0200 Subject: [PATCH 18/28] doc: add missing pause --- src/doc/nomicon/phantom-data.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/doc/nomicon/phantom-data.md b/src/doc/nomicon/phantom-data.md index d565532017a65..189695716deb1 100644 --- a/src/doc/nomicon/phantom-data.md +++ b/src/doc/nomicon/phantom-data.md @@ -50,7 +50,7 @@ struct Vec { } ``` -Unlike the previous example it *appears* that everything is exactly as we +Unlike the previous example, it *appears* that everything is exactly as we want. Every generic argument to Vec shows up in at least one field. Good to go! @@ -84,4 +84,3 @@ standard library made a utility for itself called `Unique` which: * includes a `PhantomData` * auto-derives Send/Sync as if T was contained * marks the pointer as NonZero for the null-pointer optimization - From 24f8589bf3d4a198721a5ebe84679817cd1e205b Mon Sep 17 00:00:00 2001 From: ubsan Date: Thu, 21 Jul 2016 12:57:42 -0700 Subject: [PATCH 19/28] Fix nits --- src/libcore/intrinsics.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index d6fb1816b5fa0..6a1d94a2e44d8 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -284,8 +284,8 @@ extern "rust-intrinsic" { /// /// `transmute` is semantically equivalent to a bitwise move of one type /// into another. It copies the bits from the destination type into the - /// source type, then forgets the original. If you know C or C++, it's like - /// `memcpy` under the hood. + /// source type, then forgets the original. It's equivalent to C's `memcpy` + /// under the hood, just like `transmute_copy`. /// /// `transmute` is incredibly unsafe. There are a vast number of ways to /// cause undefined behavior with this function. `transmute` should be @@ -299,7 +299,7 @@ extern "rust-intrinsic" { /// There are a few things that `transmute` is really useful for. /// /// Getting the bitpattern of a floating point type (or, more generally, - /// type punning, when T and U aren't pointers): + /// type punning, when `T` and `U` aren't pointers): /// /// ``` /// let bitpattern = unsafe { @@ -339,11 +339,10 @@ extern "rust-intrinsic" { /// # Alternatives /// /// However, many uses of `transmute` can be achieved through other means. - /// `transmute` can transform - /// any type into any other, with just the caveat that they're the same - /// size, and it sometimes results in interesting results. Below are common - /// applications of `transmute` which can be replaced with safe applications - /// of `as`: + /// `transmute` can transform any type into any other, with just the caveat + /// that they're the same size, and often interesting results occur. Below + /// are common applications of `transmute` which can be replaced with safe + /// applications of `as`: /// /// Turning a pointer into a `usize`: /// From 0d192c34991aef87a06e1a3e2396228b03508796 Mon Sep 17 00:00:00 2001 From: abhi Date: Fri, 22 Jul 2016 17:50:54 +0530 Subject: [PATCH 20/28] Update VecDeque documentation to specify direction of index 0 (#34920) --- src/libcollections/vec_deque.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index 9e4428ec57d50..9c3792afa2f1c 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -402,6 +402,8 @@ impl VecDeque { /// Retrieves an element in the `VecDeque` by index. /// + /// Element at index 0 is the front of the queue. + /// /// # Examples /// /// ``` @@ -425,6 +427,8 @@ impl VecDeque { /// Retrieves an element in the `VecDeque` mutably by index. /// + /// Element at index 0 is the front of the queue. + /// /// # Examples /// /// ``` @@ -456,6 +460,8 @@ impl VecDeque { /// /// Fails if there is no element with either index. /// + /// Element at index 0 is the front of the queue. + /// /// # Examples /// /// ``` @@ -1180,6 +1186,8 @@ impl VecDeque { /// /// Returns `None` if `index` is out of bounds. /// + /// Element at index 0 is the front of the queue. + /// /// # Examples /// /// ``` @@ -1214,6 +1222,8 @@ impl VecDeque { /// /// Returns `None` if `index` is out of bounds. /// + /// Element at index 0 is the front of the queue. + /// /// # Examples /// /// ``` @@ -1245,6 +1255,8 @@ impl VecDeque { /// end is closer to the insertion point will be moved to make room, /// and all the affected elements will be moved to new positions. /// + /// Element at index 0 is the front of the queue. + /// /// # Panics /// /// Panics if `index` is greater than `VecDeque`'s length @@ -1472,6 +1484,8 @@ impl VecDeque { /// room, and all the affected elements will be moved to new positions. /// Returns `None` if `index` is out of bounds. /// + /// Element at index 0 is the front of the queue. + /// /// # Examples /// /// ``` @@ -1651,6 +1665,8 @@ impl VecDeque { /// /// Note that the capacity of `self` does not change. /// + /// Element at index 0 is the front of the queue. + /// /// # Panics /// /// Panics if `at > len` From ec33dab062aba12ff248a4fd3cb04c7c8d0dfd27 Mon Sep 17 00:00:00 2001 From: ggomez Date: Wed, 20 Jul 2016 14:44:15 +0200 Subject: [PATCH 21/28] Add HashMap Entry enums examples --- src/libstd/collections/hash/map.rs | 203 ++++++++++++++++++++++++++++- 1 file changed, 198 insertions(+), 5 deletions(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 60d7e01d98814..a4aa434d6c47f 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1336,6 +1336,10 @@ impl<'a, K, V> InternalEntry> { } /// A view into a single location in a map, which may be vacant or occupied. +/// This enum is constructed from the [`entry`] method on [`HashMap`]. +/// +/// [`HashMap`]: struct.HashMap.html +/// [`entry`]: struct.HashMap.html#method.entry #[stable(feature = "rust1", since = "1.0.0")] pub enum Entry<'a, K: 'a, V: 'a> { /// An occupied Entry. @@ -1352,6 +1356,9 @@ pub enum Entry<'a, K: 'a, V: 'a> { } /// A view into a single occupied location in a HashMap. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html #[stable(feature = "rust1", since = "1.0.0")] pub struct OccupiedEntry<'a, K: 'a, V: 'a> { key: Option, @@ -1359,6 +1366,9 @@ pub struct OccupiedEntry<'a, K: 'a, V: 'a> { } /// A view into a single empty location in a HashMap. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html #[stable(feature = "rust1", since = "1.0.0")] pub struct VacantEntry<'a, K: 'a, V: 'a> { hash: SafeHash, @@ -1518,6 +1528,20 @@ impl<'a, K, V> Entry<'a, K, V> { #[stable(feature = "rust1", since = "1.0.0")] /// Ensures a value is in the entry by inserting the default if empty, and returns /// a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// + /// *map.entry("poneyland").or_insert(12) += 10; + /// assert_eq!(map["poneyland"], 22); + /// ``` pub fn or_insert(self, default: V) -> &'a mut V { match self { Occupied(entry) => entry.into_mut(), @@ -1528,6 +1552,19 @@ impl<'a, K, V> Entry<'a, K, V> { #[stable(feature = "rust1", since = "1.0.0")] /// Ensures a value is in the entry by inserting the result of the default function if empty, /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map: HashMap<&str, String> = HashMap::new(); + /// let s = "hoho".to_owned(); + /// + /// map.entry("poneyland").or_insert_with(|| s); + /// + /// assert_eq!(map["poneyland"], "hoho".to_owned()); + /// ``` pub fn or_insert_with V>(self, default: F) -> &'a mut V { match self { Occupied(entry) => entry.into_mut(), @@ -1536,6 +1573,15 @@ impl<'a, K, V> Entry<'a, K, V> { } /// Returns a reference to this entry's key. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// ``` #[stable(feature = "map_entry_keys", since = "1.10.0")] pub fn key(&self) -> &K { match *self { @@ -1547,37 +1593,130 @@ impl<'a, K, V> Entry<'a, K, V> { impl<'a, K, V> OccupiedEntry<'a, K, V> { /// Gets a reference to the key in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// ``` #[stable(feature = "map_entry_keys", since = "1.10.0")] pub fn key(&self) -> &K { self.elem.read().0 } /// Take the ownership of the key and value from the map. + /// + /// # Examples + /// + /// ``` + /// #![feature(map_entry_recover_keys)] + /// + /// use std::collections::HashMap; + /// use std::collections::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// // We delete the entry from the map. + /// o.remove_pair(); + /// } + /// + /// assert_eq!(map.contains_key("poneyland"), false); + /// ``` #[unstable(feature = "map_entry_recover_keys", issue = "34285")] pub fn remove_pair(self) -> (K, V) { pop_internal(self.elem) } /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::collections::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// assert_eq!(o.get(), &12); + /// } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get(&self) -> &V { self.elem.read().1 } /// Gets a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::collections::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let Entry::Occupied(mut o) = map.entry("poneyland") { + /// *o.get_mut() += 10; + /// } + /// + /// assert_eq!(map["poneyland"], 22); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self) -> &mut V { self.elem.read_mut().1 } /// Converts the OccupiedEntry into a mutable reference to the value in the entry - /// with a lifetime bound to the map itself + /// with a lifetime bound to the map itself. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::collections::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// *o.into_mut() += 10; + /// } + /// + /// assert_eq!(map["poneyland"], 22); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn into_mut(self) -> &'a mut V { self.elem.into_mut_refs().1 } - /// Sets the value of the entry, and returns the entry's old value + /// Sets the value of the entry, and returns the entry's old value. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::collections::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(mut o) = map.entry("poneyland") { + /// assert_eq!(o.insert(15), 12); + /// } + /// + /// assert_eq!(map["poneyland"], 15); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(&mut self, mut value: V) -> V { let old_value = self.get_mut(); @@ -1585,7 +1724,23 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { value } - /// Takes the value out of the entry, and returns it + /// Takes the value out of the entry, and returns it. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::collections::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// assert_eq!(o.remove(), 12); + /// } + /// + /// assert_eq!(map.contains_key("poneyland"), false); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn remove(self) -> V { pop_internal(self.elem).1 @@ -1601,20 +1756,58 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { /// Gets a reference to the key that would be used when inserting a value - /// through the VacantEntry. + /// through the `VacantEntry`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// ``` #[stable(feature = "map_entry_keys", since = "1.10.0")] pub fn key(&self) -> &K { &self.key } /// Take ownership of the key. + /// + /// # Examples + /// + /// ``` + /// #![feature(map_entry_recover_keys)] + /// + /// use std::collections::HashMap; + /// use std::collections::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let Entry::Vacant(v) = map.entry("poneyland") { + /// v.into_key(); + /// } + /// ``` #[unstable(feature = "map_entry_recover_keys", issue = "34285")] pub fn into_key(self) -> K { self.key } /// Sets the value of the entry with the VacantEntry's key, - /// and returns a mutable reference to it + /// and returns a mutable reference to it. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::collections::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let Entry::Vacant(o) = map.entry("poneyland") { + /// o.insert(37); + /// } + /// assert_eq!(map["poneyland"], 37); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(self, value: V) -> &'a mut V { match self.elem { From 90bb8d469c495f48cf0da67c7811fd887a8b0655 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 23 Jul 2016 01:57:21 +0200 Subject: [PATCH 22/28] Add DirBuilder doc examples --- src/libstd/fs.rs | 19 ++++++++++++++++++- src/libstd/sys/unix/ext/fs.rs | 10 ++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index c28f70b8692ad..c74e508a69b30 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -1397,6 +1397,14 @@ pub fn set_permissions>(path: P, perm: Permissions) impl DirBuilder { /// Creates a new set of options with default mode/security settings for all /// platforms and also non-recursive. + /// + /// # Examples + /// + /// ``` + /// use std::fs::DirBuilder; + /// + /// let builder = DirBuilder::new(); + /// ``` #[stable(feature = "dir_builder", since = "1.6.0")] pub fn new() -> DirBuilder { DirBuilder { @@ -1409,7 +1417,16 @@ impl DirBuilder { /// all parent directories if they do not exist with the same security and /// permissions settings. /// - /// This option defaults to `false` + /// This option defaults to `false`. + /// + /// # Examples + /// + /// ``` + /// use std::fs::DirBuilder; + /// + /// let mut builder = DirBuilder::new(); + /// builder.recursive(true); + /// ``` #[stable(feature = "dir_builder", since = "1.6.0")] pub fn recursive(&mut self, recursive: bool) -> &mut Self { self.recursive = recursive; diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs index bb90a977433e0..d1f26fec249a9 100644 --- a/src/libstd/sys/unix/ext/fs.rs +++ b/src/libstd/sys/unix/ext/fs.rs @@ -239,6 +239,16 @@ pub fn symlink, Q: AsRef>(src: P, dst: Q) -> io::Result<()> pub trait DirBuilderExt { /// Sets the mode to create new directories with. This option defaults to /// 0o777. + /// + /// # Examples + /// + /// ```ignore + /// use std::fs::DirBuilder; + /// use std::os::unix::fs::DirBuilderExt; + /// + /// let mut builder = DirBuilder::new(); + /// builder.mode(0o755); + /// ``` #[stable(feature = "dir_builder", since = "1.6.0")] fn mode(&mut self, mode: u32) -> &mut Self; } From 6ebe6e8f8041a7a7058cbc1ec481751de45fb5ef Mon Sep 17 00:00:00 2001 From: abhi Date: Sat, 23 Jul 2016 13:15:09 +0530 Subject: [PATCH 23/28] Update underscore usage (#34903) --- src/doc/book/syntax-index.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/book/syntax-index.md b/src/doc/book/syntax-index.md index 3e889f51f542d..0259db221b6bc 100644 --- a/src/doc/book/syntax-index.md +++ b/src/doc/book/syntax-index.md @@ -94,7 +94,7 @@ * `|` (`|…| expr`): closures. See [Closures]. * `|=` (`var |= expr`): bitwise or & assignment. Overloadable (`BitOrAssign`). * `||` (`expr || expr`): logical or. -* `_`: "ignored" pattern binding. See [Patterns (Ignoring bindings)]. +* `_`: "ignored" pattern binding (see [Patterns (Ignoring bindings)]). Also used to make integer-literals readable (see [Reference (Integer literals)]). ## Other Syntax @@ -231,6 +231,7 @@ [Primitive Types (Tuples)]: primitive-types.html#tuples [Raw Pointers]: raw-pointers.html [Reference (Byte String Literals)]: ../reference.html#byte-string-literals +[Reference (Integer literals)]: ../reference.html#integer-literals [Reference (Raw Byte String Literals)]: ../reference.html#raw-byte-string-literals [Reference (Raw String Literals)]: ../reference.html#raw-string-literals [References and Borrowing]: references-and-borrowing.html From ccc955c84c3edb1aab58a5e6afe08cc1f57b7697 Mon Sep 17 00:00:00 2001 From: Robert Williamson Date: Sat, 23 Jul 2016 16:13:25 -0600 Subject: [PATCH 24/28] Fix HashMap's values_mut example to use println! --- src/libstd/collections/hash/map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index a03249e006356..97af99030c8f7 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -877,7 +877,7 @@ impl HashMap /// } /// /// for val in map.values() { - /// print!("{}", val); + /// println!("{}", val); /// } /// ``` #[stable(feature = "map_values_mut", since = "1.10.0")] From dad29a6d03429874ddf5ce6f53045bae2e0d6fac Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 24 Jul 2016 16:07:06 +0200 Subject: [PATCH 25/28] Add missing links --- src/libstd/fs.rs | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index c28f70b8692ad..d1453b05a791d 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -58,28 +58,37 @@ pub struct File { /// Metadata information about a file. /// -/// This structure is returned from the `metadata` function or method and +/// This structure is returned from the [`metadata`] function or method and /// represents known metadata about a file such as its permissions, size, /// modification times, etc. +/// +/// [`metadata`]: fn.metadata.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] pub struct Metadata(fs_imp::FileAttr); /// Iterator over the entries in a directory. /// -/// This iterator is returned from the `read_dir` function of this module and -/// will yield instances of `io::Result`. Through a `DirEntry` +/// This iterator is returned from the [`read_dir`] function of this module and +/// will yield instances of `io::Result`. Through a [`DirEntry`] /// information like the entry's path and possibly other metadata can be /// learned. /// +/// [`read_dir`]: fn.read_dir.html +/// [`DirEntry`]: struct.DirEntry.html +/// /// # Errors /// -/// This `io::Result` will be an `Err` if there's some sort of intermittent +/// This [`io::Result`] will be an `Err` if there's some sort of intermittent /// IO error during iteration. +/// +/// [`io::Result`]: ../io/type.Result.html #[stable(feature = "rust1", since = "1.0.0")] pub struct ReadDir(fs_imp::ReadDir); -/// Entries returned by the `ReadDir` iterator. +/// Entries returned by the [`ReadDir`] iterator. +/// +/// [`ReadDir`]: struct.ReadDir.html /// /// An instance of `DirEntry` represents an entry inside of a directory on the /// filesystem. Each entry can be inspected via methods to learn about the full @@ -89,17 +98,23 @@ pub struct DirEntry(fs_imp::DirEntry); /// Options and flags which can be used to configure how a file is opened. /// -/// This builder exposes the ability to configure how a `File` is opened and -/// what operations are permitted on the open file. The `File::open` and -/// `File::create` methods are aliases for commonly used options using this +/// This builder exposes the ability to configure how a [`File`] is opened and +/// what operations are permitted on the open file. The [`File::open`] and +/// [`File::create`] methods are aliases for commonly used options using this /// builder. /// -/// Generally speaking, when using `OpenOptions`, you'll first call `new()`, -/// then chain calls to methods to set each option, then call `open()`, passing -/// the path of the file you're trying to open. This will give you a +/// [`File`]: struct.File.html +/// [`File::open`]: struct.File.html#method.open +/// [`File::create`]: struct.File.html#method.create +/// +/// Generally speaking, when using `OpenOptions`, you'll first call [`new()`], +/// then chain calls to methods to set each option, then call [`open()`], +/// passing the path of the file you're trying to open. This will give you a /// [`io::Result`][result] with a [`File`][file] inside that you can further /// operate on. /// +/// [`new()`]: struct.OpenOptions.html#method.new +/// [`open()`]: struct.OpenOptions.html#method.open /// [result]: ../io/type.Result.html /// [file]: struct.File.html /// @@ -131,10 +146,12 @@ pub struct OpenOptions(fs_imp::OpenOptions); /// Representation of the various permissions on a file. /// -/// This module only currently provides one bit of information, `readonly`, +/// This module only currently provides one bit of information, [`readonly`], /// which is exposed on all currently supported platforms. Unix-specific /// functionality, such as mode bits, is available through the /// `os::unix::PermissionsExt` trait. +/// +/// [`readonly`]: struct.Permissions.html#method.readonly #[derive(Clone, PartialEq, Eq, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Permissions(fs_imp::FilePermissions); From 16699635bc467b0940c11675dd73e7e444088c4e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 24 Jul 2016 16:52:28 +0200 Subject: [PATCH 26/28] Add DirEntry doc examples --- src/libstd/fs.rs | 55 +++++++++++++++++++++++++++++++++++ src/libstd/sys/unix/ext/fs.rs | 16 ++++++++++ 2 files changed, 71 insertions(+) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index d1453b05a791d..6547cb6acbe44 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -846,6 +846,26 @@ impl DirEntry { /// On Windows this function is cheap to call (no extra system calls /// needed), but on Unix platforms this function is the equivalent of /// calling `symlink_metadata` on the path. + /// + /// # Examples + /// + /// ``` + /// use std::fs; + /// + /// if let Ok(entries) = fs::read_dir(".") { + /// for entry in entries { + /// if let Ok(entry) = entry { + /// // Here, `entry` is a `DirEntry`. + /// if let Ok(metadata) = entry.metadata() { + /// // Now let's show our entry's permissions! + /// println!("{:?}: {:?}", entry.path(), metadata.permissions()); + /// } else { + /// println!("Couldn't get metadata for {:?}", entry.path()); + /// } + /// } + /// } + /// } + /// ``` #[stable(feature = "dir_entry_ext", since = "1.1.0")] pub fn metadata(&self) -> io::Result { self.0.metadata().map(Metadata) @@ -861,6 +881,26 @@ impl DirEntry { /// On Windows and most Unix platforms this function is free (no extra /// system calls needed), but some Unix platforms may require the equivalent /// call to `symlink_metadata` to learn about the target file type. + /// + /// # Examples + /// + /// ``` + /// use std::fs; + /// + /// if let Ok(entries) = fs::read_dir(".") { + /// for entry in entries { + /// if let Ok(entry) = entry { + /// // Here, `entry` is a `DirEntry`. + /// if let Ok(file_type) = entry.file_type() { + /// // Now let's show our entry's file type! + /// println!("{:?}: {:?}", entry.path(), file_type); + /// } else { + /// println!("Couldn't get file type for {:?}", entry.path()); + /// } + /// } + /// } + /// } + /// ``` #[stable(feature = "dir_entry_ext", since = "1.1.0")] pub fn file_type(&self) -> io::Result { self.0.file_type().map(FileType) @@ -868,6 +908,21 @@ impl DirEntry { /// Returns the bare file name of this directory entry without any other /// leading path component. + /// + /// # Examples + /// + /// ``` + /// use std::fs; + /// + /// if let Ok(entries) = fs::read_dir(".") { + /// for entry in entries { + /// if let Ok(entry) = entry { + /// // Here, `entry` is a `DirEntry`. + /// println!("{:?}", entry.file_name()); + /// } + /// } + /// } + /// ``` #[stable(feature = "dir_entry_ext", since = "1.1.0")] pub fn file_name(&self) -> OsString { self.0.file_name() diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs index bb90a977433e0..17c093e6cac68 100644 --- a/src/libstd/sys/unix/ext/fs.rs +++ b/src/libstd/sys/unix/ext/fs.rs @@ -196,6 +196,22 @@ impl FileTypeExt for fs::FileType { pub trait DirEntryExt { /// Returns the underlying `d_ino` field in the contained `dirent` /// structure. + /// + /// # Examples + /// + /// ``` + /// use std::fs; + /// use std::os::unix::fs::DirEntryExt; + /// + /// if let Ok(entries) = fs::read_dir(".") { + /// for entry in entries { + /// if let Ok(entry) = entry { + /// // Here, `entry` is a `DirEntry`. + /// println!("{:?}: {}", entry.file_name(), entry.ino()); + /// } + /// } + /// } + /// ``` #[stable(feature = "dir_entry_ext", since = "1.1.0")] fn ino(&self) -> u64; } From debb2ac76bd8b4ef8de0f470351a2b187afc91df Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 24 Jul 2016 17:00:49 +0200 Subject: [PATCH 27/28] Improve Open doc --- src/libstd/fs.rs | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index c28f70b8692ad..4d4d44bae309a 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -156,12 +156,14 @@ pub struct DirBuilder { impl File { /// Attempts to open a file in read-only mode. /// - /// See the `OpenOptions::open` method for more details. + /// See the [`OpenOptions::open`] method for more details. /// /// # Errors /// /// This function will return an error if `path` does not already exist. - /// Other errors may also be returned according to `OpenOptions::open`. + /// Other errors may also be returned according to [`OpenOptions::open`]. + /// + /// [`OpenOptions::open`]: struct.OpenOptions.html#method.open /// /// # Examples /// @@ -183,7 +185,9 @@ impl File { /// This function will create a file if it does not exist, /// and will truncate it if it does. /// - /// See the `OpenOptions::open` function for more details. + /// See the [`OpenOptions::open`] function for more details. + /// + /// [`OpenOptions::open`]: struct.OpenOptions.html#method.open /// /// # Examples /// @@ -224,7 +228,7 @@ impl File { self.inner.fsync() } - /// This function is similar to `sync_all`, except that it may not + /// This function is similar to [`sync_all`], except that it may not /// synchronize file metadata to the filesystem. /// /// This is intended for use cases that must synchronize content, but don't @@ -232,7 +236,9 @@ impl File { /// operations. /// /// Note that some platforms may simply implement this in terms of - /// `sync_all`. + /// [`sync_all`]. + /// + /// [`sync_all`]: struct.File.html#method.sync_all /// /// # Examples /// @@ -304,6 +310,18 @@ impl File { /// The returned `File` is a reference to the same state that this object /// references. Both handles will read and write with the same cursor /// position. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut f = try!(File::open("foo.txt")); + /// let file_copy = try!(f.try_clone()); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "file_try_clone", since = "1.9.0")] pub fn try_clone(&self) -> io::Result { Ok(File { From 96932cf3d0fa247c30a117e78fe23020b865f2ee Mon Sep 17 00:00:00 2001 From: abhi Date: Mon, 25 Jul 2016 15:00:32 +0530 Subject: [PATCH 28/28] Remove no_stack_check tests (#34915) Part of fixes for #34915 --- ...nction-prologue-stepping-no-stack-check.rs | 369 ------------------ 1 file changed, 369 deletions(-) delete mode 100644 src/test/debuginfo/function-prologue-stepping-no-stack-check.rs diff --git a/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs b/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs deleted file mode 100644 index b5b6ca7572703..0000000000000 --- a/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs +++ /dev/null @@ -1,369 +0,0 @@ -// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// ignore-android: FIXME(#10381) -// min-lldb-version: 310 - -// This test case checks if function arguments already have the correct value -// when breaking at the beginning of a function. Functions with the -// #[no_stack_check] attribute have the same prologue as regular C functions -// compiled with GCC or Clang and therefore are better handled by GDB. As a -// consequence, and as opposed to regular Rust functions, we can set the -// breakpoints via the function name (and don't have to fall back on using line -// numbers). For LLDB this shouldn't make a difference because it can handle -// both cases. - -// compile-flags:-g - -// === GDB TESTS =================================================================================== - -// gdb-command:rbreak immediate_args -// gdb-command:rbreak binding -// gdb-command:rbreak assignment -// gdb-command:rbreak function_call -// gdb-command:rbreak identifier -// gdb-command:rbreak return_expr -// gdb-command:rbreak arithmetic_expr -// gdb-command:rbreak if_expr -// gdb-command:rbreak while_expr -// gdb-command:rbreak loop_expr -// gdb-command:run - -// IMMEDIATE ARGS -// gdb-command:print a -// gdb-check:$1 = 1 -// gdb-command:print b -// gdb-check:$2 = true -// gdb-command:print c -// gdb-check:$3 = 2.5 -// gdb-command:continue - -// NON IMMEDIATE ARGS -// gdb-command:print a -// gdb-check:$4 = {a = 3, b = 4, c = 5, d = 6, e = 7, f = 8, g = 9, h = 10} -// gdb-command:print b -// gdb-check:$5 = {a = 11, b = 12, c = 13, d = 14, e = 15, f = 16, g = 17, h = 18} -// gdb-command:continue - -// BINDING -// gdb-command:print a -// gdb-check:$6 = 19 -// gdb-command:print b -// gdb-check:$7 = 20 -// gdb-command:print c -// gdb-check:$8 = 21.5 -// gdb-command:continue - -// ASSIGNMENT -// gdb-command:print a -// gdb-check:$9 = 22 -// gdb-command:print b -// gdb-check:$10 = 23 -// gdb-command:print c -// gdb-check:$11 = 24.5 -// gdb-command:continue - -// FUNCTION CALL -// gdb-command:print x -// gdb-check:$12 = 25 -// gdb-command:print y -// gdb-check:$13 = 26 -// gdb-command:print z -// gdb-check:$14 = 27.5 -// gdb-command:continue - -// EXPR -// gdb-command:print x -// gdb-check:$15 = 28 -// gdb-command:print y -// gdb-check:$16 = 29 -// gdb-command:print z -// gdb-check:$17 = 30.5 -// gdb-command:continue - -// RETURN EXPR -// gdb-command:print x -// gdb-check:$18 = 31 -// gdb-command:print y -// gdb-check:$19 = 32 -// gdb-command:print z -// gdb-check:$20 = 33.5 -// gdb-command:continue - -// ARITHMETIC EXPR -// gdb-command:print x -// gdb-check:$21 = 34 -// gdb-command:print y -// gdb-check:$22 = 35 -// gdb-command:print z -// gdb-check:$23 = 36.5 -// gdb-command:continue - -// IF EXPR -// gdb-command:print x -// gdb-check:$24 = 37 -// gdb-command:print y -// gdb-check:$25 = 38 -// gdb-command:print z -// gdb-check:$26 = 39.5 -// gdb-command:continue - -// WHILE EXPR -// gdb-command:print x -// gdb-check:$27 = 40 -// gdb-command:print y -// gdb-check:$28 = 41 -// gdb-command:print z -// gdb-check:$29 = 42 -// gdb-command:continue - -// LOOP EXPR -// gdb-command:print x -// gdb-check:$30 = 43 -// gdb-command:print y -// gdb-check:$31 = 44 -// gdb-command:print z -// gdb-check:$32 = 45 -// gdb-command:continue - - -// === LLDB TESTS ================================================================================== - -// lldb-command:breakpoint set --name immediate_args -// lldb-command:breakpoint set --name non_immediate_args -// lldb-command:breakpoint set --name binding -// lldb-command:breakpoint set --name assignment -// lldb-command:breakpoint set --name function_call -// lldb-command:breakpoint set --name identifier -// lldb-command:breakpoint set --name return_expr -// lldb-command:breakpoint set --name arithmetic_expr -// lldb-command:breakpoint set --name if_expr -// lldb-command:breakpoint set --name while_expr -// lldb-command:breakpoint set --name loop_expr -// lldb-command:run - -// IMMEDIATE ARGS -// lldb-command:print a -// lldb-check:[...]$0 = 1 -// lldb-command:print b -// lldb-check:[...]$1 = true -// lldb-command:print c -// lldb-check:[...]$2 = 2.5 -// lldb-command:continue - -// NON IMMEDIATE ARGS -// lldb-command:print a -// lldb-check:[...]$3 = BigStruct { a: 3, b: 4, c: 5, d: 6, e: 7, f: 8, g: 9, h: 10 } -// lldb-command:print b -// lldb-check:[...]$4 = BigStruct { a: 11, b: 12, c: 13, d: 14, e: 15, f: 16, g: 17, h: 18 } -// lldb-command:continue - -// BINDING -// lldb-command:print a -// lldb-check:[...]$5 = 19 -// lldb-command:print b -// lldb-check:[...]$6 = 20 -// lldb-command:print c -// lldb-check:[...]$7 = 21.5 -// lldb-command:continue - -// ASSIGNMENT -// lldb-command:print a -// lldb-check:[...]$8 = 22 -// lldb-command:print b -// lldb-check:[...]$9 = 23 -// lldb-command:print c -// lldb-check:[...]$10 = 24.5 -// lldb-command:continue - -// FUNCTION CALL -// lldb-command:print x -// lldb-check:[...]$11 = 25 -// lldb-command:print y -// lldb-check:[...]$12 = 26 -// lldb-command:print z -// lldb-check:[...]$13 = 27.5 -// lldb-command:continue - -// EXPR -// lldb-command:print x -// lldb-check:[...]$14 = 28 -// lldb-command:print y -// lldb-check:[...]$15 = 29 -// lldb-command:print z -// lldb-check:[...]$16 = 30.5 -// lldb-command:continue - -// RETURN EXPR -// lldb-command:print x -// lldb-check:[...]$17 = 31 -// lldb-command:print y -// lldb-check:[...]$18 = 32 -// lldb-command:print z -// lldb-check:[...]$19 = 33.5 -// lldb-command:continue - -// ARITHMETIC EXPR -// lldb-command:print x -// lldb-check:[...]$20 = 34 -// lldb-command:print y -// lldb-check:[...]$21 = 35 -// lldb-command:print z -// lldb-check:[...]$22 = 36.5 -// lldb-command:continue - -// IF EXPR -// lldb-command:print x -// lldb-check:[...]$23 = 37 -// lldb-command:print y -// lldb-check:[...]$24 = 38 -// lldb-command:print z -// lldb-check:[...]$25 = 39.5 -// lldb-command:continue - -// WHILE EXPR -// lldb-command:print x -// lldb-check:[...]$26 = 40 -// lldb-command:print y -// lldb-check:[...]$27 = 41 -// lldb-command:print z -// lldb-check:[...]$28 = 42 -// lldb-command:continue - -// LOOP EXPR -// lldb-command:print x -// lldb-check:[...]$29 = 43 -// lldb-command:print y -// lldb-check:[...]$30 = 44 -// lldb-command:print z -// lldb-check:[...]$31 = 45 -// lldb-command:continue - -#![allow(dead_code, unused_assignments, unused_variables)] -#![feature(omit_gdb_pretty_printer_section)] -#![omit_gdb_pretty_printer_section] - -#[no_stack_check] -fn immediate_args(a: isize, b: bool, c: f64) { - println!(""); -} - -struct BigStruct { - a: u64, - b: u64, - c: u64, - d: u64, - e: u64, - f: u64, - g: u64, - h: u64 -} - -#[no_stack_check] -fn non_immediate_args(a: BigStruct, b: BigStruct) { - println!(""); -} - -#[no_stack_check] -fn binding(a: i64, b: u64, c: f64) { - let x = 0; - println!(""); -} - -#[no_stack_check] -fn assignment(mut a: u64, b: u64, c: f64) { - a = b; - println!(""); -} - -#[no_stack_check] -fn function_call(x: u64, y: u64, z: f64) { - println!("Hi!") -} - -#[no_stack_check] -fn identifier(x: u64, y: u64, z: f64) -> u64 { - x -} - -#[no_stack_check] -fn return_expr(x: u64, y: u64, z: f64) -> u64 { - return x; -} - -#[no_stack_check] -fn arithmetic_expr(x: u64, y: u64, z: f64) -> u64 { - x + y -} - -#[no_stack_check] -fn if_expr(x: u64, y: u64, z: f64) -> u64 { - if x + y < 1000 { - x - } else { - y - } -} - -#[no_stack_check] -fn while_expr(mut x: u64, y: u64, z: u64) -> u64 { - while x + y < 1000 { - x += z - } - return x; -} - -#[no_stack_check] -fn loop_expr(mut x: u64, y: u64, z: u64) -> u64 { - loop { - x += z; - - if x + y > 1000 { - return x; - } - } -} - -fn main() { - immediate_args(1, true, 2.5); - - non_immediate_args( - BigStruct { - a: 3, - b: 4, - c: 5, - d: 6, - e: 7, - f: 8, - g: 9, - h: 10 - }, - BigStruct { - a: 11, - b: 12, - c: 13, - d: 14, - e: 15, - f: 16, - g: 17, - h: 18 - } - ); - - binding(19, 20, 21.5); - assignment(22, 23, 24.5); - function_call(25, 26, 27.5); - identifier(28, 29, 30.5); - return_expr(31, 32, 33.5); - arithmetic_expr(34, 35, 36.5); - if_expr(37, 38, 39.5); - while_expr(40, 41, 42); - loop_expr(43, 44, 45); -}