{"action":"created","comment":{"url":"https://api.github.com/repos/rust-lang/rfcs/pulls/comments/37568619","id":37568619,"diff_hunk":"@@ -0,0 +1,345 @@\n+- Feature Name: `catch_panic`\n+- Start Date: 2015-07-24\n+- RFC PR: (leave this empty)\n+- Rust Issue: (leave this empty)\n+\n+# Summary\n+\n+Move `std::thread::catch_panic` to `std::panic::catch` after removing the `Send`\n+and `'static` bounds from the closure parameter.\n+\n+# Motivation\n+\n+In today's stable Rust it's not possible to catch a panic on the thread that\n+caused it. There are a number of situations, however, where this is\n+either required for correctness or necessary for building a useful abstraction:\n+\n+* It is currently defined as undefined behavior to have a Rust program panic\n+  across an FFI boundary. For example if C calls into Rust and Rust panics, then\n+  this is undefined behavior. Being able to catch a panic will allow writing\n+  C APIs in Rust that do not risk aborting the process they are embedded into.\n+\n+* Abstractions like thread pools want to catch the panics of tasks being run\n+  instead of having the thread torn down (and having to spawn a new thread).\n+\n+Stabilizing the `catch_panic` function would enable these two use cases, but\n+let's also take a look at the current signature of the function:\n+\n+```rust\n+fn catch_panic<F, R>(f: F) -> thread::Result<R>\n+    where F: FnOnce() -> R + Send + 'static\n+```\n+\n+This function will run the closure `f` and if it panics return `Err(Box<Any>)`.\n+If the closure doesn't panic it will return `Ok(val)` where `val` is the\n+returned value of the closure. The closure, however, is restricted to only close\n+over `Send` and `'static` data. These bounds can be overly restrictive, and due\n+to thread-local storage [they can be subverted][tls-subvert], making it unclear\n+what purpose they serve. This RFC proposes to remove the bounds as well.\n+\n+[tls-subvert]: https://github.com/rust-lang/rust/issues/25662\n+\n+Historically Rust has purposefully avoided the foray into the situation of\n+catching panics, largely because of a problem typically referred to as\n+\"exception safety\". To further understand the motivation of stabilization and\n+relaxing the bounds, let's review what exception safety is and what it means for\n+Rust.\n+\n+# Background: What is exception safety?\n+\n+Languages with exceptions have the property that a function can \"return\" early\n+if an exception is thrown. While exceptions aren't too hard to reason about when\n+thrown explicitly, they can be problematic when they are thrown by code being\n+called -- especially when that code isn't known in advance. Code is **exception\n+safe** if it works correctly even when the functions it calls into throw\n+exceptions.\n+\n+The idea of throwing an exception causing bugs may sound a bit alien, so it's\n+helpful to drill down into exactly why this is the case. Bugs related to\n+exception safety are comprised of two critical components:\n+\n+1. An invariant of a data structure is broken.\n+2. This broken invariant is the later observed.\n+\n+Exceptional control flow often exacerbates this first component of breaking\n+invariants. For example many data structures have a number of invariants that\n+are dynamically upheld for correctness, and the type's routines can temporarily\n+break these invariants to be fixed up before the function returns.  If, however,\n+an exception is thrown in this interim period the broken invariant could be\n+accidentally exposed.\n+\n+The second component, observing a broken invariant, can sometimes be difficult\n+in the face of exceptions, but languages often have constructs to enable these\n+sorts of witnesses. Two primary methods of doing so are something akin to\n+finally blocks (code run on a normal or exceptional return) or just catching the\n+exception. In both cases code which later runs that has access to the original\n+data structure will see the broken invariants.\n+\n+Now that we've got a better understanding of how an exception might cause a bug\n+(e.g. how code can be \"exception unsafe\"), let's take a look how we can make\n+code exception safe. To be exception safe, code needs to be prepared for an\n+exception to be thrown whenever an invariant it relies on is broken, for\n+example:\n+\n+* Code can be audited to ensure it only calls functions which are statically\n+  known to not throw an exception.\n+* Local \"cleanup\" handlers can be placed on the stack to restore invariants\n+  whenever a function returns, either normally or exceptionally. This can be\n+  done through finally blocks in some languages or via destructors in others.\n+* Exceptions can be caught locally to perform cleanup before possibly re-raising\n+  the exception.\n+\n+With all that in mind, we've now identified problems that can arise via\n+exceptions (an invariant is broken and then observed) as well as methods to\n+ensure that prevent this from happening. In languages like C++ this means that\n+we can be memory safe in the face of exceptions and in languages like Java we\n+can ensure that our logical invariants are upheld. Given this background let's\n+take a look at how any of this applies to Rust.\n+\n+# Background: What is exception safety in Rust?\n+\n+> Note: This section describes the current state of Rust today without this RFC\n+>       implemented\n+\n+Up to now we've been talking about exceptions and exception safety, but from a\n+Rust perspective we can just replace this with panics and panic safety. Panics\n+in Rust are currently implemented essentially as a C++ exception under the hood.\n+As a result, **exception safety is something that needs to be handled in Rust\n+code today**.\n+\n+One of the primary examples where panics need to be handled in Rust is unsafe\n+code. Let's take a look at an example where this matters:\n+\n+```rust\n+pub fn push_ten_more<T: Clone>(v: &mut Vec<T>, t: T) {\n+    unsafe {\n+        v.reserve(10);\n+        let len = v.len();\n+        v.set_len(len + 10);\n+        for i in 0..10 {\n+            ptr::write(v.as_mut_ptr().offset(len + i), t.clone());\n+        }\n+    }\n+}\n+```\n+\n+While this code may look correct, it's actually not memory safe.\n+`Vec` has an internal invariant that its first `len` elements are safe to drop\n+at any time. Our function above has temporarily broken this invariant with the\n+call to `set_len` (the next 10 elements are uninitialized). If the type `T`'s\n+`clone` method panics then this broken invariant will escape the function. The\n+broken `Vec` is then observed during its destructor, leading to the eventual\n+memory unsafety.\n+\n+It's important to keep in mind that panic safety in Rust is not solely limited\n+to memory safety. *Logical invariants* are often just as critical to keep correct\n+during execution and no `unsafe` code in Rust is needed to break a logical\n+invariant. In practice, however, these sorts of bugs are rarely observed due to\n+Rust's design:\n+\n+* Rust doesn't expose uninitialized memory\n+* Panics cannot be caught in a thread\n+* Across threads data is poisoned by default on panics\n+* Idiomatic Rust must opt in to extra sharing across boundaries (e.g. `RefCell`)\n+* Destructors are relatively rare and uninteresting in safe code\n+\n+These mitigations all address the *second* aspect of exception unsafety:\n+observation of broken invariants. With the tactics in place, it ends up being\n+the case that **safe Rust code can largely ignore exception safety\n+concerns**. That being said, it does not mean that safe Rust code can *always*\n+ignore exception safety issues. There are a number of methods to subvert the\n+mitigation strategies listed above:\n+\n+1. When poisoning data across threads, antidotes are available to access\n+   poisoned data. Namely the [`PoisonError` type][pet] allows safe access to the\n+   poisoned information.\n+2. Single-threaded types with interior mutability, such as `RefCell`, allow for\n+   sharing data across stack frames such that a broken invariant could\n+   eventually be observed.\n+3. Whenever a thread panics, the destructors for its stack variables will be run\n+   as the thread unwinds. Destructors may have access to data which was also\n+   accessible lower on the stack (such as through `RefCell` or `Rc`) which has a\n+   broken invariant, and the destructor may then witness this.\n+\n+[pet]: http://doc.rust-lang.org/std/sync/struct.PoisonError.html\n+\n+But all of these \"subversions\" fall outside the realm of normal, idiomatic, safe\n+Rust code, and so they all serve as a \"heads up\" that panic safety might be an\n+issue. Thus, in practice, Rust programmers worry about exception safety far less\n+than in languages with full-blown exceptions.\n+\n+Despite these methods to subvert the mitigations placed by default in Rust, a\n+key part of exception safety in Rust is that **safe code can never lead to\n+memory unsafety**, regardless of whether it panics or not. Memory unsafety\n+triggered as part of a panic can always be traced back to an `unsafe` block.\n+\n+With all that background out of the way now, let's take a look at the guts of\n+this RFC.\n+\n+# Detailed design\n+\n+At its heart, the change this RFC is proposing is to move\n+`std::thread::catch_panic` to a new `std::panic` module and rename the function\n+to `catch`. Additionally, the `Send` and `'static` bounds from the closure\n+parameter will be removed, modifying the signature to be:\n+\n+```rust\n+fn catch<F: FnOnce() -> R, R>(f: F) -> thread::Result<R>\n+```\n+\n+More generally, however, this RFC also claims that this stable function does\n+not radically alter Rust's exception safety story (explained above).\n+\n+## Will Rust have exceptions?\n+\n+In a technical sense this RFC is not \"adding exceptions to Rust\" as they already\n+exist in the form of panics. What this RFC is adding, however, is a construct\n+via which to catch these exceptions within a thread, bringing the standard\n+library closer to the exception support in other languages.\n+\n+Catching a panic (and especially not having `'static` on the bounds list) makes\n+it easier to observe broken invariants of data structures shared across the\n+`catch_panic` boundary, which can possibly increase the likelihood of exception\n+safety issues arising.\n+\n+The risk of this step is that catching panics becomes an idiomatic way to deal\n+with error-handling, thereby making exception safety much more of a headache\n+than it is today (as it's more likely that a broken invariant is later\n+witnessed). The `catch_panic` function is intended to only be used\n+where it's absolutely necessary, e.g. for FFI boundaries, but how can it be\n+ensured that `catch_panic` isn't overused?\n+\n+There are two key reasons `catch_panic` likely won't become idiomatic:\n+\n+1. There are already strong and established conventions around error handling,\n+   and in particular around the use of panic and `Result` with stabilized usage\n+   of them in the standard library. There is little chance these conventions\n+   would change overnight.\n+\n+2. There has long been a desire to treat every use of `panic!` as an abort\n+   which is motivated by portability, compile time, binary size, and a number of\n+   other factors. Assuming this step is taken, it would be extremely unwise for\n+   a library to signal expected errors via panics and rely on consumers using\n+   `catch_panic` to handle them.\n+\n+For reference, here's a summary of the conventions around `Result` and `panic`,\n+which still hold good after this RFC:\n+\n+### Result vs Panic\n+\n+There are two primary strategies for signaling that a function can fail in Rust\n+today:\n+\n+* `Results` represent errors/edge-cases that the author of the library knew\n+  about, and expects the consumer of the library to handle.\n+\n+* `panic`s represent errors that the author of the library did not expect to\n+  occur, such as a contract violation, and therefore does not expect the\n+  consumer to handle in any particular way.\n+\n+Another way to put this division is that:\n+\n+* `Result`s represent errors that carry additional contextual information. This\n+  information allows them to be handled by the caller of the function producing\n+  the error, modified with additional contextual information, and eventually\n+  converted into an error message fit for a top-level program.\n+\n+* `panic`s represent errors that carry no contextual information (except,\n+  perhaps, debug information). Because they represented an unexpected error,\n+  they cannot be easily handled by the caller of the function or presented to\n+  the top-level program (except to say \"something unexpected has gone wrong\").\n+\n+Some pros of `Result` are that it signals specific edge cases that you as a\n+consumer should think about handling and it allows the caller to decide\n+precisely how to handle the error. A con with `Result` is that defining errors\n+and writing down `Result` + `try!` is not always the most ergonomic.\n+\n+The pros and cons of `panic` are essentially the opposite of `Result`, being\n+easy to use (nothing to write down other than the panic) but difficult to\n+determine when a panic can happen or handle it in a custom fashion, even with\n+`catch_panic`.\n+\n+These divisions justify the use of `panic`s for things like out-of-bounds\n+indexing: such an error represents a programming mistake that (1) the author of\n+the library was not aware of, by definition, and (2) cannot be meaningfully\n+handled by the caller.\n+\n+In terms of heuristics for use, `panic`s should rarely if ever be used to report\n+routine errors for example through communication with the system or through IO.\n+If a Rust program shells out to `rustc`, and `rustc` is not found, it might be\n+tempting to use a panic because the error is unexpected and hard to recover\n+from. A user of the program, however, would benefit from intermediate code\n+adding contextual information about the in-progress operation, and the program\n+could report the error in terms a they can understand. While the error is\n+rare, **when it happens it is not a programmer error**. In short, panics are\n+roughly analogous to an opaque \"an unexpected error has occurred\" message.\n+\n+Stabilizing `catch_panic` does little to change the tradeoffs around `Result`\n+and `panic` that led to these conventions.\n+\n+## Why remove the bounds?\n+\n+There are a few reasons to remove the `'static` and `Send` bounds on the\n+`catch_panic` function:\n+\n+* One of the primary use cases of `catch_panic` is in an FFI context, where lots\n+  of `*mut` and `*const` pointers are flying around. These two types aren't\n+  `Send` by default, so having their values cross the `catch_panic` boundary\n+  would be highly un-ergonomic (albeit still possible). As a result, this RFC\n+  proposes removing the `Send` bound from the function.\n+\n+* A reason to remove the `'static` bound is that it doesn't provide rock-solid\n+  exception-safety mitigation. Using thread-local storage it's possible to\n+  share mutable data across a call to `catch_panic` even if that data isn't\n+  `'static`.\n+\n+* Borrowed data, in particular, is helpful for thread pools that need\n+  to execute closures with borrowed data within them; essentially, the worker\n+  threads are executing multiple \"semantic threads\" over their lifetime, and the\n+  `catch_panic` boundary represents the end of these \"semantic threads\".\n+\n+# Drawbacks\n+\n+A drawback of this RFC is that it can water down Rust's error handling story.\n+With the addition of a \"catch\" construct for exceptions, it may be unclear to\n+library authors whether to use panics or `Result` for their error types. As we\n+discussed above, however, Rust's design around error handling has always had to\n+deal with these two strategies, and our conventions don't materially change by\n+stabilizing `catch_panic`.\n+\n+# Alternatives\n+\n+One alternative, which is somewhat more of an addition, is to have the standard\n+library entirely abandon all exception safety mitigation tactics. As explained\n+in the motivation section, exception safety will not lead to memory unsafety\n+unless paired with unsafe code, so it is perhaps within the realm of possibility\n+to remove the tactics of poisoning from mutexes and simply require that\n+consumers deal with exception safety 100% of the time.\n+\n+This alternative is often motivated by saying that there are enough methods to\n+subvert the default mitigation tactics that it's not worth trying to plug some\n+holes and not others. Upon closer inspection, however, the areas where safe code\n+needs to worry about exception safety are isolated to the single-threaded\n+situations. For example `RefCell`, destructors, and `catch_panic` all only\n+expose data possibly broken through a panic in a single thread.\n+\n+Once a thread boundary is crossed, the only current way to share data mutably is\n+via `Mutex` or `RwLock`, both of which are poisoned by default. This sort of\n+sharing is fundamental to threaded code, and poisoning by default allows safe\n+code to freely use many threads without having to consider exception safety\n+across threads (as poisoned data will tear down all connected threads).\n+\n+This property of multithreaded programming in Rust is seen as strong enough that\n+poisoning should not be removed by default, and in fact a new hypothetical\n+`thread::scoped` API (a rough counterpart of `catch_panic`) could also propagate\n+panics by default (like poisoning) with an ability to opt out (like\n+`PoisonError`).\n+\n+# Unresolved questions\n+\n+- Is it worth keeping the `'static` and `Send` bounds as a mitigation measure in\n+  practice, even if they aren't enforceable in theory? That would require thread\n+  pools to use unsafe code, but that could be acceptable.\n+\n+- Should `catch_panic` be stabilized within `std::thread` where it lives today,\n+  or somewhere else?","path":"text/0000-stabilize-catch-panic.md","position":345,"original_position":345,"commit_id":"e78f3e9cebc1497ea80b09dc20cb10d34248bdc3","original_commit_id":"e78f3e9cebc1497ea80b09dc20cb10d34248bdc3","user":{"login":"glaebhoerl","id":1216629,"avatar_url":"https://avatars.githubusercontent.com/u/1216629?v=3","gravatar_id":"","url":"https://api.github.com/users/glaebhoerl","html_url":"https://github.com/glaebhoerl","followers_url":"https://api.github.com/users/glaebhoerl/followers","following_url":"https://api.github.com/users/glaebhoerl/following{/other_user}","gists_url":"https://api.github.com/users/glaebhoerl/gists{/gist_id}","starred_url":"https://api.github.com/users/glaebhoerl/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/glaebhoerl/subscriptions","organizations_url":"https://api.github.com/users/glaebhoerl/orgs","repos_url":"https://api.github.com/users/glaebhoerl/repos","events_url":"https://api.github.com/users/glaebhoerl/events{/privacy}","received_events_url":"https://api.github.com/users/glaebhoerl/received_events","type":"User","site_admin":false},"body":"This is no longer unresolved? :)","created_at":"2015-08-20T19:05:40Z","updated_at":"2015-08-20T19:05:40Z","html_url":"https://github.com/rust-lang/rfcs/pull/1236#discussion_r37568619","pull_request_url":"https://api.github.com/repos/rust-lang/rfcs/pulls/1236","_links":{"self":{"href":"https://api.github.com/repos/rust-lang/rfcs/pulls/comments/37568619"},"html":{"href":"https://github.com/rust-lang/rfcs/pull/1236#discussion_r37568619"},"pull_request":{"href":"https://api.github.com/repos/rust-lang/rfcs/pulls/1236"}}},"pull_request":{"url":"https://api.github.com/repos/rust-lang/rfcs/pulls/1236","id":41593848,"html_url":"https://github.com/rust-lang/rfcs/pull/1236","diff_url":"https://github.com/rust-lang/rfcs/pull/1236.diff","patch_url":"https://github.com/rust-lang/rfcs/pull/1236.patch","issue_url":"https://api.github.com/repos/rust-lang/rfcs/issues/1236","number":1236,"state":"open","locked":false,"title":"RFC: Stabilize catch_panic","user":{"login":"alexcrichton","id":64996,"avatar_url":"https://avatars.githubusercontent.com/u/64996?v=3","gravatar_id":"","url":"https://api.github.com/users/alexcrichton","html_url":"https://github.com/alexcrichton","followers_url":"https://api.github.com/users/alexcrichton/followers","following_url":"https://api.github.com/users/alexcrichton/following{/other_user}","gists_url":"https://api.github.com/users/alexcrichton/gists{/gist_id}","starred_url":"https://api.github.com/users/alexcrichton/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/alexcrichton/subscriptions","organizations_url":"https://api.github.com/users/alexcrichton/orgs","repos_url":"https://api.github.com/users/alexcrichton/repos","events_url":"https://api.github.com/users/alexcrichton/events{/privacy}","received_events_url":"https://api.github.com/users/alexcrichton/received_events","type":"User","site_admin":false},"body":"Stabilize `std::thread::catch_panic` after removing the `Send` and `'static` bounds from the closure parameter. \r\n\r\n[Rendered](https://github.com/alexcrichton/rfcs/blob/stabilize-catch-panic/text/0000-stabilize-catch-panic.md)","created_at":"2015-08-04T17:13:21Z","updated_at":"2015-08-20T19:05:40Z","closed_at":null,"merged_at":null,"merge_commit_sha":"bead07948e4e4ed397a45a82e1d041acfdca08a3","assignee":{"login":"alexcrichton","id":64996,"avatar_url":"https://avatars.githubusercontent.com/u/64996?v=3","gravatar_id":"","url":"https://api.github.com/users/alexcrichton","html_url":"https://github.com/alexcrichton","followers_url":"https://api.github.com/users/alexcrichton/followers","following_url":"https://api.github.com/users/alexcrichton/following{/other_user}","gists_url":"https://api.github.com/users/alexcrichton/gists{/gist_id}","starred_url":"https://api.github.com/users/alexcrichton/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/alexcrichton/subscriptions","organizations_url":"https://api.github.com/users/alexcrichton/orgs","repos_url":"https://api.github.com/users/alexcrichton/repos","events_url":"https://api.github.com/users/alexcrichton/events{/privacy}","received_events_url":"https://api.github.com/users/alexcrichton/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/rust-lang/rfcs/pulls/1236/commits","review_comments_url":"https://api.github.com/repos/rust-lang/rfcs/pulls/1236/comments","review_comment_url":"https://api.github.com/repos/rust-lang/rfcs/pulls/comments{/number}","comments_url":"https://api.github.com/repos/rust-lang/rfcs/issues/1236/comments","statuses_url":"https://api.github.com/repos/rust-lang/rfcs/statuses/e78f3e9cebc1497ea80b09dc20cb10d34248bdc3","head":{"label":"alexcrichton:stabilize-catch-panic","ref":"stabilize-catch-panic","sha":"e78f3e9cebc1497ea80b09dc20cb10d34248bdc3","user":{"login":"alexcrichton","id":64996,"avatar_url":"https://avatars.githubusercontent.com/u/64996?v=3","gravatar_id":"","url":"https://api.github.com/users/alexcrichton","html_url":"https://github.com/alexcrichton","followers_url":"https://api.github.com/users/alexcrichton/followers","following_url":"https://api.github.com/users/alexcrichton/following{/other_user}","gists_url":"https://api.github.com/users/alexcrichton/gists{/gist_id}","starred_url":"https://api.github.com/users/alexcrichton/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/alexcrichton/subscriptions","organizations_url":"https://api.github.com/users/alexcrichton/orgs","repos_url":"https://api.github.com/users/alexcrichton/repos","events_url":"https://api.github.com/users/alexcrichton/events{/privacy}","received_events_url":"https://api.github.com/users/alexcrichton/received_events","type":"User","site_admin":false},"repo":{"id":17584422,"name":"rfcs","full_name":"alexcrichton/rfcs","owner":{"login":"alexcrichton","id":64996,"avatar_url":"https://avatars.githubusercontent.com/u/64996?v=3","gravatar_id":"","url":"https://api.github.com/users/alexcrichton","html_url":"https://github.com/alexcrichton","followers_url":"https://api.github.com/users/alexcrichton/followers","following_url":"https://api.github.com/users/alexcrichton/following{/other_user}","gists_url":"https://api.github.com/users/alexcrichton/gists{/gist_id}","starred_url":"https://api.github.com/users/alexcrichton/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/alexcrichton/subscriptions","organizations_url":"https://api.github.com/users/alexcrichton/orgs","repos_url":"https://api.github.com/users/alexcrichton/repos","events_url":"https://api.github.com/users/alexcrichton/events{/privacy}","received_events_url":"https://api.github.com/users/alexcrichton/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/alexcrichton/rfcs","description":"RFCs for changes to Rust","fork":true,"url":"https://api.github.com/repos/alexcrichton/rfcs","forks_url":"https://api.github.com/repos/alexcrichton/rfcs/forks","keys_url":"https://api.github.com/repos/alexcrichton/rfcs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/alexcrichton/rfcs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/alexcrichton/rfcs/teams","hooks_url":"https://api.github.com/repos/alexcrichton/rfcs/hooks","issue_events_url":"https://api.github.com/repos/alexcrichton/rfcs/issues/events{/number}","events_url":"https://api.github.com/repos/alexcrichton/rfcs/events","assignees_url":"https://api.github.com/repos/alexcrichton/rfcs/assignees{/user}","branches_url":"https://api.github.com/repos/alexcrichton/rfcs/branches{/branch}","tags_url":"https://api.github.com/repos/alexcrichton/rfcs/tags","blobs_url":"https://api.github.com/repos/alexcrichton/rfcs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/alexcrichton/rfcs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/alexcrichton/rfcs/git/refs{/sha}","trees_url":"https://api.github.com/repos/alexcrichton/rfcs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/alexcrichton/rfcs/statuses/{sha}","languages_url":"https://api.github.com/repos/alexcrichton/rfcs/languages","stargazers_url":"https://api.github.com/repos/alexcrichton/rfcs/stargazers","contributors_url":"https://api.github.com/repos/alexcrichton/rfcs/contributors","subscribers_url":"https://api.github.com/repos/alexcrichton/rfcs/subscribers","subscription_url":"https://api.github.com/repos/alexcrichton/rfcs/subscription","commits_url":"https://api.github.com/repos/alexcrichton/rfcs/commits{/sha}","git_commits_url":"https://api.github.com/repos/alexcrichton/rfcs/git/commits{/sha}","comments_url":"https://api.github.com/repos/alexcrichton/rfcs/comments{/number}","issue_comment_url":"https://api.github.com/repos/alexcrichton/rfcs/issues/comments{/number}","contents_url":"https://api.github.com/repos/alexcrichton/rfcs/contents/{+path}","compare_url":"https://api.github.com/repos/alexcrichton/rfcs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/alexcrichton/rfcs/merges","archive_url":"https://api.github.com/repos/alexcrichton/rfcs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/alexcrichton/rfcs/downloads","issues_url":"https://api.github.com/repos/alexcrichton/rfcs/issues{/number}","pulls_url":"https://api.github.com/repos/alexcrichton/rfcs/pulls{/number}","milestones_url":"https://api.github.com/repos/alexcrichton/rfcs/milestones{/number}","notifications_url":"https://api.github.com/repos/alexcrichton/rfcs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/alexcrichton/rfcs/labels{/name}","releases_url":"https://api.github.com/repos/alexcrichton/rfcs/releases{/id}","created_at":"2014-03-10T06:59:41Z","updated_at":"2014-06-25T00:56:45Z","pushed_at":"2015-08-20T00:08:09Z","git_url":"git://github.com/alexcrichton/rfcs.git","ssh_url":"git@github.com:alexcrichton/rfcs.git","clone_url":"https://github.com/alexcrichton/rfcs.git","svn_url":"https://github.com/alexcrichton/rfcs","homepage":"","size":2751,"stargazers_count":0,"watchers_count":0,"language":null,"has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":1,"forks":1,"open_issues":1,"watchers":0,"default_branch":"master"}},"base":{"label":"rust-lang:master","ref":"master","sha":"6e537fe1f42a9f094ce07829b9c5b72b86c52f00","user":{"login":"rust-lang","id":5430905,"avatar_url":"https://avatars.githubusercontent.com/u/5430905?v=3","gravatar_id":"","url":"https://api.github.com/users/rust-lang","html_url":"https://github.com/rust-lang","followers_url":"https://api.github.com/users/rust-lang/followers","following_url":"https://api.github.com/users/rust-lang/following{/other_user}","gists_url":"https://api.github.com/users/rust-lang/gists{/gist_id}","starred_url":"https://api.github.com/users/rust-lang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rust-lang/subscriptions","organizations_url":"https://api.github.com/users/rust-lang/orgs","repos_url":"https://api.github.com/users/rust-lang/repos","events_url":"https://api.github.com/users/rust-lang/events{/privacy}","received_events_url":"https://api.github.com/users/rust-lang/received_events","type":"Organization","site_admin":false},"repo":{"id":17527989,"name":"rfcs","full_name":"rust-lang/rfcs","owner":{"login":"rust-lang","id":5430905,"avatar_url":"https://avatars.githubusercontent.com/u/5430905?v=3","gravatar_id":"","url":"https://api.github.com/users/rust-lang","html_url":"https://github.com/rust-lang","followers_url":"https://api.github.com/users/rust-lang/followers","following_url":"https://api.github.com/users/rust-lang/following{/other_user}","gists_url":"https://api.github.com/users/rust-lang/gists{/gist_id}","starred_url":"https://api.github.com/users/rust-lang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rust-lang/subscriptions","organizations_url":"https://api.github.com/users/rust-lang/orgs","repos_url":"https://api.github.com/users/rust-lang/repos","events_url":"https://api.github.com/users/rust-lang/events{/privacy}","received_events_url":"https://api.github.com/users/rust-lang/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/rust-lang/rfcs","description":"RFCs for changes to Rust","fork":false,"url":"https://api.github.com/repos/rust-lang/rfcs","forks_url":"https://api.github.com/repos/rust-lang/rfcs/forks","keys_url":"https://api.github.com/repos/rust-lang/rfcs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/rust-lang/rfcs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/rust-lang/rfcs/teams","hooks_url":"https://api.github.com/repos/rust-lang/rfcs/hooks","issue_events_url":"https://api.github.com/repos/rust-lang/rfcs/issues/events{/number}","events_url":"https://api.github.com/repos/rust-lang/rfcs/events","assignees_url":"https://api.github.com/repos/rust-lang/rfcs/assignees{/user}","branches_url":"https://api.github.com/repos/rust-lang/rfcs/branches{/branch}","tags_url":"https://api.github.com/repos/rust-lang/rfcs/tags","blobs_url":"https://api.github.com/repos/rust-lang/rfcs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/rust-lang/rfcs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/rust-lang/rfcs/git/refs{/sha}","trees_url":"https://api.github.com/repos/rust-lang/rfcs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/rust-lang/rfcs/statuses/{sha}","languages_url":"https://api.github.com/repos/rust-lang/rfcs/languages","stargazers_url":"https://api.github.com/repos/rust-lang/rfcs/stargazers","contributors_url":"https://api.github.com/repos/rust-lang/rfcs/contributors","subscribers_url":"https://api.github.com/repos/rust-lang/rfcs/subscribers","subscription_url":"https://api.github.com/repos/rust-lang/rfcs/subscription","commits_url":"https://api.github.com/repos/rust-lang/rfcs/commits{/sha}","git_commits_url":"https://api.github.com/repos/rust-lang/rfcs/git/commits{/sha}","comments_url":"https://api.github.com/repos/rust-lang/rfcs/comments{/number}","issue_comment_url":"https://api.github.com/repos/rust-lang/rfcs/issues/comments{/number}","contents_url":"https://api.github.com/repos/rust-lang/rfcs/contents/{+path}","compare_url":"https://api.github.com/repos/rust-lang/rfcs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/rust-lang/rfcs/merges","archive_url":"https://api.github.com/repos/rust-lang/rfcs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/rust-lang/rfcs/downloads","issues_url":"https://api.github.com/repos/rust-lang/rfcs/issues{/number}","pulls_url":"https://api.github.com/repos/rust-lang/rfcs/pulls{/number}","milestones_url":"https://api.github.com/repos/rust-lang/rfcs/milestones{/number}","notifications_url":"https://api.github.com/repos/rust-lang/rfcs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/rust-lang/rfcs/labels{/name}","releases_url":"https://api.github.com/repos/rust-lang/rfcs/releases{/id}","created_at":"2014-03-07T21:29:00Z","updated_at":"2015-08-20T13:43:00Z","pushed_at":"2015-08-20T18:35:08Z","git_url":"git://github.com/rust-lang/rfcs.git","ssh_url":"git@github.com:rust-lang/rfcs.git","clone_url":"https://github.com/rust-lang/rfcs.git","svn_url":"https://github.com/rust-lang/rfcs","homepage":"","size":11795,"stargazers_count":437,"watchers_count":437,"language":null,"has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":226,"mirror_url":null,"open_issues_count":550,"forks":226,"open_issues":550,"watchers":437,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/rust-lang/rfcs/pulls/1236"},"html":{"href":"https://github.com/rust-lang/rfcs/pull/1236"},"issue":{"href":"https://api.github.com/repos/rust-lang/rfcs/issues/1236"},"comments":{"href":"https://api.github.com/repos/rust-lang/rfcs/issues/1236/comments"},"review_comments":{"href":"https://api.github.com/repos/rust-lang/rfcs/pulls/1236/comments"},"review_comment":{"href":"https://api.github.com/repos/rust-lang/rfcs/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/rust-lang/rfcs/pulls/1236/commits"},"statuses":{"href":"https://api.github.com/repos/rust-lang/rfcs/statuses/e78f3e9cebc1497ea80b09dc20cb10d34248bdc3"}}}}