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

Fix Async Generator ABI #105082

Merged
merged 1 commit into from
Dec 10, 2022
Merged

Fix Async Generator ABI #105082

merged 1 commit into from
Dec 10, 2022

Conversation

Swatinem
Copy link
Contributor

@Swatinem Swatinem commented Nov 30, 2022

This change was missed when making async generators implement Future directly.
It did not cause any problems in codegen so far, as GeneratorState<(), Output>
happens to have the same ABI as Poll<Output>.

@rustbot
Copy link
Collaborator

rustbot commented Nov 30, 2022

r? @compiler-errors

(rustbot has picked a reviewer for you, use r? to override)

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Nov 30, 2022
@compiler-errors
Copy link
Member

compiler-errors commented Nov 30, 2022

  1. This needs a test

  2. Doesn't this break using async {} as a generator? There's nothing keepin someone from passing async {} into a parameter accepting _: impl Generator, which is the opposite of this problem, right?

  3. How did you find this? Does this make Miri angry? Or what?

@Swatinem
Copy link
Contributor Author

1. This needs a test

Can you give a suggestion how to specifically test for the ABI here?

2. Doesn't this break using async {} as a generator? There's nothing keeping one someone from passing async {} into a parameter accepting _: impl Generator, which is the opposite of this problem, right?

async blocks / fns always went through from_generator, and now through identity_future, so they do not implement Generator directly, though this is indeed worth a test.
And this is also something to watch out for when tackling #104826.

3. How did you find this? Does this make Miri angry? Or what?

I started looking at #104828, searching for all the places that use resume_ty.

bors added a commit to rust-lang-ci/rust that referenced this pull request Dec 4, 2022
…piler-errors

Make sure async constructs do not `impl Generator`

Async lowering turns async functions and blocks into generators internally.
Though these special kinds of generators should not `impl Generator` themselves.
The other way around, normal generators should not `impl Future`.

This was discovered in rust-lang#105082 (comment) and is a regression from rust-lang#104321.

r? `@compiler-errors`
RalfJung pushed a commit to RalfJung/miri that referenced this pull request Dec 5, 2022
Make sure async constructs do not `impl Generator`

Async lowering turns async functions and blocks into generators internally.
Though these special kinds of generators should not `impl Generator` themselves.
The other way around, normal generators should not `impl Future`.

This was discovered in rust-lang/rust#105082 (comment) and is a regression from rust-lang/rust#104321.

r? `@compiler-errors`
@bjorn3
Copy link
Member

bjorn3 commented Dec 7, 2022

Friendly ping. This is blocking a rustup for cg_clif.

@Swatinem
Copy link
Contributor Author

Swatinem commented Dec 7, 2022

I think this is blocked on figuring out a good way to regression test against this in the future. I would happily do that as a followup though to unblock cg_clif.

With #104828 / #105250 I contiously took advantage that the compiler was very lenient and did not verify these things too strictly. This bug here was rather by accident. Ideally both should be covered by tests that avoid similar things in the future.

@bjorn3
Copy link
Member

bjorn3 commented Dec 7, 2022

I'm hoping to integrate cg_clif's test suite with rust's CI soonish, which should catch any regressions. A regular test would indeed be nice though. Would a MIR dump after the generator transformation for the generator of an async function that uses .await work? That should show both the function signature and what the created MIR expects as type.

@Swatinem
Copy link
Contributor Author

Swatinem commented Dec 7, 2022

That might indeed be an option, I will experiment with that tomorrow.

@Swatinem
Copy link
Contributor Author

Swatinem commented Dec 8, 2022

The MIR type is not the problem here, and it should be coming through correctly from the generator transform:

let (state_adt_ref, state_substs) = if is_async_kind {
// Compute Poll<return_ty>
let state_did = tcx.require_lang_item(LangItem::Poll, None);
let state_adt_ref = tcx.adt_def(state_did);
let state_substs = tcx.intern_substs(&[body.return_ty().into()]);
(state_adt_ref, state_substs)
} else {
// Compute GeneratorState<yield_ty, return_ty>
let state_did = tcx.require_lang_item(LangItem::GeneratorState, None);
let state_adt_ref = tcx.adt_def(state_did);
let state_substs = tcx.intern_substs(&[yield_ty.into(), body.return_ty().into()]);
(state_adt_ref, state_substs)
};
let ret_ty = tcx.mk_adt(state_adt_ref, state_substs);

fn future::{closure#0}(_1: Pin<&mut [async fn body@src/main.rs:20:19: 20:21]>, _2: &mut Context<'_>) -> Poll<()> {

The problem is rather that cg_clif and rustc_const_eval are the only places where the FnAbi of call terminators is actually checked. And you can’t call the non-const poll fn.

if !Self::check_argument_compat(&caller_fn_abi.ret, &callee_fn_abi.ret) {

I don’t see the FnAbi being checked anywhere in rustc_codegen_ssa / codegen_call_terminator.

@compiler-errors
Copy link
Member

Hm, is check_argument_compat succeeding because even though the types are unequal, they have compatible layouts?

@compiler-errors
Copy link
Member

Also, what is clif doing differently? Is it checking full type equality? Or does it just do layout for Poll vs GeneratorState differently so that they're unequal?

@Swatinem
Copy link
Contributor Author

Swatinem commented Dec 8, 2022

I don’t think we are hitting check_argument_compat at all, as that is part of rustc_const_eval which we are not going through.

For clif, I believe it is doing full type equality, but @bjorn3 can answer that better I’m sure.

@compiler-errors
Copy link
Member

rustc_const_eval is used by miri, though -- but it's just checking that size and align are equal, I think.

anyways, since this is blocking @bjorn3's upgrade, then this is fine without a test. @Swatinem, could you add a comment explaining this check on line 107? i'll approve after.

This change was missed when making async generators implement `Future` directly.
It did not cause any problems in codegen so far, as `GeneratorState<(), Output>`
happens to have the same ABI as `Poll<Output>`.
@Swatinem
Copy link
Contributor Author

Swatinem commented Dec 8, 2022

Rebased and added a comment.

@bjorn3
Copy link
Member

bjorn3 commented Dec 8, 2022

Yeah, cg_clif is checking full type equality. It has catched a lot of bugs while working on cg_clif itself. However even when relaxing the check to allow Poll/GeneratorState mismatches I still get a crash as the generated MIR attempts to write to field 0 of the return value which is an i32 for one type and () for the other type.

@compiler-errors
Copy link
Member

@bors r+

@bors
Copy link
Contributor

bors commented Dec 9, 2022

📌 Commit ecf8127 has been approved by compiler-errors

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Dec 9, 2022
bors added a commit to rust-lang-ci/rust that referenced this pull request Dec 10, 2022
…iaskrgr

Rollup of 10 pull requests

Successful merges:

 - rust-lang#98391 (Reimplement std's thread parker on top of events on SGX)
 - rust-lang#104019 (Compute generator sizes with `-Zprint_type_sizes`)
 - rust-lang#104512 (Set `download-ci-llvm = "if-available"` by default when `channel = dev`)
 - rust-lang#104901 (Implement masking in FileType comparison on Unix)
 - rust-lang#105082 (Fix Async Generator ABI)
 - rust-lang#105109 (Add LLVM KCFI support to the Rust compiler)
 - rust-lang#105505 (Don't warn about unused parens when they are used by yeet expr)
 - rust-lang#105514 (Introduce `Span::is_visible`)
 - rust-lang#105516 (Update cargo)
 - rust-lang#105522 (Remove wrong note for short circuiting operators)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit 020d7af into rust-lang:master Dec 10, 2022
@rustbot rustbot added this to the 1.68.0 milestone Dec 10, 2022
@Swatinem Swatinem deleted the async-abi branch December 10, 2022 14:18
@bjorn3
Copy link
Member

bjorn3 commented Dec 10, 2022

I can confirm that all issues for cg_clif are fixed with this PR. I will update cg_clif once a nightly with this PR is released.

@cuviper
Copy link
Member

cuviper commented Feb 9, 2023

It did not cause any problems in codegen so far,

Just for reference, this did manifest as a crash on Fedora 36 with LLVM 14:
https://bugzilla.redhat.com/show_bug.cgi?id=2168622

So far, backporting this PR does appear to fix that, thanks!

@bjorn3
Copy link
Member

bjorn3 commented Feb 9, 2023

Do we have any builders with both LLVM 14 and LLVM assertions enabled? If not I think the crash was due to pointer types being mixed up. LLVM 15 uses opaque pointers and as such there is nothing to mixup.

@cuviper
Copy link
Member

cuviper commented Feb 9, 2023

I added LLVM 14 in #107044, but that's Ubuntu's normal package. I think we only have CI builds with assertions in the bundled LLVM.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants