10499 Commits

Author SHA1 Message Date
Ibraheem Ahmed
32ab0b88f4 respect doc(hidden) when suggesting available fields 2022-01-22 15:48:45 -05:00
Cameron Steffen
b11733534d Remove a span from hir::ExprKind::MethodCall 2022-01-21 07:48:10 -06:00
bors
84e918971d Auto merge of #92896 - lqd:update-deps, r=Mark-Simulacrum
Update some rustc dependencies to deduplicate them

This PR updates `rand` and `itertools` in rustc (not the whole workspace) in order to deduplicate them (and hopefully slightly improve compile times).

~~Currently, `object` is still duplicated, but https://github.com/rust-lang/thorin/pull/15 and updating `thorin` in the future will remove the use of version 0.27.~~  Update: Thorin 0.2 has now been released, and this PR updates `rustc_codegen_ssa` to use it and deduplicate the `object` crate.

There's a final tiny rustc dependency, `cfg-if`, which will be left: as both versions 0.1.x and 1.0 looked to be heavily depended on, they will require a few cascading updates to be removed.
2022-01-21 10:38:30 +00:00
bors
0bcacb391b Auto merge of #91359 - dtolnay:args, r=Mark-Simulacrum
Emit simpler code from format_args

I made this PR so that `cargo expand` dumps a less overwhelming amount of formatting-related code.

<br>

`println!("rust")` **Before:**

```rust
{
    ::std::io::_print(::core::fmt::Arguments::new_v1(&["rust\n"],
                                                     &match () {
                                                          _args => [],
                                                      }));
};
```

**After:**

```rust
{ ::std::io::_print(::core::fmt::Arguments::new_v1(&["rust\n"], &[])); };
```

`println!("{}", x)` **Before:**

```rust
{
    ::std::io::_print(::core::fmt::Arguments::new_v1(
        &["", "\n"],
        &match (&x,) {
            _args => [::core::fmt::ArgumentV1::new(
                _args.0,
                ::core::fmt::Display::fmt,
            )],
        },
    ));
};
```

**After:**

```rust
{
    ::std::io::_print(::core::fmt::Arguments::new_v1(
        &["", "\n"],
        &[::core::fmt::ArgumentV1::new(&x, ::core::fmt::Display::fmt)],
    ));
};
```
2022-01-21 06:20:18 +00:00
bors
523be2e05d Auto merge of #93138 - matthiaskrgr:rollup-m8akifd, r=matthiaskrgr
Rollup of 17 pull requests

Successful merges:

 - #91032 (Introduce drop range tracking to generator interior analysis)
 - #92856 (Exclude "test" from doc_auto_cfg)
 - #92860 (Fix errors on blanket impls by ignoring the children of generated impls)
 - #93038 (Fix star handling in block doc comments)
 - #93061 (Only suggest adding `!` to expressions that can be macro invocation)
 - #93067 (rustdoc mobile: fix scroll offset when jumping to internal id)
 - #93086 (Add tests to ensure that `let_chains` works with `if_let_guard`)
 - #93087 (Fix src/test/run-make/raw-dylib-alt-calling-convention)
 - #93091 (⬆ chalk to 0.76.0)
 - #93094 (src/test/rustdoc-json: Check for `struct_field`s in `variant_tuple_struct.rs`)
 - #93098 (Show a more informative panic message when `DefPathHash` does not exist)
 - #93099 (rustdoc: auto create output directory when "--output-format json")
 - #93102 (Pretty printer algorithm revamp step 3)
 - #93104 (Support --bless for pp-exact pretty printer tests)
 - #93114 (update comment for `ensure_monomorphic_enough`)
 - #93128 (Add script to prevent point releases with same number as existing ones)
 - #93136 (Backport the 1.58.1 release notes to master)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
2022-01-21 03:04:43 +00:00
Matthias Krüger
b8df581ef8
Rollup merge of #93114 - lcnr:mk_array, r=RalfJung
update comment for `ensure_monomorphic_enough`

r? `@RalfJung`
2022-01-20 23:37:42 +01:00
Matthias Krüger
d4ec46444b
Rollup merge of #93102 - dtolnay:ringbuffer, r=lcnr
Pretty printer algorithm revamp step 3

This PR follows #93065 as a third chunk of minor modernizations backported from https://github.com/dtolnay/prettyplease into rustc_ast_pretty.

I've broken this up into atomic commits that hopefully are sensible in isolation. At every commit, the pretty printer is compilable and has runtime behavior that is identical to before and after the PR. None of the refactoring so far changes behavior.

This PR is the last chunk of non-behavior-changing cleanup. After this the **next PR** will begin backporting behavior changes from `prettyplease`, starting with block indentation:

```rust
macro_rules! print_expr {
    ($expr:expr) => {
        println!("{}", stringify!($expr));
    };
}

fn main() {
    print_expr!(Struct { x: 0, y: 0 });
    print_expr!(Structtttttttttttttttttttttttttttttttttttttttttttttttttt { xxxxxxxxx: 0, yyyyyyyyy: 0 });
}
```

Output currently on master (nowhere near modern Rust style):

```console
Struct{x: 0, y: 0,}
Structtttttttttttttttttttttttttttttttttttttttttttttttttt{xxxxxxxxx: 0,
                                                         yyyyyyyyy: 0,}
```

After the upcoming PR for block indentation (based on 401d60c042):

```console
Struct { x: 0, y: 0, }
Structtttttttttttttttttttttttttttttttttttttttttttttttttt {
    xxxxxxxxx: 0,
    yyyyyyyyy: 0,
}
```

And the PR after that, for intelligent trailing commas (based on e2a0297f17):

```console
Struct { x: 0, y: 0 }
Structtttttttttttttttttttttttttttttttttttttttttttttttttt {
    xxxxxxxxx: 0,
    yyyyyyyyy: 0,
}
```
2022-01-20 23:37:40 +01:00
Matthias Krüger
e901b24310
Rollup merge of #93098 - Aaron1011:def-path-hash-debug, r=oli-obk
Show a more informative panic message when `DefPathHash` does not exist

This should hopefully make it easier to debug incremental compilation
bugs like #93096 without affecting performance.
2022-01-20 23:37:38 +01:00
Matthias Krüger
b1a405df19
Rollup merge of #93091 - pierwill:chalk-0.76, r=jackh726
⬆ chalk to 0.76.0

This update contains https://github.com/rust-lang/chalk/pull/740, which is needed for work on #90317.
2022-01-20 23:37:37 +01:00
Matthias Krüger
dc393b2ecc
Rollup merge of #93061 - estebank:macr-suggestion, r=cjgillot
Only suggest adding `!` to expressions that can be macro invocation
2022-01-20 23:37:33 +01:00
Matthias Krüger
aa7f4520a1
Rollup merge of #93038 - GuillaumeGomez:block-doc-comments, r=notriddle
Fix star handling in block doc comments

Fixes #92872.

Some extra explanation about this PR and why https://github.com/rust-lang/rust/pull/92357 created this regression: when we merge doc comment kinds for example in:

```rust
/// he
/**
* hello
*/
#[doc = "boom"]
```

We don't want to remove the empty lines between them. However, to correctly compute the "horizontal trim", we still need it, so instead, I put back a part of the "vertical trim" directly in the "horizontal trim" computation so it doesn't impact the output buffer but allows us to correctly handle the stars.

r? ``@camelid``
2022-01-20 23:37:32 +01:00
Matthias Krüger
3d10c64b26
Rollup merge of #91032 - eholk:generator-drop-tracking, r=nikomatsakis
Introduce drop range tracking to generator interior analysis

This PR addresses cases such as this one from #57478:
```rust
struct Foo;
impl !Send for Foo {}

let _: impl Send = || {
    let guard = Foo;
    drop(guard);
    yield;
};
```

Previously, the `generator_interior` pass would unnecessarily include the type `Foo` in the generator because it was not aware of the behavior of `drop`. We fix this issue by introducing a drop range analysis that finds portions of the code where a value is guaranteed to be dropped. If a value is dropped at all suspend points, then it is no longer included in the generator type. Note that we are using "dropped" in a generic sense to include any case in which a value has been moved. That is, we do not only look at calls to the `drop` function.

There are several phases to the drop tracking algorithm, and we'll go into more detail below.
1. Use `ExprUseVisitor` to find values that are consumed and borrowed.
2. `DropRangeVisitor` uses consume and borrow information to gather drop and reinitialization events, as well as build a control flow graph.
3. We then propagate drop and reinitialization information through the CFG until we reach a fix point (see `DropRanges::propagate_to_fixpoint`).
4. When recording a type (see `InteriorVisitor::record`), we check the computed drop ranges to see if that value is definitely dropped at the suspend point. If so, we skip including it in the type.

## 1. Use `ExprUseVisitor` to find values that are consumed and borrowed.

We use `ExprUseVisitor` to identify the places where values are consumed. We track both the `hir_id` of the value, and the `hir_id` of the expression that consumes it. For example, in the expression `[Foo]`, the `Foo` is consumed by the array expression, so after the array expression we can consider the `Foo` temporary to be dropped.

In this process, we also collect values that are borrowed. The reason is that the MIR transform for generators conservatively assumes anything borrowed is live across a suspend point (see `rustc_mir_transform::generator::locals_live_across_suspend_points`). We match this behavior here as well.

## 2. Gather drop events, reinitialization events, and control flow graph

After finding the values of interest, we perform a post-order traversal over the HIR tree to find the points where these values are dropped or reinitialized. We use the post-order index of each event because this is how the existing generator interior analysis refers to the position of suspend points and the scopes of variables.

During this traversal, we also record branching and merging information to handle control flow constructs such as `if`, `match`, and `loop`. This is necessary because values may be dropped along some control flow paths but not others.

## 3. Iterate to fixed point

The previous pass found the interesting events and locations, but now we need to find the actual ranges where things are dropped. Upon entry, we have a list of nodes ordered by their position in the post-order traversal. Each node has a set of successors. For each node we additionally keep a bitfield with one bit per potentially consumed value. The bit is set if we the value is dropped along all paths entering this node.

To compute the drop information, we first reverse the successor edges to find each node's predecessors. Then we iterate through each node, and for each node we set its dropped value bitfield to the intersection of all incoming dropped value bitfields.

If any bitfield for any node changes, we re-run the propagation loop again.

## 4. Ignore dropped values across suspend points

At this point we have a data structure where we can ask whether a value is guaranteed to be dropped at any post order index for the HIR tree. We use this information in `InteriorVisitor` to check whether a value in question is dropped at a particular suspend point. If it is, we do not include that value's type in the generator type.

Note that we had to augment the region scope tree to include all yields in scope, rather than just the last one as we did before.

r? `@nikomatsakis`
2022-01-20 23:37:29 +01:00
Matthias Krüger
6c627d25f6
Rollup merge of #93038 - GuillaumeGomez:block-doc-comments, r=notriddle
Fix star handling in block doc comments

Fixes #92872.

Some extra explanation about this PR and why https://github.com/rust-lang/rust/pull/92357 created this regression: when we merge doc comment kinds for example in:

```rust
/// he
/**
* hello
*/
#[doc = "boom"]
```

We don't want to remove the empty lines between them. However, to correctly compute the "horizontal trim", we still need it, so instead, I put back a part of the "vertical trim" directly in the "horizontal trim" computation so it doesn't impact the output buffer but allows us to correctly handle the stars.

r? `@camelid`
2022-01-20 17:10:41 +01:00
Matthias Krüger
5c10dbd85f
Rollup merge of #92704 - 5225225:std_mem_transmute_ref_t_mut_t, r=michaelwoerister
Change lint message to be stronger for &T -> &mut T transmute

The old message implied that it's only UB if you use the reference to mutate, which (as far as I know) is not true. As in, the following program has UB, and a &T -> &mut T transmute is effectively an `unreachable_unchecked`.

```rust
fn main() {
    #[allow(mutable_transmutes)]
    unsafe {
        let _ = std::mem::transmute::<&i32, &mut i32>(&0);
    }
}
```

In the future, it might be a good idea to use the edition system to make this a hard error, since I don't think it is *ever* defined behaviour? Unless we rule that `&UnsafeCell<i32> -> &mut i32` is fine. (That, and you always could just use `.get()`, so you're not losing anything)
2022-01-20 17:10:37 +01:00
Matthias Krüger
db1253f1d2
Rollup merge of #92582 - lcnr:generic-arg-infer, r=BoxyUwU
improve `_` constants in item signature handling

removing the "type" from the error messages does slightly worsen the error messages for types, but figuring out whether the placeholder is for a type or a constant and correctly dealing with that seemed fairly difficult to me so I took the easy way out  Imo the error message is still clear enough.

r? `@BoxyUwU` cc `@estebank`
2022-01-20 17:10:35 +01:00
Matthias Krüger
413f490677
Rollup merge of #92183 - tmandry:issue-74256, r=estebank
Point at correct argument when async fn output type lifetime disagrees with signature

Fixes most of #74256.

## Problems fixed

This PR fixes a couple of related problems in the error reporting code.

### Highlighting the wrong argument

First, the error reporting code was looking at the desugared return type of an `async fn` to decide which parameter to highlight. For example, a function like

```rust
async fn async_fn(self: &Struct, f: &u32) -> &u32
{ f }
```

desugars to

```rust
async fn async_fn<'a, 'b>(self: &'a Struct, f: &'b u32)
-> impl Future<Output = &'a u32> + 'a + 'b
{ f }
```

Since `f: &'b u32` is returned but the output type is `&'a u32`, the error would occur when checking that `'a: 'b`.

The reporting code would look to see if the "offending" lifetime `'b` was included in the return type, and because the code was looking at the desugared future type, it was included. So it defaulted to reporting that the source of the other lifetime `'a` (the `self` type) was the problem, when it was really the type of `f`. (Note that if it had chosen instead to look at `'a` first, it too would have been included in the output type, and it would have arbitrarily reported the error (correctly this time) on the type of `f`.)

Looking at the actual future type isn't useful for this reason; it captures all input lifetimes. Using the written return type for `async fn` solves this problem and results in less confusing error messages for the user.

This isn't a perfect fix, unfortunately; writing the "manually desugared" form of the above function still results in the wrong parameter being highlighted. Looking at the output type of every `impl Future` return type doesn't feel like a very principled approach, though it might work. The problem would remain for function signatures that look like the desugared one above but use different traits. There may be deeper changes required to pinpoint which part of each type is conflicting.

### Lying about await point capture causing lifetime conflicts

The second issue fixed by this PR is the unnecessary complexity in `try_report_anon_anon_conflict`. It turns out that the root cause I suggested in https://github.com/rust-lang/rust/issues/76547#issuecomment-692863608 wasn't really the root cause. Adding special handling to report that a variable was captured over an await point only made the error messages less correct and pointed to a problem other than the one that actually occurred.

Given the above discussion, it's easy to see why: `async fn`s capture all input lifetimes in their return type, so holding an argument across an await point should never cause a lifetime conflict! Removing the special handling simplified the code and improved the error messages (though they still aren't very good!)

## Future work

* Fix error reporting on the "desugared" form of this code
* Get the `suggest_adding_lifetime_params` suggestion firing on these examples
  * cc #42703, I think

r? `@estebank`
2022-01-20 17:10:34 +01:00
Matthias Krüger
02379e917b
Rollup merge of #91606 - joshtriplett:stabilize-print-link-args, r=pnkfelix
Stabilize `-Z print-link-args` as `--print link-args`

We have stable options for adding linker arguments; we should have a
stable option to help debug linker arguments.

Add documentation for the new option. In the documentation, make it clear that
the *exact* format of the output is not a stable guarantee.
2022-01-20 17:10:32 +01:00
Matthias Krüger
d188287a54
Rollup merge of #89764 - tmiasko:uninhabited-enums, r=wesleywiser
Fix variant index / discriminant confusion in uninhabited enum branching

Fix confusion between variant index and variant discriminant. The pass
incorrectly assumed that for `Variants::Single` variant index is the same as
variant discriminant.

r? `@wesleywiser`
2022-01-20 17:10:31 +01:00
Rémy Rakic
820fd05e29 Update thorin-dwp to deduplicate object 2022-01-20 15:09:05 +01:00
lcnr
c29b637875 update comments 2022-01-20 14:50:35 +01:00
David Tolnay
21c1571e79
Deduplicate branches of print_break implementation 2022-01-19 19:04:36 -08:00
David Tolnay
51eeb82d9d
Inline print_newline function 2022-01-19 19:04:35 -08:00
David Tolnay
224536f4fe
Inline indent function 2022-01-19 19:04:35 -08:00
David Tolnay
9e794d7de3
Eliminate offset number from Fits frames
PrintStackElems with pbreak=PrintStackBreak::Fits always carried a
meaningless value offset=0. We can combine the two types PrintStackElem
+ PrintStackBreak into one PrintFrame enum that stores offset only for
Broken frames.
2022-01-19 19:04:34 -08:00
David Tolnay
65dd67096e
Touch up print_string 2022-01-19 19:04:33 -08:00
David Tolnay
d5f15a8c18
Replace all single character variable names 2022-01-19 19:04:32 -08:00
David Tolnay
ea23a1fac7
Combine advance_left matches 2022-01-19 19:04:31 -08:00
David Tolnay
ae75ba692a
Inline print into advance_left 2022-01-19 19:04:30 -08:00
David Tolnay
d2eb46cfec
Simplify advance_left 2022-01-19 19:03:53 -08:00
David Tolnay
351011ec3f
Simplify left_total tracking 2022-01-19 19:02:56 -08:00
David Tolnay
d981c5b354
Eliminate a token clone from advance_left 2022-01-19 19:02:25 -08:00
David Tolnay
d81740ed2a
Grow scan_stack in the conventional direction
The pretty printer algorithm involves 2 VecDeques: a ring-buffer of
tokens and a deque of ring-buffer indices. Confusingly, those two deques
were being grown in opposite directions for no good reason. Ring-buffer
pushes would go on the "back" of the ring-buffer (i.e. higher indices)
while scan_stack pushes would go on the "front" (i.e. lower indices).
This commit flips the scan_stack accesses to grow the scan_stack and
ring-buffer in the same direction, where push does the same
operation as a Vec push i.e. inserting on the high-index end.
2022-01-19 18:32:18 -08:00
David Tolnay
eec6016ec3
Delete unused Display for pretty printer Token 2022-01-19 18:31:36 -08:00
Aaron Hill
70d36a05bc
Show a more informative panic message when DefPathHash does not exist
This should hopefully make it easier to debug incremental compilation
bugs like #93096 without affecting performance.
2022-01-19 17:36:44 -05:00
Tyler Mandry
698631e16c Simplify error reporting code, remove await point wording 2022-01-19 21:33:57 +00:00
Tyler Mandry
5c15ad7fca NiceRegionError: Use written return type for async fn 2022-01-19 21:33:57 +00:00
Tyler Mandry
6487845884 Properly account for binders in get_impl_future_output_ty 2022-01-19 21:33:57 +00:00
pierwill
8d27c28e39 ⬆ chalk to 0.76.0 2022-01-19 13:44:43 -06:00
Matthias Krüger
43d508bb78
Rollup merge of #93077 - lcnr:write_substs, r=oli-obk
remove `List::is_noop`

think that `is_noop` is actually less clear than just using `is_empty`
2022-01-19 19:19:52 +01:00
Matthias Krüger
fe93f08051
Rollup merge of #93065 - dtolnay:ringbuffer, r=lcnr
Pretty printer algorithm revamp step 2

This PR follows #92923 as a second chunk of modernizations backported from https://github.com/dtolnay/prettyplease into rustc_ast_pretty.

I've broken this up into atomic commits that hopefully are sensible in isolation. At every commit, the pretty printer is compilable and has runtime behavior that is identical to before and after the PR. None of the refactoring so far changes behavior.

The general theme of this chunk of commits is: the logic in the old pretty printer is doing some very basic things (pushing and popping tokens on a ring buffer) but expressed in a too-low-level way that I found makes it quite complicated/subtle to reason about. There are a number of obvious invariants that are "almost true" -- things like `self.left == self.buf.offset` and `self.right == self.buf.offset + self.buf.data.len()` and `self.right_total == self.left_total + self.buf.data.sum()`. The reason these things are "almost true" is the implementation tends to put updating one side of the invariant unreasonably far apart from updating the other side, leaving the invariant broken while unrelated stuff happens in between. The following code from master is an example of this:

e5e2b0be26/compiler/rustc_ast_pretty/src/pp.rs (L314-L317)

In this code the `advance_right` is reserving an entry into which to write a next token on the right side of the ring buffer, the `check_stack` is doing something totally unrelated to the right boundary of the ring buffer, and the `scan_push` is actually writing the token we previously reserved space for. Much of what this PR is doing is rearranging code to shrink the amount of stuff in between when an invariant is broken to when it is restored, until the whole thing can be factored out into one indivisible method call on the RingBuffer type.

The end state of the PR is that we can entirely eliminate `self.left` (because it's now just equal to `self.buf.offset` always) and `self.right` (because it's equal to `self.buf.offset + self.buf.data.len()` always) and the whole `Token::Eof` state which used to be the value of tokens that have been reserved space for but not yet written.

I found without these changes the pretty printer implementation to be hard to reason about and I wasn't able to confidently introduce improvements like trailing commas in `prettyplease` until after this refactor. The logic here is 43 years old at this point (Graydon translated it as directly as possible from the 1979 pretty printing paper) and while there are advantages to following the paper as closely as possible, in `prettyplease` I decided if we're going to adapt the algorithm to work better for Rust syntax, it was worthwhile making it easier to follow than the original.
2022-01-19 19:19:51 +01:00
Matthias Krüger
715cda2e81
Rollup merge of #92316 - petrochenkov:extmangle, r=wesleywiser
mangling_v0: Skip extern blocks during mangling

There's no need to include the dummy `Nt` into the symbol name, items in extern blocks belong to their parent modules for all purposes except for inheriting the ABI and attributes.

Follow up to https://github.com/rust-lang/rust/pull/92032

(There's also a drive-by fix to the `rust-demangler` tool's tests, which don't run on CI, I initially attempted using them for testing this PR.)
2022-01-19 19:19:45 +01:00
Esteban Kuber
017747fa5a Only suggest adding ! to expressions that can be macro invocation 2022-01-19 18:00:10 +00:00
lcnr
4bd571c4ff remove is_noop 2022-01-19 13:58:29 +01:00
Guillaume Gomez
2938be612d Correctly handle starts in block doc comments 2022-01-19 11:18:17 +01:00
Matthias Krüger
0b9056c38a
Rollup merge of #93041 - pierwill:rm-unused-defid-ords, r=cjgillot
Remove some unused ordering derivations based on `DefId`

Like #93018, this removes some unused/unneeded ordering derivations as part of ongoing work on #90317. Here, these changes are aimed at making https://github.com/rust-lang/rust/pull/90749 easier to review, test, and merge.

r? `@cjgillot`
2022-01-19 10:42:19 +01:00
Matthias Krüger
420ada6f8a
Rollup merge of #92920 - dtolnay:printtidy, r=cjgillot
Move expr- and item-related pretty printing functions to modules

Currently *compiler/rustc_ast_pretty/src/pprust/state.rs* is 2976 lines on master. The `tidy` limit is 3000, which is blocking #92243.

This PR adds a `mod expr;` and `mod item;` to move logic related to those AST nodes out of the single huge file.
2022-01-19 10:42:18 +01:00
Matthias Krüger
9a82f74cdf
Rollup merge of #92783 - FabianWolff:issue-92726, r=nikomatsakis
Annotate dead code lint with notes about ignored derived impls

Fixes #92726. CC `@pmetzger,` is this what you had in mind?

r? `@nikomatsakis`
2022-01-19 10:42:16 +01:00
Matthias Krüger
3a1db90efb
Rollup merge of #91278 - SparrowLii:place, r=spastorino
Use iterator instead of recursion in `codegen_place`

This PR fixes the FIXME in `codegen_place` about using iterator instead of recursion when processing the `projection` field in `mir::PlaceRef`. At the same time, it also reduces the right drift.
2022-01-19 10:42:14 +01:00
Matthias Krüger
5d2928f7b9
Rollup merge of #88642 - c410-f3r:let_chains_2, r=matthewjasper
Formally implement let chains

## Let chains

My longest and hardest contribution since #64010.

Thanks to `@Centril` for creating the RFC and special thanks to `@matthewjasper` for helping me since the beginning of this journey. In fact, `@matthewjasper` did much of the complicated MIR stuff so it's true to say that this feature wouldn't be possible without him. Thanks again `@matthewjasper!`

With the changes proposed in this PR, it will be possible to chain let expressions along side local variable declarations or ordinary conditional expressions. In other words, do much of what the `if_chain` crate already does.

## Other considerations

* `if let guard` and `let ... else` features need special care and should be handled in a following PR.

* Irrefutable patterns are allowed within a let chain context

* ~~Three Clippy lints were already converted to start dogfooding and help detect possible corner cases~~

cc #53667
2022-01-19 10:42:12 +01:00
David Tolnay
4d3faae5cd
Eliminate left and right cursors in favor of ring buffer 2022-01-18 20:19:44 -08:00