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

Implement tainted_by_errors in MIR borrowck, use it to skip CTFE #93691

Merged
merged 7 commits into from
Feb 12, 2022
Prev Previous commit
Next Next commit
always cache result from mir_borrowck
compiler-errors committed Feb 11, 2022
commit 8b7b0a0e49cf3e313d0432d1f6e8ce20253fef0a
3 changes: 2 additions & 1 deletion compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
@@ -836,13 +836,14 @@ rustc_queries! {
/// additional requirements that the closure's creator must verify.
query mir_borrowck(key: LocalDefId) -> &'tcx mir::BorrowCheckResult<'tcx> {
desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key.to_def_id()) }
cache_on_disk_if(tcx) { tcx.is_typeck_child(key.to_def_id()) }
cache_on_disk_if { true }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this necessary?

I'm going to do a perf run,? but maybe we just need to check the tainted flag here, too

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was getting ICEs in incremental tests complaining that the MIR body for a fn was stolen, since we're now calling borrowck which depends on unoptimized MIR which is probably gone if we do const eval late in the compilation process...

Not sure if only caching if the body if it is tainted works, since we're unconditionally calling borrowck before const eval.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

heh, yea, this is what @BoxyUwU ran into, too, and we never got as far as to figuring it out.

I guess it makes sense that if the cache rules differ between two queries that work on stealing things, that said caching breaks, but it's really opaque to me. Well... let's see what perf says

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perf does show the additional query result serialization, so we should try to do something here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's probably not worth it, but we could try adding a query that returns just an Option<ErrorReported> and does all the processing of typeck, borrowck and const qualifs. Then we can only cache that on disk and it should rarely get recomputed. But: new query so probably overkill, but worth an experiment?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'm not exactly sure what we can do to limit cache_on_disk just to when it's needed, since it seems like we need to cache it for any body that has a promoted const, see the failing query stack trace:

query stack during panic:
#0 [mir_borrowck] borrow-checking `lit_test::lit_test`
#1 [eval_to_allocation_raw] const-evaluating + checking `lit_test::lit_test::promoted[1]`
#2 [eval_to_allocation_raw] const-evaluating + checking `lit_test::lit_test::promoted[1]`
#3 [optimized_mir] optimizing MIR for `lit_test::lit_test`
#4 [collect_and_partition_mono_items] collect_and_partition_mono_items

... but we don't know if a body has any promoted consts until after borrowck.

so I might try the query experiment you suggested. I'll ping you for a perf run when I put it up, since I don't have super powers.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, we do know it at borrowck time, so we could encode that info in the borrowck result.

But maybe we're going about this the wrong way. When we force mir borrowck and then steal the mir, we own the mir, so we can mutate it and change its tainted field. This is essentially the same idea as the merging of the tainted flags into one query only we're putting it right in the data we have to load anyway

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, we do know it at borrowck time, so we could encode that info in the borrowck result.

Oh lol, I thought we did borrowck on mir_built, whoopsy.

When we force mir borrowck and then steal the mir, we own the mir, so we can mutate it and change its tainted field.

So you're suggesting we do add the tainted field to mir::Body then, instead of BorrowCheckerResult?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need it on both, as (as you reminded me) you can't mutate the mir from borrowck. But at the query that steals the mir after forcing the borrowck query, you can just call borrowck instead of forcing it and copy the tainted field over to the mir body you just stole

}
query mir_borrowck_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::BorrowCheckResult<'tcx> {
desc {
|tcx| "borrow-checking the const argument`{}`",
tcx.def_path_str(key.0.to_def_id())
}
cache_on_disk_if { true }
}

/// Gets a complete map from all types to their inherent impls.