Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom panic handlers in the standard library #30449

Closed
alexcrichton opened this issue Dec 17, 2015 · 31 comments
Closed

Custom panic handlers in the standard library #30449

alexcrichton opened this issue Dec 17, 2015 · 31 comments
Labels
B-unstable Blocker: Implemented in the nightly compiler and unstable. final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.

Comments

@alexcrichton
Copy link
Member

Tracking issue for rust-lang/rfcs#1328

@sfackler
Copy link
Member

sfackler commented Jan 5, 2016

See rust-lang/log#67 for one usage example.

@yberreby
Copy link

Is there a good reason for the global panic handler to run even if the panic is recovered from?

#![feature(std_panic, recover)]
use std::panic;

fn main() {
    panic::recover(|| {
        panic!("hello");
    }).unwrap_err();
}

http://is.gd/HP4EyO

This prints thread '<main>' panicked at 'hello', <anon>:6. It seems unexpected to me, since the panic was caught, it shouldn't trigger the global handler, should it? IMO, only uncaught panics should trigger the handler and print a message. If a message needs to be printed, it can be, explicitly, at the recover call site.

@sfackler
Copy link
Member

There's some talk about this in the RFC PR, but the main reason is that it's very important for the handler to be able to take stack traces.

In addition, the intended use cases for recover are fairly limited, and almost all of them involve rethrowing the panic payload at a different location after catching it. The thread did panic, so it makes sense that the handler would be called IMO.

@alexcrichton alexcrichton added T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. B-unstable Blocker: Implemented in the nightly compiler and unstable. and removed B-RFC-approved Blocker: Approved by a merged RFC but not yet implemented. labels Jan 12, 2016
@shahn
Copy link
Contributor

shahn commented Jan 14, 2016

My biggest usecase for this is #1089, so I'd love a way to suppress the std panic handler, too. I would like to present my users with an error message, set an appropriate exit code, and be assured that desctructors ran without wrapping basically all my return values in Results when an error happens very rarely, is dependant on certain combinations of user input that can't be checked early/not very deep in the call chain.

@sfackler
Copy link
Member

@shahn panic::set_handler(|_| ()); should do that for you.

@fables-tales
Copy link
Contributor

I'm trying to do something of the form:

let orig_handler = panic::take_handler();
panic::set_handler(|_| ());
<an actual thing>
panic::set_handler(orig_handler);

and getting the error

src/example_group.rs:41:13: 41:31 error: the trait `for<'r, 'r> core::ops::Fn<(&'r std::panicking::PanicInfo<'r>,)>` is not implemented for the type `Box<for<'r, 'r> core::ops::Fn(&'r std::panicking::PanicInfo<'r>) + Send + Sync>` [E0277]
src/example_group.rs:41             panic::set_handler(orig_panic_handler);
                                    ^~~~~~~~~~~~~~~~~~
src/example_group.rs:41:13: 41:31 help: run `rustc --explain E0277` to see a detailed explanation
src/example_group.rs:41:13: 41:31 note: required by `std::panicking::set_handler`
src/example_group.rs:41:13: 41:31 error: the trait `for<'r, 'r> core::ops::FnOnce<(&'r std::panicking::PanicInfo<'r>,)>` is not implemented for the type `Box<for<'r, 'r> core::ops::Fn(&'r std::panicking::PanicInfo<'r>) + Send + Sync>` [E0277]
src/example_group.rs:41             panic::set_handler(orig_panic_handler);
                                    ^~~~~~~~~~~~~~~~~~
src/example_group.rs:41:13: 41:31 help: run `rustc --explain E0277` to see a detailed explanation
src/example_group.rs:41:13: 41:31 help: the following implementations were found:
src/example_group.rs:41:13: 41:31 help:   <Box<alloc::boxed::FnBox<A, Output=R> + 'a> as core::ops::FnOnce<A>>
src/example_group.rs:41:13: 41:31 help:   <Box<alloc::boxed::FnBox<A, Output=R> + Send + 'a> as core::ops::FnOnce<A>>
src/example_group.rs:41:13: 41:31 note: required by `std::panicking::set_handler`
error: aborting due to 2 previous errors
Could not compile `descriptor`.

I tried taking ownership of the value inside the box with

panic::set_handler(*orig_handler);

but this gives the error

src/example_group.rs:41:13: 41:31 error: the trait `core::marker::Sized` is not implemented for the type `for<'r, 'r> core::ops::Fn(&'r std::panicking::PanicInfo<'r>) + Send + Sync` [E0277]
src/example_group.rs:41             panic::set_handler(*orig_panic_handler);
                                    ^~~~~~~~~~~~~~~~~~
src/example_group.rs:41:13: 41:31 help: run `rustc --explain E0277` to see a detailed explanation
src/example_group.rs:41:13: 41:31 note: `for<'r, 'r> core::ops::Fn(&'r std::panicking::PanicInfo<'r>) + Send + Sync` does not have a constant size known at compile-time
src/example_group.rs:41:13: 41:31 note: required by `std::panicking::set_handler`
error: aborting due to previous error
Could not compile `descriptor`.

I feel like it should be easy to set_handler the result from take_handler and I might be missing a trick here. Does anyone have any advice for me? I really like this API and I'd appreciate any help ^_^

@yberreby
Copy link

@samphippen This is ugly, but it works.

#![feature(std_panic, panic_handler)]
use std::panic;

fn main() {
    let orig_handler = panic::take_handler();
    panic::set_handler(|_| ());
    // <an actual thing>
    panic::set_handler(move |info| (*orig_handler)(info));
}

http://is.gd/CzXxcb

@fables-tales
Copy link
Contributor

thanks!

@fables-tales
Copy link
Contributor

Further to this, I think there's a race or bug in the implementation. If this is the wrong place to report this issue please let me know, and I'll delete this comment and put it in the appropriate place. I'm aware this feature is unstable as well, but I figured I'd report some real world feedback anyway. My use case boils down to the following rust program:

#![feature(panic_handler, recover, std_panic)]
use std::thread;
use std::panic::{self, recover};

fn main() {
    let mut build = Vec::new();
    for _ in 0..10 {
        build.push(thread::spawn(|| {
            let orig_handler = panic::take_handler();

            panic::set_handler(|_| ());

            let _res = recover(|| {
                panic!("fail");
            });


            panic::set_handler(move |info| { (*orig_handler)(info) });
        }));
    }

    let results: Vec<_> = build.into_iter().map(|jh| jh.join()).collect();
    let all_passed = results.into_iter().all(|r| r.is_ok());
    println!("{}", all_passed);
}

When I run this, I get the following output:

     Running `target/debug/main`
thread '<unnamed>' panicked at 'fail', src/bin/main.rs:14
thread '<unnamed>' panicked at 'fail', src/bin/main.rs:14
true

(other runs produce more output, or garbled output, but always fewer than 10 total lines)

Given that I'm running 10 threads, I'd expect to either 10 lines of output, or 0, but not two. Is this an incorrect usage of the API, or is this actually a bug I'm seeing?

edit: versions

$ cargo --version
cargo 0.8.0-nightly (2c1426e 2016-01-15)
$ rustc --version
rustc 1.7.0-nightly (2fb0c5ebc 2016-01-14)
$

@SimonSapin
Copy link
Contributor

Having set_handler be a separate call from take_handler is inherently racy. This is a bug in the API design IMO.

@sfackler
Copy link
Member

@samphippen The panic handler is a global resource. If multiple threads are messing with it at once without synchronization, you'll see that kind of behavior.

You will want to take a different approach, possibly involving a handler that looks at a thread local which indicates if the panic should be suppressed.

@yberreby
Copy link

Now that recover was stabilized, do we still need global, or even thread-local panic handlers? recover with an error branch seems less error prone, immune (I think) to this kind of race condition, and cleaner overall.

@sfackler
Copy link
Member

@SimonSapin Those kinds of race conditions still exist if setting and taking were not separate actions. If multiple threads are adjusting a global resource at once without any synchronization at once, you'll see inconsistent behavior. For example, if the panic handlers were a stack, and each handler could choose whether or not to let the next handler run, the ordering of that stack would be inconsistent and so if any handler doesn't unconditionally allow the next handler to run, you'll see inconsistent behavior.

@yberreby recover hasn't yet been stabilized. Anyway, the use case for panic handlers is e.g. "I want to log panic messages with liblog instead of having them dumped to standard output". recover can't really serve that purpose because the handler will run anyway before the recover intercepts the unwind, recover doesn't have contextual information about the panic like the line number, and you don't necessarily have control over all threads in your program to insert the recovers.

@sfackler
Copy link
Member

The issue with resetting an old handler is a problem - it's not great to force it to get wrapped in another closure every time. It seems like adjusting set_handler to take an Into<Box<Fn(&PanicInfo)>> would be what you'd want, but it doesn't look like From<T> is implemented for Box<T>. @aturon is that impl prohibited by coherence or something, or could we add it?

EDIT: Ah, it's actually a bit weirder since it's more like impl<F: Fn(&PanicInfo)> From<F> for Box<Fn(&PanicInfo)>.

@yberreby
Copy link

@sfackler Oh? I thought it had been. My mistake.

recover can't really serve that purpose because the handler will run anyway before the recover intercepts the unwind, recover doesn't have contextual information about the panic like the line number, and you don't necessarily have control over all threads in your program to insert the recovers.

Couldn't all of this be solved rather easily, especially since recover is still unstable?

  • Add a PanicInfo parameter to recover's FnOnce.
  • Have just one panic handler for the main thread, which only runs in case of a bubbled up, unhandled, unrecovered panic.

You usually don't want to have dependencies mess with a global resource, but the current approach encourages this behavior. If you don't want caught panics to be silent, you can always re-throw them and have them bubble up to the main thread, can't you?

@sfackler
Copy link
Member

PanicInfo wouldn't be a parameter to the closure, but rather part of the Err return value.

"Just one panic handler" sounds like a global resource to me. How would you configure it? It's absolutely true you don't want dependencies messing with the global handler whenever they want, but you absolutely do want it to be possible for dependencies to adjust the panic handler when asked. For example, you may want your log dependency to install a handler that logs panics: https://doc.rust-lang.org/log/log/fn.log_panics.html

EDIT: Ah, and as I mentioned in a previous comment, it is crucial that you be able to capture backtraces at the point that you "deal" with a panic, whether that be in a panic handler or elsewhere.

@yberreby
Copy link

@sfackler You're right, it should be part of Err.

"Just one panic handler" is a global resource, like, say, environment variables. However, with this approach, it's less problematic because recover eliminates the need for it in the majority of cases.

Moreover, we already had a global panic handler. There needs to be one to provide logging in case of completely unhandled panic.

It's not strictly needed for it to be writable, but it's convenient for the use-case you described (panic logging), and not having to wrap main in a giant recover closure. If users want to do the latter and get the same behavior, they can.

@sfackler
Copy link
Member

From my perspective, there are a couple things here:

First, recover is a thing that most people should not use. It's intended to be used in a very few contexts, primarily preventing a program from unwinding through FFI layers. We explicitly do not want recover to be used in contexts where people would be catching panics as a matter of course. The RecoverSafe bound makes it unergonomic to work with, and that is to some extent intentional.

Here are a couple of examples that the panic handler API is intended to help deal with. Could you go into a bit more detail on how these kinds of things would work with your proposal? I'm not sure I totally understand it.

I'm writing an e.g. webserver, and use log::log_panics to send panic messages to my logger instead of standard error.

I notice some weird panics popping up, and switch to a panic handler that also captures backtraces of the panic source.

I can't track down what's going on just from a backtrace, so I switch to a panic handler that will trigger a process abort for the panic I'm debugging so I can look at the core dump in a debugger.

Note that the latter two of these cases require that the code that looks at the PanicInfo needs to be running before unwinding begins.

@SimonSapin
Copy link
Contributor

@sfackler Yes, synchronization is needed, and I argue that libstd should provide that synchronization by default. The API could take a closure that is given a the previous handler and return the new one, and is called with a lock held internally. Something like:

pub type Handler = Box<Fn(&PanicInfo) + 'static + Sync + Send>;
pub fn set_handler<F>(F) where F: FnOnce(Handler) -> Handler

Looking at the source now, access to the private static mut HANDLER is already protected by a RW lock.

Note that the first thing set_handler currently does with the given unboxed generic Fn(&PanicInfo) is box it, so it’s not a loss to take it boxed in the first place.

@sfackler
Copy link
Member

@SimonSapin the issue is that that kind of API doesn't provide the proper sort of synchronization. For example, the race that @samphippen ran into is still present.

Fundamentally, if you have multiple threads adjusting the panic handler concurrently, it seems to me like you need an external, implementation specific ordering to be imposed for the resulting handler to be consistent.

What use cases were you imagining for which an atomic set_handler/take_handler combo was necessary? I think I'd prefer to implement it via an RAII-style API rather than one with nested closures.

@aturon
Copy link
Member

aturon commented Jan 26, 2016

@sfackler

It seems like adjusting set_handler to take an Into<Box<Fn(&PanicInfo)>> would be what you'd want, but it doesn't look like From is implemented for Box. @aturon is that impl prohibited by coherence or something, or could we add it?

Nope, should be fine. I don't remember any deliberate decision not to include it.

@alexcrichton
Copy link
Member Author

🔔 This issue is now entering its cycle-long final comment period for stabilization 🔔

@alexcrichton alexcrichton added final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. and removed I-nominated labels Apr 29, 2016
@alexcrichton
Copy link
Member Author

The libs team discussed this issue during triage yesterday and the decision was to stabilize

@tomaka
Copy link
Contributor

tomaka commented May 20, 2016

When the crate is compiled with -C panic=abort, is the hook called after a panic and before the abort? Or is it not called at all? Maybe the docs should have a note about that.

@sfackler
Copy link
Member

I believe it will still be called, yeah - is that right @alexcrichton? I'll update the docs.

@alexcrichton
Copy link
Member Author

Yes hooks are called regardless of the panic runtime

alexcrichton added a commit to alexcrichton/rust that referenced this issue May 24, 2016
This commit applies the FCP decisions made by the libs team for the 1.10 cycle,
including both new stabilizations and deprecations. Specifically, the list of
APIs is:

Stabilized:

* `os::windows::fs::OpenOptionsExt::access_mode`
* `os::windows::fs::OpenOptionsExt::share_mode`
* `os::windows::fs::OpenOptionsExt::custom_flags`
* `os::windows::fs::OpenOptionsExt::attributes`
* `os::windows::fs::OpenOptionsExt::security_qos_flags`
* `os::unix::fs::OpenOptionsExt::custom_flags`
* `sync::Weak::new`
* `Default for sync::Weak`
* `panic::set_hook`
* `panic::take_hook`
* `panic::PanicInfo`
* `panic::PanicInfo::payload`
* `panic::PanicInfo::location`
* `panic::Location`
* `panic::Location::file`
* `panic::Location::line`
* `ffi::CStr::from_bytes_with_nul`
* `ffi::CStr::from_bytes_with_nul_unchecked`
* `ffi::FromBytesWithNulError`
* `fs::Metadata::modified`
* `fs::Metadata::accessed`
* `fs::Metadata::created`
* `sync::atomic::Atomic{Usize,Isize,Bool,Ptr}::compare_exchange`
* `sync::atomic::Atomic{Usize,Isize,Bool,Ptr}::compare_exchange_weak`
* `collections::{btree,hash}_map::{Occupied,Vacant,}Entry::key`
* `os::unix::net::{UnixStream, UnixListener, UnixDatagram, SocketAddr}`
* `SocketAddr::is_unnamed`
* `SocketAddr::as_pathname`
* `UnixStream::connect`
* `UnixStream::pair`
* `UnixStream::try_clone`
* `UnixStream::local_addr`
* `UnixStream::peer_addr`
* `UnixStream::set_read_timeout`
* `UnixStream::set_write_timeout`
* `UnixStream::read_timeout`
* `UnixStream::write_Timeout`
* `UnixStream::set_nonblocking`
* `UnixStream::take_error`
* `UnixStream::shutdown`
* Read/Write/RawFd impls for `UnixStream`
* `UnixListener::bind`
* `UnixListener::accept`
* `UnixListener::try_clone`
* `UnixListener::local_addr`
* `UnixListener::set_nonblocking`
* `UnixListener::take_error`
* `UnixListener::incoming`
* RawFd impls for `UnixListener`
* `UnixDatagram::bind`
* `UnixDatagram::unbound`
* `UnixDatagram::pair`
* `UnixDatagram::connect`
* `UnixDatagram::try_clone`
* `UnixDatagram::local_addr`
* `UnixDatagram::peer_addr`
* `UnixDatagram::recv_from`
* `UnixDatagram::recv`
* `UnixDatagram::send_to`
* `UnixDatagram::send`
* `UnixDatagram::set_read_timeout`
* `UnixDatagram::set_write_timeout`
* `UnixDatagram::read_timeout`
* `UnixDatagram::write_timeout`
* `UnixDatagram::set_nonblocking`
* `UnixDatagram::take_error`
* `UnixDatagram::shutdown`
* RawFd impls for `UnixDatagram`
* `{BTree,Hash}Map::values_mut`
* `<[_]>::binary_search_by_key`

Deprecated:

* `StaticCondvar` - this, and all other static synchronization primitives
                    below, are usable today through the lazy-static crate on
                    stable Rust today. Additionally, we'd like the non-static
                    versions to be directly usable in a static context one day,
                    so they're unlikely to be the final forms of the APIs in any
                    case.
* `CONDVAR_INIT`
* `StaticMutex`
* `MUTEX_INIT`
* `StaticRwLock`
* `RWLOCK_INIT`
* `iter::Peekable::is_empty`

Closes rust-lang#27717
Closes rust-lang#27720
cc rust-lang#27784 (but encode methods still exist)
Closes rust-lang#30014
Closes rust-lang#30425
Closes rust-lang#30449
Closes rust-lang#31190
Closes rust-lang#31399
Closes rust-lang#31767
Closes rust-lang#32111
Closes rust-lang#32281
Closes rust-lang#32312
Closes rust-lang#32551
Closes rust-lang#33018
bors added a commit that referenced this issue May 26, 2016
std: Stabilize APIs for the 1.10 release

This commit applies the FCP decisions made by the libs team for the 1.10 cycle,
including both new stabilizations and deprecations. Specifically, the list of
APIs is:

Stabilized:

* `os::windows::fs::OpenOptionsExt::access_mode`
* `os::windows::fs::OpenOptionsExt::share_mode`
* `os::windows::fs::OpenOptionsExt::custom_flags`
* `os::windows::fs::OpenOptionsExt::attributes`
* `os::windows::fs::OpenOptionsExt::security_qos_flags`
* `os::unix::fs::OpenOptionsExt::custom_flags`
* `sync::Weak::new`
* `Default for sync::Weak`
* `panic::set_hook`
* `panic::take_hook`
* `panic::PanicInfo`
* `panic::PanicInfo::payload`
* `panic::PanicInfo::location`
* `panic::Location`
* `panic::Location::file`
* `panic::Location::line`
* `ffi::CStr::from_bytes_with_nul`
* `ffi::CStr::from_bytes_with_nul_unchecked`
* `ffi::FromBytesWithNulError`
* `fs::Metadata::modified`
* `fs::Metadata::accessed`
* `fs::Metadata::created`
* `sync::atomic::Atomic{Usize,Isize,Bool,Ptr}::compare_exchange`
* `sync::atomic::Atomic{Usize,Isize,Bool,Ptr}::compare_exchange_weak`
* `collections::{btree,hash}_map::{Occupied,Vacant,}Entry::key`
* `os::unix::net::{UnixStream, UnixListener, UnixDatagram, SocketAddr}`
* `SocketAddr::is_unnamed`
* `SocketAddr::as_pathname`
* `UnixStream::connect`
* `UnixStream::pair`
* `UnixStream::try_clone`
* `UnixStream::local_addr`
* `UnixStream::peer_addr`
* `UnixStream::set_read_timeout`
* `UnixStream::set_write_timeout`
* `UnixStream::read_timeout`
* `UnixStream::write_Timeout`
* `UnixStream::set_nonblocking`
* `UnixStream::take_error`
* `UnixStream::shutdown`
* Read/Write/RawFd impls for `UnixStream`
* `UnixListener::bind`
* `UnixListener::accept`
* `UnixListener::try_clone`
* `UnixListener::local_addr`
* `UnixListener::set_nonblocking`
* `UnixListener::take_error`
* `UnixListener::incoming`
* RawFd impls for `UnixListener`
* `UnixDatagram::bind`
* `UnixDatagram::unbound`
* `UnixDatagram::pair`
* `UnixDatagram::connect`
* `UnixDatagram::try_clone`
* `UnixDatagram::local_addr`
* `UnixDatagram::peer_addr`
* `UnixDatagram::recv_from`
* `UnixDatagram::recv`
* `UnixDatagram::send_to`
* `UnixDatagram::send`
* `UnixDatagram::set_read_timeout`
* `UnixDatagram::set_write_timeout`
* `UnixDatagram::read_timeout`
* `UnixDatagram::write_timeout`
* `UnixDatagram::set_nonblocking`
* `UnixDatagram::take_error`
* `UnixDatagram::shutdown`
* RawFd impls for `UnixDatagram`
* `{BTree,Hash}Map::values_mut`
* `<[_]>::binary_search_by_key`

Deprecated:

* `StaticCondvar` - this, and all other static synchronization primitives
                    below, are usable today through the lazy-static crate on
                    stable Rust today. Additionally, we'd like the non-static
                    versions to be directly usable in a static context one day,
                    so they're unlikely to be the final forms of the APIs in any
                    case.
* `CONDVAR_INIT`
* `StaticMutex`
* `MUTEX_INIT`
* `StaticRwLock`
* `RWLOCK_INIT`
* `iter::Peekable::is_empty`

Closes #27717
Closes #27720
Closes #30014
Closes #30425
Closes #30449
Closes #31190
Closes #31399
Closes #31767
Closes #32111
Closes #32281
Closes #32312
Closes #32551
Closes #33018
alexcrichton added a commit to alexcrichton/rust that referenced this issue May 26, 2016
This commit applies the FCP decisions made by the libs team for the 1.10 cycle,
including both new stabilizations and deprecations. Specifically, the list of
APIs is:

Stabilized:

* `os::windows::fs::OpenOptionsExt::access_mode`
* `os::windows::fs::OpenOptionsExt::share_mode`
* `os::windows::fs::OpenOptionsExt::custom_flags`
* `os::windows::fs::OpenOptionsExt::attributes`
* `os::windows::fs::OpenOptionsExt::security_qos_flags`
* `os::unix::fs::OpenOptionsExt::custom_flags`
* `sync::Weak::new`
* `Default for sync::Weak`
* `panic::set_hook`
* `panic::take_hook`
* `panic::PanicInfo`
* `panic::PanicInfo::payload`
* `panic::PanicInfo::location`
* `panic::Location`
* `panic::Location::file`
* `panic::Location::line`
* `ffi::CStr::from_bytes_with_nul`
* `ffi::CStr::from_bytes_with_nul_unchecked`
* `ffi::FromBytesWithNulError`
* `fs::Metadata::modified`
* `fs::Metadata::accessed`
* `fs::Metadata::created`
* `sync::atomic::Atomic{Usize,Isize,Bool,Ptr}::compare_exchange`
* `sync::atomic::Atomic{Usize,Isize,Bool,Ptr}::compare_exchange_weak`
* `collections::{btree,hash}_map::{Occupied,Vacant,}Entry::key`
* `os::unix::net::{UnixStream, UnixListener, UnixDatagram, SocketAddr}`
* `SocketAddr::is_unnamed`
* `SocketAddr::as_pathname`
* `UnixStream::connect`
* `UnixStream::pair`
* `UnixStream::try_clone`
* `UnixStream::local_addr`
* `UnixStream::peer_addr`
* `UnixStream::set_read_timeout`
* `UnixStream::set_write_timeout`
* `UnixStream::read_timeout`
* `UnixStream::write_Timeout`
* `UnixStream::set_nonblocking`
* `UnixStream::take_error`
* `UnixStream::shutdown`
* Read/Write/RawFd impls for `UnixStream`
* `UnixListener::bind`
* `UnixListener::accept`
* `UnixListener::try_clone`
* `UnixListener::local_addr`
* `UnixListener::set_nonblocking`
* `UnixListener::take_error`
* `UnixListener::incoming`
* RawFd impls for `UnixListener`
* `UnixDatagram::bind`
* `UnixDatagram::unbound`
* `UnixDatagram::pair`
* `UnixDatagram::connect`
* `UnixDatagram::try_clone`
* `UnixDatagram::local_addr`
* `UnixDatagram::peer_addr`
* `UnixDatagram::recv_from`
* `UnixDatagram::recv`
* `UnixDatagram::send_to`
* `UnixDatagram::send`
* `UnixDatagram::set_read_timeout`
* `UnixDatagram::set_write_timeout`
* `UnixDatagram::read_timeout`
* `UnixDatagram::write_timeout`
* `UnixDatagram::set_nonblocking`
* `UnixDatagram::take_error`
* `UnixDatagram::shutdown`
* RawFd impls for `UnixDatagram`
* `{BTree,Hash}Map::values_mut`
* `<[_]>::binary_search_by_key`

Deprecated:

* `StaticCondvar` - this, and all other static synchronization primitives
                    below, are usable today through the lazy-static crate on
                    stable Rust today. Additionally, we'd like the non-static
                    versions to be directly usable in a static context one day,
                    so they're unlikely to be the final forms of the APIs in any
                    case.
* `CONDVAR_INIT`
* `StaticMutex`
* `MUTEX_INIT`
* `StaticRwLock`
* `RWLOCK_INIT`
* `iter::Peekable::is_empty`

Closes rust-lang#27717
Closes rust-lang#27720
cc rust-lang#27784 (but encode methods still exist)
Closes rust-lang#30014
Closes rust-lang#30425
Closes rust-lang#30449
Closes rust-lang#31190
Closes rust-lang#31399
Closes rust-lang#31767
Closes rust-lang#32111
Closes rust-lang#32281
Closes rust-lang#32312
Closes rust-lang#32551
Closes rust-lang#33018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
B-unstable Blocker: Implemented in the nightly compiler and unstable. final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

9 participants