Skip to content

fix ICE in note_and_explain when handling cross crate DefIds#153382

Open
Shrey-N wants to merge 12 commits intorust-lang:mainfrom
Shrey-N:main
Open

fix ICE in note_and_explain when handling cross crate DefIds#153382
Shrey-N wants to merge 12 commits intorust-lang:mainfrom
Shrey-N:main

Conversation

@Shrey-N
Copy link

@Shrey-N Shrey-N commented Mar 4, 2026

View all comments

Fixes an Internal Compiler Error (ICE) in note_and_explain where the compiler would panic with DefId::expect_local: DefId(...) isn't local when attempting to explain lifetime errors involving definitions from external crates.
The crash occurred because the diagnostic logic assumed that items being explained were always local to the current crate. This replaces .expect_local() with .as_local() to safely handle cross crate DefIds, falling back to tcx.def_span() for external definitions.
A regression test is included in tests/ui/lifetimes/ice-cross-crate-defid.rs using an auxiliary crate to reproduce the cross-crate boundary condition.

Fixes

Fixes #153375

@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 Mar 4, 2026
@rustbot
Copy link
Collaborator

rustbot commented Mar 4, 2026

r? @nnethercote

rustbot has assigned @nnethercote.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: compiler, types
  • compiler, types expanded to 69 candidates
  • Random selection from 15 candidates

@rust-log-analyzer

This comment has been minimized.

@nnethercote
Copy link
Contributor

#153375 doesn't have any steps to reproduce. How did you determine that this test case reproduces the problem?

@lqd
Copy link
Member

lqd commented Mar 4, 2026

The test doesn’t have error annotations either, does it actually ICE with the fix reverted?

@nnethercote
Copy link
Contributor

nnethercote commented Mar 4, 2026

does it actually ICE with the fix reverted?

I tested this and no, it doesn't ICE. (It does fail with "error: ui test did not emit an error" both before and after the reversion.)

@lqd
Copy link
Member

lqd commented Mar 4, 2026

Seeing the test the LLM produced having nothing to do with the code in the repository from that issue, I expected that as well. I wonder if the fix was tried on that crate.

@Shrey-N
Copy link
Author

Shrey-N commented Mar 4, 2026

Hiya @nnethercote and @lqd

My bad, I totally missed that. Because the test was using check pass, the compiler never actually entered the diagnostic code path.

I am updating the test right now to include a lifetime mistake on purpose. That should force the compiler to look at the external trait and try to explain why the lifetimes don't match which is exactly where it hits that expect_local panic without the fix.

Give me just a second to push it

@lqd
Copy link
Member

lqd commented Mar 4, 2026

The issue mentions the ICE happening with cargo check, and the test wasn’t using check pass either.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@Shrey-N
Copy link
Author

Shrey-N commented Mar 4, 2026

You are right @lqd my previous test used check pass, it was valid and never entered the diagnostic code path.

I have pushed an update with a deliberate lifetime error to force the exact cross-crate region explanation that triggered the ICE. (And just fixed the tidy error which is now back again :( ).

@lqd
Copy link
Member

lqd commented Mar 4, 2026

That should force the compiler

Did you try, and did it work?

@rust-log-analyzer

This comment has been minimized.

Fix lifetime issue in test function to ensure proper bounds.
@Shrey-N
Copy link
Author

Shrey-N commented Mar 4, 2026

@lqd I don't have my local environment built to test it properly but the CI just proved it works perfectly

The recent CI run failed because the compiler successfully emitted the expected error: lifetime may not live long enough instead of crashing with the expect_local() ICE.

I just pushed the missing ice-cross-crate-defid.stderr file, so the checks should pass completely now. Thanks for bearing with me :)

@lqd
Copy link
Member

lqd commented Mar 4, 2026

I don't have my local environment built to test it properly

Just running any rustc will work to do that. Let us know how that goes!

I just pushed the missing ice-cross-crate-defid.stderr file

Did the LLM generate it, you need some kind of environment to bless it otherwise, and can't you check in that environment?

the checks should pass completely now

They will not, and our questions are to see how effective is the fix.

the CI just proved it works perfectly

Not yet, because that depends on the question above.

You are right @lqd my previous test used check pass, it was valid and never entered the diagnostic code path.

(I had said quite the opposite.)

@rust-log-analyzer

This comment has been minimized.

@Shrey-N
Copy link
Author

Shrey-N commented Mar 4, 2026

@lqd I did not use an LLM, I actually just copied the ---stderr--- block out of the aarch64-gnu-llvm-20-1 CI failure log, that ran on the PR, I am having issues building x.py locally, I tried to take a wrong shortcut of using the CI logs... And yea i misread the earlier comment of yours, I apologise for the confusion from my side, I am trying to set up a proper linux env from source, for verification, I will message back once the tests run. :(

@lqd
Copy link
Member

lqd commented Mar 4, 2026

Oh, it was quite unlucky that some characters had changed in the copy paste then.

@Shrey-N
Copy link
Author

Shrey-N commented Mar 4, 2026

image_2026-03-04_151800591

@lqd I actually made a manual edit before, I was dumb -_- messed it up thought I knew better than the compiler, now I ran it on my machine, this should work now (attached an ss), The updated .stderr should work properly

@lqd
Copy link
Member

lqd commented Mar 4, 2026

Cool you have both a Windows and Linux environment now, did the ICE reproduce there?

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@Shrey-N
Copy link
Author

Shrey-N commented Mar 4, 2026

image @lqd I was able to reproduce the ICE locally :)

@lqd
Copy link
Member

lqd commented Mar 4, 2026

This is showing the test, not the ICE though. Try to rerun that test again, but with the first commit reverted. It needs to fail.

Similarly, also try running the compiler you have now built in that screenshot (with the fix in the first commit still in) on the crate linked in the issue, following the steps to reproduce there. It needs to not ICE there.

@rust-log-analyzer
Copy link
Collaborator

The job aarch64-gnu-llvm-20-1 failed! Check out the build log: (web) (plain enhanced) (plain)

Click to see the possible cause of the failure (guessed by this bot)
/dev/sda15       98M  6.4M   92M   7% /boot/efi
tmpfs           1.6G   16K  1.6G   1% /run/user/1001
================================================================================

Sufficient disk space available (120307280KB >= 52428800KB). Skipping cleanup.
##[group]Run echo "[CI_PR_NUMBER=$num]"
echo "[CI_PR_NUMBER=$num]"
shell: /usr/bin/bash --noprofile --norc -e -o pipefail {0}
---
set -ex

# Run a subset of tests. Used to run tests in parallel in multiple jobs.

# When this job partition is run as part of PR CI, skip tidy to allow revealing more failures. The
# dedicated `tidy` job failing won't block other PR CI jobs from completing, and so tidy failures
# shouldn't inhibit revealing other failures in PR CI jobs.
if [ "$PR_CI_JOB" == "1" ]; then
  echo "PR_CI_JOB set; skipping tidy"
  SKIP_TIDY="--skip tidy"
fi

../x.py --stage 2 test \
  ${SKIP_TIDY:+$SKIP_TIDY} \
  --skip compiler \
  --skip src
#!/bin/bash

set -ex

# Run a subset of tests. Used to run tests in parallel in multiple jobs.

# When this job partition is run as part of PR CI, skip tidy to allow revealing more failures. The
# dedicated `tidy` job failing won't block other PR CI jobs from completing, and so tidy failures
# shouldn't inhibit revealing other failures in PR CI jobs.
if [ "$PR_CI_JOB" == "1" ]; then
  echo "PR_CI_JOB set; skipping tidy"
  SKIP_TIDY="--skip tidy"
fi

../x.py --stage 2 test \
  ${SKIP_TIDY:+$SKIP_TIDY} \
  --skip tests \
  --skip coverage-map \
  --skip coverage-run \
  --skip library \
  --skip tidyselftest
---
##[endgroup]
Executing "/scripts/stage_2_test_set1.sh"
+ /scripts/stage_2_test_set1.sh
+ '[' 1 == 1 ']'
+ echo 'PR_CI_JOB set; skipping tidy'
+ SKIP_TIDY='--skip tidy'
+ ../x.py --stage 2 test --skip tidy --skip compiler --skip src
PR_CI_JOB set; skipping tidy
##[group]Building bootstrap
    Finished `dev` profile [unoptimized] target(s) in 0.04s
##[endgroup]
---
test [ui] tests/ui/abi/abi-sysv64-register-usage.rs ... ignored, ignored when the architecture is aarch64
test [ui] tests/ui/abi/abi-typo-unstable.rs#feature_disabled ... ok
test [ui] tests/ui/abi/abi-typo-unstable.rs#feature_enabled ... ok
test [ui] tests/ui/abi/anon-extern-mod.rs ... ok
test [ui] tests/ui/abi/avr-sram.rs#disable_sram ... ok
test [ui] tests/ui/abi/arm-unadjusted-intrinsic.rs#aarch64 ... ok
test [ui] tests/ui/abi/avr-sram.rs#no_sram ... ok
test [ui] tests/ui/abi/avr-sram.rs#has_sram ... ok
test [ui] tests/ui/abi/arm-unadjusted-intrinsic.rs#arm ... ok
test [ui] tests/ui/abi/bad-custom.rs ... ok
test [ui] tests/ui/abi/c-stack-as-value.rs ... ok
test [ui] tests/ui/abi/c-zst.rs#aarch64-darwin ... ok
test [ui] tests/ui/abi/c-zst.rs#powerpc-linux ... ok
---
test [ui] tests/ui/asm/aarch64/may_unwind.rs ... ok
test [ui] tests/ui/asm/aarch64/type-check-2.rs ... ok
test [ui] tests/ui/asm/aarch64/type-check-3.rs ... ok
test [ui] tests/ui/asm/aarch64/type-f16.rs ... ok
test [ui] tests/ui/asm/aarch64v8r.rs#hf ... ok
test [ui] tests/ui/asm/aarch64v8r.rs#r82 ... ok
test [ui] tests/ui/asm/aarch64/sym.rs ... ok
test [ui] tests/ui/asm/arm-low-dreg.rs ... ok
test [ui] tests/ui/asm/asm-with-nested-closure.rs ... ok
test [ui] tests/ui/asm/binary_asm_labels.rs ... ignored, only executed when the architecture is x86_64
test [ui] tests/ui/asm/aarch64v8r.rs#sf ... ok
test [ui] tests/ui/asm/cfg-parse-error.rs ... ok
test [ui] tests/ui/asm/cfg.rs#reva ... ignored, only executed when the architecture is x86_64
test [ui] tests/ui/asm/cfg.rs#revb ... ignored, only executed when the architecture is x86_64
test [ui] tests/ui/asm/bad-template.rs#aarch64 ... ok
test [ui] tests/ui/asm/binary_asm_labels_allowed.rs ... ok
---
test [ui] tests/ui/const-generics/ogca/basic.rs ... ok
test [ui] tests/ui/const-generics/ogca/basic-fail.rs ... ok
test [ui] tests/ui/const-generics/occurs-check/unused-substs-4.rs ... ok
test [ui] tests/ui/const-generics/occurs-check/unused-substs-5.rs ... ok
test [ui] tests/ui/const-generics/ogca/coherence-ambiguous.rs ... ok
test [ui] tests/ui/const-generics/ogca/rhs-but-not-root.rs ... ok
test [ui] tests/ui/const-generics/ogca/generic-param-rhs.rs ... ok
test [ui] tests/ui/const-generics/outer-lifetime-in-const-generic-default.rs ... ok
test [ui] tests/ui/const-generics/opaque_types.rs ... ok
test [ui] tests/ui/const-generics/opaque_types2.rs ... ok
test [ui] tests/ui/const-generics/overlapping_impls.rs ... ok
test [ui] tests/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs#full ... ok
---
test [ui] tests/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs#fat2 ... ok
test [ui] tests/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs#fat3 ... ok
test [ui] tests/ui/extern/issue-80074.rs ... ok
test [ui] tests/ui/extern/issue-95829.rs ... ok
test [ui] tests/ui/extern/lgamma-linkage.rs ... ok
test [ui] tests/ui/extern/no-mangle-associated-fn.rs ... ok
test [ui] tests/ui/extern/not-in-block.rs ... ok
test [ui] tests/ui/extern/unsized-extern-derefmove.rs ... ok
test [ui] tests/ui/extern/windows-tcb-trash-13259.rs ... ok
test [ui] tests/ui/feature-gates/allow-features-empty.rs ... ok
---
test [ui] tests/ui/feature-gates/feature-gate-macro-derive.rs ... ok
test [ui] tests/ui/feature-gates/feature-gate-macro-metavar-expr-concat.rs ... ok
test [ui] tests/ui/feature-gates/feature-gate-marker_trait_attr.rs ... ok
test [ui] tests/ui/feature-gates/feature-gate-may-dangle.rs ... ok
test [ui] tests/ui/feature-gates/feature-gate-mgca-type-const-syntax.rs ... ok
test [ui] tests/ui/feature-gates/feature-gate-min-generic-const-args.rs ... ok
test [ui] tests/ui/feature-gates/feature-gate-movrs_target_feature.rs ... ignored, only executed when the architecture is x86_64
test [ui] tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs ... ok
test [ui] tests/ui/feature-gates/feature-gate-min_const_fn.rs ... ok
test [ui] tests/ui/feature-gates/feature-gate-naked_functions_rustic_abi.rs ... ignored, only executed when the architecture is x86_64
---
test [ui] tests/ui/imports/ambiguous-9.rs ... ok
test [ui] tests/ui/imports/ambiguous-import-visibility-module.rs ... ok
test [ui] tests/ui/imports/ambiguous-glob-vs-expanded-extern.rs ... ok
test [ui] tests/ui/imports/ambiguous-8.rs ... ok
test [ui] tests/ui/imports/ambiguous-panic-globvsglob.rs ... ok
test [ui] tests/ui/imports/ambiguous-panic-glob-vs-multiouter.rs ... ok
test [ui] tests/ui/imports/ambiguous-panic-no-implicit-prelude.rs ... ok
test [ui] tests/ui/imports/ambiguous-panic-non-prelude-core-glob.rs ... ok
test [ui] tests/ui/imports/ambiguous-panic-non-prelude-std-glob.rs ... ok
test [ui] tests/ui/imports/ambiguous-panic-pick-core.rs ... ok
test [ui] tests/ui/imports/ambiguous-panic-pick-std.rs ... ok
---
test [ui] tests/ui/layout/randomize.rs#randomize-layout ... ok
test [ui] tests/ui/layout/null-pointer-optimization.rs ... ok
test [ui] tests/ui/layout/reprc-power-alignment.rs ... ok
test [ui] tests/ui/layout/size-of-val-raw-too-big.rs ... ignored, only executed when the pointer width is 32bit (Layout computation rejects this layout for different reasons on 64-bit.)
test [ui] tests/ui/layout/rigid-alias-due-to-broken-impl.rs ... ok
test [ui] tests/ui/layout/struct.rs ... ok
test [ui] tests/ui/layout/rust-call-abi-not-a-tuple-ice-81974.rs ... ok
test [ui] tests/ui/layout/thaw-transmute-invalid-enum.rs ... ok
test [ui] tests/ui/layout/rigid-alias-no-params.rs ... ok
test [ui] tests/ui/layout/thaw-validate-invalid-enum.rs ... ok
---
1 error: lifetime may not live long enough
-   --> $DIR/ice-cross-crate-defid.rs:7:5
+   --> $DIR/ice-cross-crate-defid.rs:6:5
3    |
4 LL | fn test<'a, T: ExternalTrait>(a: &'a mut T) -> impl std::future::Future<Output = ()> + 'static {
5    |         -- lifetime `'a` defined here

18    |
19 
20 error: aborting due to 1 previous error
---
To only update this specific test, also pass `--test-args lifetimes/ice-cross-crate-defid.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: env -u RUSTC_LOG_COLOR RUSTC_ICE="0" RUST_BACKTRACE="short" "/checkout/obj/build/aarch64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/lifetimes/ice-cross-crate-defid.rs" "-Zthreads=1" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "-Z" "ignore-directory-in-diagnostics-source-blocks=/checkout/vendor" "--sysroot" "/checkout/obj/build/aarch64-unknown-linux-gnu/stage2" "--target=aarch64-unknown-linux-gnu" "--check-cfg" "cfg(test,FALSE)" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/aarch64-unknown-linux-gnu/test/ui/lifetimes/ice-cross-crate-defid" "-A" "unused" "-W" "unused_attributes" "-A" "internal_features" "-A" "unused_parens" "-A" "unused_braces" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/aarch64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/aarch64-unknown-linux-gnu/test/ui/lifetimes/ice-cross-crate-defid/auxiliary"
stdout: none
--- stderr -------------------------------
error: lifetime may not live long enough
##[error]  --> /checkout/tests/ui/lifetimes/ice-cross-crate-defid.rs:6:5
   |
LL | fn test<'a, T: ExternalTrait>(a: &'a mut T) -> impl std::future::Future<Output = ()> + 'static {
   |         -- lifetime `'a` defined here
LL |     a.build_request()
   |     ^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
   |
help: consider changing `impl Future<Output = ()> + 'static`'s explicit `'static` bound to the lifetime of argument `a`
   |
LL - fn test<'a, T: ExternalTrait>(a: &'a mut T) -> impl std::future::Future<Output = ()> + 'static {
LL + fn test<'a, T: ExternalTrait>(a: &'a mut T) -> impl std::future::Future<Output = ()> + 'a {
   |
help: alternatively, add an explicit `'static` bound to this reference
   |
LL - fn test<'a, T: ExternalTrait>(a: &'a mut T) -> impl std::future::Future<Output = ()> + 'static {
LL + fn test<'a, T: ExternalTrait>(a: &'static mut T) -> impl std::future::Future<Output = ()> + 'static {
   |

error: aborting due to 1 previous error
------------------------------------------

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[ICE]: "DefId::expect_local: … isn't local" in phantom-lifetime heavy traits

5 participants