From e6c058e18c7a63e831a98b41d0d9df0e0c4901b4 Mon Sep 17 00:00:00 2001 From: Aidan Hobson Sayers Date: Thu, 21 May 2015 16:45:38 +0100 Subject: [PATCH 01/17] Rename 'link-args' to 'advanced-linking', add intro --- src/doc/trpl/SUMMARY.md | 2 +- .../trpl/{link-args.md => advanced-linking.md} | 15 +++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) rename src/doc/trpl/{link-args.md => advanced-linking.md} (62%) diff --git a/src/doc/trpl/SUMMARY.md b/src/doc/trpl/SUMMARY.md index ca3381ffba4..f1e51591aea 100644 --- a/src/doc/trpl/SUMMARY.md +++ b/src/doc/trpl/SUMMARY.md @@ -63,7 +63,7 @@ * [No stdlib](no-stdlib.md) * [Intrinsics](intrinsics.md) * [Lang items](lang-items.md) - * [Link args](link-args.md) + * [Advanced linking](advanced-linking.md) * [Benchmark Tests](benchmark-tests.md) * [Box Syntax and Patterns](box-syntax-and-patterns.md) * [Slice Patterns](slice-patterns.md) diff --git a/src/doc/trpl/link-args.md b/src/doc/trpl/advanced-linking.md similarity index 62% rename from src/doc/trpl/link-args.md rename to src/doc/trpl/advanced-linking.md index cdaef6cd9b5..f54799d9e4a 100644 --- a/src/doc/trpl/link-args.md +++ b/src/doc/trpl/advanced-linking.md @@ -1,6 +1,13 @@ -% Link args +% Advanced Linking -There is one other way to tell rustc how to customize linking, and that is via +The common cases of linking with Rust have been covered earlier in this book, +but supporting the range of linking possibilities made available by other +languages is important for Rust to achieve seamless interaction with native +libraries. + +# Link args + +There is one other way to tell `rustc` how to customize linking, and that is via the `link_args` attribute. This attribute is applied to `extern` blocks and specifies raw flags which need to get passed to the linker when producing an artifact. An example usage would be: @@ -14,9 +21,9 @@ extern {} ``` Note that this feature is currently hidden behind the `feature(link_args)` gate -because this is not a sanctioned way of performing linking. Right now rustc +because this is not a sanctioned way of performing linking. Right now `rustc` shells out to the system linker, so it makes sense to provide extra command line -arguments, but this will not always be the case. In the future rustc may use +arguments, but this will not always be the case. In the future `rustc` may use LLVM directly to link native libraries, in which case `link_args` will have no meaning. From e5c1884c26cf41a338e903ec60f58bdad49af886 Mon Sep 17 00:00:00 2001 From: Aidan Hobson Sayers Date: Thu, 21 May 2015 16:47:41 +0100 Subject: [PATCH 02/17] Note possiblities of empty extern blocks (based on #12575) --- src/doc/reference.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/doc/reference.md b/src/doc/reference.md index a37e1c14668..26fd2fd8d20 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -1636,6 +1636,10 @@ The type of a function declared in an extern block is `extern "abi" fn(A1, ..., An) -> R`, where `A1...An` are the declared types of its arguments and `R` is the declared return type. +It is valid to add the `link` attribute on an empty extern block. You can use +this to satisfy the linking requirements of extern blocks elsewhere in your code +(including upstream crates) instead of adding the attribute to each extern block. + ## Visibility and Privacy These two terms are often used interchangeably, and what they are attempting to From 7af865b33348730aacc02afeb3233cf8d90bb1f2 Mon Sep 17 00:00:00 2001 From: Aidan Hobson Sayers Date: Thu, 21 May 2015 19:55:51 +0100 Subject: [PATCH 03/17] Static linking --- src/doc/trpl/advanced-linking.md | 127 +++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/src/doc/trpl/advanced-linking.md b/src/doc/trpl/advanced-linking.md index f54799d9e4a..ea5238c3814 100644 --- a/src/doc/trpl/advanced-linking.md +++ b/src/doc/trpl/advanced-linking.md @@ -30,3 +30,130 @@ meaning. It is highly recommended to *not* use this attribute, and rather use the more formal `#[link(...)]` attribute on `extern` blocks instead. +# Static linking + +Static linking refers to the process of creating output that contain all +required libraries and so don't need libraries installed on every system where +you want to use your compiled project. Pure-Rust dependencies are statically +linked by default so you can use created binaries and libraries without +installing the Rust everywhere. By contrast, native libraries +(e.g. `libc` and `libm`) usually dynamically linked, but it is possible to +change this and statically link them as well. + +Linking is a very platform dependent topic - on some platforms, static linking +may not be possible at all! This section assumes some basic familiarity with +linking on your platform on choice. + +## Linux + +By default, all Rust programs on Linux will link to the system `libc` along with +a number of other libraries. Let's look at an example on a 64-bit linux machine +with GCC and `glibc` (by far the most common `libc` on Linux): + +``` text +$ cat example.rs +fn main() {} +$ rustc example.rs +$ ldd example + linux-vdso.so.1 => (0x00007ffd565fd000) + libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fa81889c000) + libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fa81867e000) + librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fa818475000) + libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fa81825f000) + libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa817e9a000) + /lib64/ld-linux-x86-64.so.2 (0x00007fa818cf9000) + libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fa817b93000) +``` + +Dynamic linking on Linux can be undesirable if you wish to use new library +features on old systems or target systems which do not have the required +dependencies for your program to run. + +The first step in using static linking is examining the Rust linking arguments +with an option to rustc. Newlines have been added for readability: + +``` text +$ rustc example.rs -Z print-link-args +"cc" + "-Wl,--as-needed" + "-m64" + [...] + "-o" "example" + "example.o" + "-Wl,--whole-archive" "-lmorestack" "-Wl,--no-whole-archive" + "-Wl,--gc-sections" + "-pie" + "-nodefaultlibs" + [...] + "-Wl,--whole-archive" "-Wl,-Bstatic" + "-Wl,--no-whole-archive" "-Wl,-Bdynamic" + "-ldl" "-lpthread" "-lrt" "-lgcc_s" "-lpthread" "-lc" "-lm" "-lcompiler-rt" +``` + +Arguments with a `-L` before them set up the linker search path and arguments +ending with `.rlib` are linking Rust crates statically into your application. +Neither of these are relevent for static linking so have been ommitted. + +The first step in being able to statically link is to obtain an object file. +This can be achieved with `rustc --emit obj example.rs`, and creates a file +called `example.o`, which you can see being passed in the command line above - +rustc automatically deletes it when finished with it by default. As you now have +the object file, you should be able to run the link command obtained with +`print-link-args` to create perform the linking stage yourself. + +In order to statically link, there are a number of changes you must make. Below +is the command required to perform a static link; we will go through them each +in turn. + +``` text +$ rustc example.rs -Z print-link-args +"cc" + "-static" + "-m64" + [...] + "-o" "example" + "example.o" + "-Wl,--whole-archive" "-lmorestack" "-Wl,--no-whole-archive" + "-Wl,--gc-sections" + "-nodefaultlibs" + [...] + "-Wl,--whole-archive" + "-Wl,--no-whole-archive" + "-ldl" "-lpthread" "-lrt" "-lgcc_eh" "-lpthread" "-lc" "-lm" "-lcompiler-rt" +``` + + - `-static` was added - this is the signal to the compiler to use a static + glibc, among other things + - `-Wl,--as-needed` was removed - this can be left in, but is unnecessary + as it only applies to dynamic librares + - `-pie` was removed - this is not compatible with static binaries + - both `-Wl,-B*` options were removed - everything will be linked statically, + so informing the linker of how certain libraries should be linked is not + appropriate + - `-lgcc_s` was changed to `-lgcc_eh` - `gcc_s` is the GCC support library, + which Rust uses for unwinding support. This is only available as a dynamic + library, so we must specify the static version of the library providing + unwinding support. + +By running this command, you will likely see some warnings like + +``` text +warning: Using 'getpwuid_r' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking +``` + +These should be considered carefully! They indicate calls in glibc which +*cannot* be statically linked without significant extra effort. An application +using these calls will find it is not as portable as 'static binary' would imply. +Rust supports targeting musl as an alternative libc to be able to fully +statically link these calls. + +As we are confident that our code does not use these calls, we can now see the +fruits of our labour: + +``` +$ ldd example + not a dynamic executable +``` + +This binary can be copied to virtually any 64-bit Linux machine and work +without requiring external libraries. From dd3ac9058aa9684179415d0a6d36d23fba0d9bd1 Mon Sep 17 00:00:00 2001 From: Alisdair Owens Date: Wed, 22 Jul 2015 13:52:48 +0100 Subject: [PATCH 04/17] Add long diagnostics for E0223 and E0225 --- src/librustc_typeck/diagnostics.rs | 58 ++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index a002ed311e8..aa3219e589a 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -1886,6 +1886,62 @@ type Foo = Trait; // ok! ``` "##, +E0223: r##" +An attempt was made to retrieve an associated type, but the type was ambiguous. +For example: + +``` +trait MyTrait {type X; } + +fn main() { + let foo: MyTrait::X; +} +``` + +The problem here is that we're attempting to take the type of X from MyTrait. +Unfortunately, the type of X is not defined, because it's only made concrete in +implementations of the trait. A working version of this code might look like: + +``` +trait MyTrait {type X; } +struct MyStruct; + +impl MyTrait for MyStruct { + type X = u32; +} + +fn main() { + let foo: ::X; +} +``` + +This syntax specifies that we want the X type from MyTrait, as made concrete in +MyStruct. The reason that we cannot simply use `MyStruct::X` is that MyStruct +might implement two different traits with identically-named associated types. +This syntax allows disambiguation between the two. +"##, + +E0225: r##" +You attempted to use multiple types as bounds for a closure or trait object. +Rust does not currently support this. A simple example that causes this error: + +``` +fn main() { + let _: Box; +} +``` + +Builtin traits are an exception to this rule: it's possible to have bounds of +one non-builtin type, plus any number of builtin types. For example, the +following compiles correctly: + +``` +fn main() { + let _: Box; +} +``` +"##, + E0232: r##" The attribute must have a value. Erroneous code example: @@ -2225,9 +2281,7 @@ register_diagnostics! { E0221, // ambiguous associated type in bounds //E0222, // Error code E0045 (variadic function must have C calling // convention) duplicate - E0223, // ambiguous associated type E0224, // at least one non-builtin train is required for an object type - E0225, // only the builtin traits can be used as closure or object bounds E0226, // only a single explicit lifetime bound is permitted E0227, // ambiguous lifetime bound, explicit lifetime bound required E0228, // explicit lifetime bound required From a8a49fbfc9c8433a03c67007fb4ad30672cfb483 Mon Sep 17 00:00:00 2001 From: Aidan Hobson Sayers Date: Mon, 15 Jun 2015 18:54:37 +0100 Subject: [PATCH 05/17] musl static linking not glibc --- src/doc/trpl/advanced-linking.md | 150 +++++++++++++++---------------- 1 file changed, 70 insertions(+), 80 deletions(-) diff --git a/src/doc/trpl/advanced-linking.md b/src/doc/trpl/advanced-linking.md index ea5238c3814..614b7893e96 100644 --- a/src/doc/trpl/advanced-linking.md +++ b/src/doc/trpl/advanced-linking.md @@ -40,14 +40,14 @@ installing the Rust everywhere. By contrast, native libraries (e.g. `libc` and `libm`) usually dynamically linked, but it is possible to change this and statically link them as well. -Linking is a very platform dependent topic - on some platforms, static linking +Linking is a very platform dependent topic — on some platforms, static linking may not be possible at all! This section assumes some basic familiarity with -linking on your platform on choice. +linking on your platform of choice. ## Linux By default, all Rust programs on Linux will link to the system `libc` along with -a number of other libraries. Let's look at an example on a 64-bit linux machine +a number of other libraries. Let's look at an example on a 64-bit Linux machine with GCC and `glibc` (by far the most common `libc` on Linux): ``` text @@ -69,91 +69,81 @@ Dynamic linking on Linux can be undesirable if you wish to use new library features on old systems or target systems which do not have the required dependencies for your program to run. -The first step in using static linking is examining the Rust linking arguments -with an option to rustc. Newlines have been added for readability: +Static linking is supported via an alternative `libc`, `musl` - this must be +enabled at Rust compile-time with some prerequisites available. You can compile +your own version of Rust with `musl` enabled and install it into a custom +directory with the instructions below: -``` text -$ rustc example.rs -Z print-link-args -"cc" - "-Wl,--as-needed" - "-m64" - [...] - "-o" "example" - "example.o" - "-Wl,--whole-archive" "-lmorestack" "-Wl,--no-whole-archive" - "-Wl,--gc-sections" - "-pie" - "-nodefaultlibs" - [...] - "-Wl,--whole-archive" "-Wl,-Bstatic" - "-Wl,--no-whole-archive" "-Wl,-Bdynamic" - "-ldl" "-lpthread" "-lrt" "-lgcc_s" "-lpthread" "-lc" "-lm" "-lcompiler-rt" +```text +$ mkdir musldist +$ PREFIX=$(pwd)/musldist +$ +$ # Build musl +$ wget http://www.musl-libc.org/releases/musl-1.1.10.tar.gz +[...] +$ tar xf musl-1.1.10.tar.gz +$ cd musl-1.1.10/ +musl-1.1.10 $ ./configure --disable-shared --prefix=$PREFIX +[...] +musl-1.1.10 $ make +[...] +musl-1.1.10 $ make install +[...] +musl-1.1.10 $ cd .. +$ du -h musldist/lib/libc.a +2.2M musldist/lib/libc.a +$ +$ # Build libunwind.a +$ wget http://llvm.org/releases/3.6.1/llvm-3.6.1.src.tar.xz +$ tar xf llvm-3.6.1.src.tar.xz +$ cd llvm-3.6.1.src/projects/ +llvm-3.6.1.src/projects $ svn co http://llvm.org/svn/llvm-project/libcxxabi/trunk/ libcxxabi +llvm-3.6.1.src/projects $ svn co http://llvm.org/svn/llvm-project/libunwind/trunk/ libunwind +llvm-3.6.1.src/projects $ sed -i 's#^\(include_directories\).*$#\0\n\1(../libcxxabi/include)#' libunwind/CMakeLists.txt +llvm-3.6.1.src/projects $ mkdir libunwind/build +llvm-3.6.1.src/projects $ cd libunwind/build +llvm-3.6.1.src/projects/libunwind/build $ cmake -DLLVM_PATH=../../.. -DLIBUNWIND_ENABLE_SHARED=0 .. +llvm-3.6.1.src/projects/libunwind/build $ make +llvm-3.6.1.src/projects/libunwind/build $ cp lib/libunwind.a $PREFIX/lib/ +llvm-3.6.1.src/projects/libunwind/build $ cd cd ../../../../ +$ du -h musldist/lib/libunwind.a +164K musldist/lib/libunwind.a +$ +$ # Build musl-enabled rust +$ git clone https://github.com/rust-lang/rust.git muslrust +$ cd muslrust +muslrust $ ./configure --target=x86_64-unknown-linux-musl --musl-root=$PREFIX --prefix=$PREFIX +muslrust $ make +muslrust $ make install +muslrust $ cd .. +$ du -h musldist/bin/rustc +12K musldist/bin/rustc ``` -Arguments with a `-L` before them set up the linker search path and arguments -ending with `.rlib` are linking Rust crates statically into your application. -Neither of these are relevent for static linking so have been ommitted. +You now have a build of a `musl`-enabled Rust! Because we've installed it to a +custom prefix we need to make sure our system can the binaries and appropriate +libraries when we try and run it: -The first step in being able to statically link is to obtain an object file. -This can be achieved with `rustc --emit obj example.rs`, and creates a file -called `example.o`, which you can see being passed in the command line above - -rustc automatically deletes it when finished with it by default. As you now have -the object file, you should be able to run the link command obtained with -`print-link-args` to create perform the linking stage yourself. - -In order to statically link, there are a number of changes you must make. Below -is the command required to perform a static link; we will go through them each -in turn. - -``` text -$ rustc example.rs -Z print-link-args -"cc" - "-static" - "-m64" - [...] - "-o" "example" - "example.o" - "-Wl,--whole-archive" "-lmorestack" "-Wl,--no-whole-archive" - "-Wl,--gc-sections" - "-nodefaultlibs" - [...] - "-Wl,--whole-archive" - "-Wl,--no-whole-archive" - "-ldl" "-lpthread" "-lrt" "-lgcc_eh" "-lpthread" "-lc" "-lm" "-lcompiler-rt" +```text +$ export PATH=$PREFIX/bin:$PATH +$ export LD_LIBRARY_PATH=$PREFIX/lib:$LD_LIBRARY_PATH ``` - - `-static` was added - this is the signal to the compiler to use a static - glibc, among other things - - `-Wl,--as-needed` was removed - this can be left in, but is unnecessary - as it only applies to dynamic librares - - `-pie` was removed - this is not compatible with static binaries - - both `-Wl,-B*` options were removed - everything will be linked statically, - so informing the linker of how certain libraries should be linked is not - appropriate - - `-lgcc_s` was changed to `-lgcc_eh` - `gcc_s` is the GCC support library, - which Rust uses for unwinding support. This is only available as a dynamic - library, so we must specify the static version of the library providing - unwinding support. +Let's try it out! -By running this command, you will likely see some warnings like - -``` text -warning: Using 'getpwuid_r' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking -``` - -These should be considered carefully! They indicate calls in glibc which -*cannot* be statically linked without significant extra effort. An application -using these calls will find it is not as portable as 'static binary' would imply. -Rust supports targeting musl as an alternative libc to be able to fully -statically link these calls. - -As we are confident that our code does not use these calls, we can now see the -fruits of our labour: - -``` +```text +$ echo 'fn main() { println!("hi!"); panic!("failed"); }' > example.rs +$ rustc --target=x86_64-unknown-linux-musl example.rs $ ldd example not a dynamic executable +$ ./example +hi! +thread '
' panicked at 'failed', example.rs:1 ``` -This binary can be copied to virtually any 64-bit Linux machine and work -without requiring external libraries. +Success! This binary can be copied to almost any Linux machine with the same +machine architecture and run without issues. + +`cargo build` also permits the `--target` option so you should be able to build +your crates as normal. However, you may need to recompile your native libraries +against `musl` before they can be linked against. From b6a0d9e17843a2b078e491e10f64a4005b3a7791 Mon Sep 17 00:00:00 2001 From: Aidan Hobson Sayers Date: Mon, 15 Jun 2015 18:58:28 +0100 Subject: [PATCH 06/17] Additional notes to link-args --- src/doc/trpl/advanced-linking.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/doc/trpl/advanced-linking.md b/src/doc/trpl/advanced-linking.md index 614b7893e96..6d370433542 100644 --- a/src/doc/trpl/advanced-linking.md +++ b/src/doc/trpl/advanced-linking.md @@ -22,10 +22,12 @@ extern {} Note that this feature is currently hidden behind the `feature(link_args)` gate because this is not a sanctioned way of performing linking. Right now `rustc` -shells out to the system linker, so it makes sense to provide extra command line +shells out to the system linker (`gcc` on most systems, `link.exe` on MSVC), +so it makes sense to provide extra command line arguments, but this will not always be the case. In the future `rustc` may use LLVM directly to link native libraries, in which case `link_args` will have no -meaning. +meaning. You can achieve the same effect as the `link-args` attribute with the +`-C link-args` argument to `rustc`. It is highly recommended to *not* use this attribute, and rather use the more formal `#[link(...)]` attribute on `extern` blocks instead. From c80bff0186ab938167a649edb325c9499e594247 Mon Sep 17 00:00:00 2001 From: Jason Schein Date: Mon, 20 Jul 2015 23:18:59 -0700 Subject: [PATCH 07/17] Added how to use labels to break nested loops to trpl. --- src/doc/trpl/while-loops.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/doc/trpl/while-loops.md b/src/doc/trpl/while-loops.md index 0f5c3c64a4b..124ebc7d69d 100644 --- a/src/doc/trpl/while-loops.md +++ b/src/doc/trpl/while-loops.md @@ -88,6 +88,24 @@ for x in 0..10 { } ``` +You may also encounter situations where you have nested loops and need to +specify which one your `break` or `continue` statement is for. Like most +other languages, by default a `break` or `continue` will apply to innermost +loop. In a sitation where you would like to a `break` or `continue` for one +of the outer loops, you can use labels to specify which loop the `break` or + `continue` statement applies to. This will only print when both `x` and `y` are + odd: + +```rust +'outer: for x in 0..10 { + 'inner: for y in 0..10 { + if x % 2 == 0 { continue 'outer; } // continues the loop over x + if y % 2 == 0 { continue 'inner; } // continues the loop over y + println!("x: {}, y: {}", x, y); + } +} +``` + Both `continue` and `break` are valid in both `while` loops and [`for` loops][for]. [for]: for-loops.html From cf8a1636ef5a5227d091cbfce8365a2a603f4f79 Mon Sep 17 00:00:00 2001 From: Andrew Paseltiner Date: Wed, 22 Jul 2015 16:52:40 -0400 Subject: [PATCH 08/17] add diagnostics for E0437 and E0438 --- src/librustc_resolve/diagnostics.rs | 53 +++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 5a941c757fc..9f8a5c90d4e 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -426,6 +426,57 @@ use something_which_doesnt_exist; Please verify you didn't misspell the import's name. "##, +E0437: r##" +Trait impls can only implement associated types that are members of the trait in +question. This error indicates that you attempted to implement an associated +type whose name does not match the name of any associated type in the trait. + +Here is an example that demonstrates the error: + +``` +trait Foo {} + +impl Foo for i32 { + type Bar = bool; +} +``` + +The solution to this problem is to remove the extraneous associated type: + +``` +trait Foo {} + +impl Foo for i32 {} +``` +"##, + +E0438: r##" +Trait impls can only implement associated constants that are members of the +trait in question. This error indicates that you attempted to implement an +associated constant whose name does not match the name of any associated +constant in the trait. + +Here is an example that demonstrates the error: + +``` +#![feature(associated_consts)] + +trait Foo {} + +impl Foo for i32 { + const BAR: bool = true; +} +``` + +The solution to this problem is to remove the extraneous associated constant: + +``` +trait Foo {} + +impl Foo for i32 {} +``` +"## + } register_diagnostics! { @@ -468,6 +519,4 @@ register_diagnostics! { E0432, // unresolved import E0434, // can't capture dynamic environment in a fn item E0435, // attempt to use a non-constant value in a constant - E0437, // type is not a member of trait - E0438, // const is not a member of trait } From a700546feabd85fa06f2bbd446865c15431c0e09 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Thu, 23 Jul 2015 15:43:06 +0200 Subject: [PATCH 09/17] Fix `thread::catch_panic` documentation to mention its return value on success Fixes #27027. --- src/libstd/thread/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 3299c848ba7..20fcd309a6b 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -434,9 +434,9 @@ pub fn panicking() -> bool { /// Invokes a closure, capturing the cause of panic if one occurs. /// -/// This function will return `Ok(())` if the closure does not panic, and will -/// return `Err(cause)` if the closure panics. The `cause` returned is the -/// object with which panic was originally invoked. +/// This function will return `Ok` with the closure's result if the closure +/// does not panic, and will return `Err(cause)` if the closure panics. The +/// `cause` returned is the object with which panic was originally invoked. /// /// It is currently undefined behavior to unwind from Rust code into foreign /// code, so this function is particularly useful when Rust is called from From 38c5af86a1412a29a367c856d83cd08dd7e92a33 Mon Sep 17 00:00:00 2001 From: Alisdair Owens Date: Thu, 23 Jul 2015 10:44:04 +0100 Subject: [PATCH 10/17] Add long diagnostics for E0373 --- src/librustc_borrowck/diagnostics.rs | 51 +++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs index 3e7cfe3ee7f..4f90a287cb9 100644 --- a/src/librustc_borrowck/diagnostics.rs +++ b/src/librustc_borrowck/diagnostics.rs @@ -12,6 +12,56 @@ register_long_diagnostics! { +E0373: r##" +This error occurs when an attempt is made to use data captured by a closure, +when that data may no longer exist. It's most commonly seen when attempting to +return a closure: + +``` +fn foo() -> Box u32> { + let x = 0u32; + Box::new(|y| x + y) +} +``` + +Notice that `x` is stack-allocated by `foo()`. By default, Rust captures +closed-over data by reference. This means that once `foo()` returns, `x` no +longer exists. An attempt to access `x` within the closure would thus be unsafe. + +Another situation where this might be encountered is when spawning threads: + +``` +fn foo() { + let x = 0u32; + let y = 1u32; + + let thr = std::thread::spawn(|| { + x + y + }); +} +``` + +Since our new thread runs in parallel, the stack frame containing `x` and `y` +may well have disappeared by the time we try to use them. Even if we call +`thr.join()` within foo (which blocks until `thr` has completed, ensuring the +stack frame won't disappear), we will not succeed: the compiler cannot prove +that this behaviour is safe, and so won't let us do it. + +The solution to this problem is usually to switch to using a `move` closure. +This approach moves (or copies, where possible) data into the closure, rather +than taking references to it. For example: + +``` +fn foo() -> Box u32> { + let x = 0u32; + Box::new(move |y| x + y) +} +``` + +Now that the closure has its own copy of the data, there's no need to worry +about safety. +"##, + E0381: r##" It is not allowed to use or capture an uninitialized variable. For example: @@ -28,7 +78,6 @@ used. } register_diagnostics! { - E0373, // closure may outlive current fn, but it borrows {}, which is owned by current fn E0382, // use of partially/collaterally moved value E0383, // partial reinitialization of uninitialized structure E0384, // reassignment of immutable variable From e66817512a414d1665e37e6016a6fc06522fb2e0 Mon Sep 17 00:00:00 2001 From: Alisdair Owens Date: Wed, 22 Jul 2015 17:24:03 +0100 Subject: [PATCH 11/17] Add diagnostics for E0120 --- src/librustc_typeck/diagnostics.rs | 40 +++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index f865de522b2..ad45304341a 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -1316,6 +1316,45 @@ fn main() { ``` "##, +E0120: r##" +An attempt was made to implement Drop on a trait, which is not allowed: only +structs and enums can implement Drop. An example causing this error: + +``` +trait MyTrait {} + +impl Drop for MyTrait { + fn drop(&mut self) {} +} +``` + +A workaround for this problem is to wrap the trait up in a struct, and implement +Drop on that. An example is shown below: + +``` +trait MyTrait {} +struct MyWrapper { foo: T } + +impl Drop for MyWrapper { + fn drop(&mut self) {} +} + +``` + +Alternatively, wrapping trait objects requires something like the following: + +``` +trait MyTrait {} + +//or Box, if you wanted an owned trait object +struct MyWrapper<'a> { foo: &'a MyTrait } + +impl <'a> Drop for MyWrapper<'a> { + fn drop(&mut self) {} +} +``` +"##, + E0121: r##" In order to be consistent with Rust's lack of global type inference, type placeholders are disallowed by design in item signatures. @@ -2195,7 +2234,6 @@ register_diagnostics! { E0103, E0104, E0118, - E0120, E0122, E0123, E0127, From a319d32a57a7ad758e2719b096fdfa6fe53664b0 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Thu, 23 Jul 2015 12:57:22 -0400 Subject: [PATCH 12/17] Link Deref{,Mut} to TRPL on coercions. FIxes #26927 --- src/libcore/ops.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index c2a9b8c8308..0f9282a1455 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -1057,6 +1057,10 @@ impl fmt::Debug for RangeTo { /// The `Deref` trait is used to specify the functionality of dereferencing /// operations like `*v`. /// +/// `Deref` also enables ['`Deref` coercions'][coercions]. +/// +/// [coercions]: ../../book/deref-coercions.html +/// /// # Examples /// /// A struct with a single field which is accessible via dereferencing the @@ -1111,6 +1115,10 @@ impl<'a, T: ?Sized> Deref for &'a mut T { /// The `DerefMut` trait is used to specify the functionality of dereferencing /// mutably like `*v = 1;` /// +/// `DerefMut` also enables ['`Deref` coercions'][coercions]. +/// +/// [coercions]: ../../book/deref-coercions.html +/// /// # Examples /// /// A struct with a single field which is modifiable via dereferencing the From 01cb16d1bf510ccd33db79a7c91843a662952822 Mon Sep 17 00:00:00 2001 From: Dave Huseby Date: Sun, 19 Jul 2015 10:04:27 -0700 Subject: [PATCH 13/17] fixes #27124 for bitrig --- src/librustc_back/target/bitrig_base.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/librustc_back/target/bitrig_base.rs b/src/librustc_back/target/bitrig_base.rs index 9f6a1f1e530..258baba3573 100644 --- a/src/librustc_back/target/bitrig_base.rs +++ b/src/librustc_back/target/bitrig_base.rs @@ -20,9 +20,7 @@ pub fn opts() -> TargetOptions { linker_is_gnu: true, has_rpath: true, position_independent_executables: true, - pre_link_args: vec!( - ), - archive_format: "bsd".to_string(), + archive_format: "".to_string(), .. Default::default() } From 8ffbde44431887d0b5f877c9f1617c981b84e5ea Mon Sep 17 00:00:00 2001 From: Dave Huseby Date: Thu, 23 Jul 2015 06:05:59 -0700 Subject: [PATCH 14/17] review feedback fixes --- src/librustc_back/target/bitrig_base.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustc_back/target/bitrig_base.rs b/src/librustc_back/target/bitrig_base.rs index 258baba3573..e780539c1ac 100644 --- a/src/librustc_back/target/bitrig_base.rs +++ b/src/librustc_back/target/bitrig_base.rs @@ -20,7 +20,6 @@ pub fn opts() -> TargetOptions { linker_is_gnu: true, has_rpath: true, position_independent_executables: true, - archive_format: "".to_string(), .. Default::default() } From b208bd99209b0b26c2f4230e402ed523dcb9d928 Mon Sep 17 00:00:00 2001 From: Dave Huseby Date: Thu, 23 Jul 2015 10:13:49 -0700 Subject: [PATCH 15/17] switching to gnu archive format per review request --- src/librustc_back/target/bitrig_base.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc_back/target/bitrig_base.rs b/src/librustc_back/target/bitrig_base.rs index e780539c1ac..ddb32f4625b 100644 --- a/src/librustc_back/target/bitrig_base.rs +++ b/src/librustc_back/target/bitrig_base.rs @@ -20,6 +20,7 @@ pub fn opts() -> TargetOptions { linker_is_gnu: true, has_rpath: true, position_independent_executables: true, + archive_format: "gnu".to_string(), .. Default::default() } From 39c7a9350c50ac3dec3a8bdc6ae5e238a636bfd5 Mon Sep 17 00:00:00 2001 From: Dave Huseby Date: Thu, 23 Jul 2015 10:20:43 -0700 Subject: [PATCH 16/17] adds snapshots for bitrig and freebsd --- src/snapshots.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/snapshots.txt b/src/snapshots.txt index cb5790b34f4..5c3e55e2862 100644 --- a/src/snapshots.txt +++ b/src/snapshots.txt @@ -1,4 +1,7 @@ S 2015-07-17 d4432b3 + bitrig-x86_64 af77768e0eb0f4c7ec5a8e36047a08053b54b230 + freebsd-i386 b049325e5b2efe5f4884f3dafda448c1dac49b4f + freebsd-x86_64 a59e397188dbfe67456a6301df5ca13c7e238ab9 linux-i386 93f6216a35d3bed3cedf244c9aff4cd716336bd9 linux-x86_64 d8f4967fc71a153c925faecf95a7feadf7e463a4 macos-i386 29852c4d4b5a851f16d627856a279cae5bf9bd01 From e981311ec2e019c13088d7e510e0c050da3bcb5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20Ker=C3=A4nen?= Date: Thu, 23 Jul 2015 19:26:36 +0300 Subject: [PATCH 17/17] eval_const_expr_partial now returns ConstVal::Struct instead of None for unit-struct path expressions. Fixes #27008 --- src/librustc/middle/const_eval.rs | 3 +++ src/test/compile-fail/issue-27008.rs | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/test/compile-fail/issue-27008.rs diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index 9e2bcbaec8a..a349dab0f72 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -967,6 +967,9 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>, Some(def::DefVariant(enum_def, variant_def, _)) => { (lookup_variant_by_id(tcx, enum_def, variant_def), None) } + Some(def::DefStruct(_)) => { + return Ok(ConstVal::Struct(e.id)) + } _ => (None, None) }; let const_expr = match const_expr { diff --git a/src/test/compile-fail/issue-27008.rs b/src/test/compile-fail/issue-27008.rs new file mode 100644 index 00000000000..2a4b98563ab --- /dev/null +++ b/src/test/compile-fail/issue-27008.rs @@ -0,0 +1,21 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct S; + +fn main() { + let b = [0; S]; + //~^ ERROR mismatched types + //~| expected `usize` + //~| found `S` + //~| expected usize + //~| found struct `S` + //~| ERROR expected positive integer for repeat count, found struct +}