From 062fef3c8c2002e80c13a8712ee2fa6893141585 Mon Sep 17 00:00:00 2001
From: Sergey Fedorov <barracuda@macos-powerpc.org>
Date: Sat, 25 Jul 2026 16:44:24 +0000
Subject: [PATCH 27/30] resolve: fall back to the requested->real crate name
 map in path lookup

m_extern_crates is keyed by the real loaded crate name (e.g.
"std-0_0_0"), but AST `extern crate` items hold the requested name
until Expand_Mod rewrites them. Speculative use-resolution inside a
macro-generated module can run before that rewrite and hit
"BUG: Unable to find crate `std`". Map through AST::g_implicit_crates
before asserting, at both Crate-item lookup sites. Seen with backtrace
0.3.72, whose `mod gimli;` (from cfg_if!) contains
`extern crate std as mystd;` after `use mystd::...` items (blocks yj).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GNXc7PddzJE4X1swqbe3Xn
---
 src/resolve/common.cpp | 50 +++++++++++++++++++++++++++++++++---------
 1 file changed, 40 insertions(+), 10 deletions(-)

diff --git a/src/resolve/common.cpp b/src/resolve/common.cpp
index 3e5822e4..7f1ddbb0 100644
--- a/src/resolve/common.cpp
+++ b/src/resolve/common.cpp
@@ -138,14 +138,31 @@ namespace {
                             // Ignore, keep going
                             }
                         TU_ARMA(Crate, c) {
-                            if(out_path) {
-                                *out_path = AST::AbsolutePath(c.name,{});
-                            }
                             if( c.name == "" ) {
+                                if(out_path) {
+                                    *out_path = AST::AbsolutePath(c.name,{});
+                                }
                                 return get_module_ast(crate.m_root_module, path, 1, ignore_last, out_path);
                             }
-                            ASSERT_BUG(sp, crate.m_extern_crates.count(c.name) > 0, "Unable to find crate `" << c.name << "`");
-                            return get_module_hir(crate.m_extern_crates.at(c.name).m_hir->m_root_module, path, 1, ignore_last, out_path);
+                            // NOTE: `c.name` is the AST `extern crate` item's REQUESTED name
+                            // (e.g. `std` in `extern crate std as mystd;`), which can differ
+                            // from the key `m_extern_crates` is stored under (the real loaded
+                            // crate name). This mismatch happens when speculative resolution
+                            // runs on a macro-generated module before `Expand_Mod`'s Crate arm
+                            // has rewritten `c.name` to the real name - fall back to the
+                            // requested->real name mapping in that case.
+                            auto crate_name = c.name;
+                            if( crate.m_extern_crates.count(crate_name) == 0 ) {
+                                auto ec_it = AST::g_implicit_crates.find(c.name);
+                                if( ec_it != AST::g_implicit_crates.end() && crate.m_extern_crates.count(ec_it->second) > 0 ) {
+                                    crate_name = ec_it->second;
+                                }
+                            }
+                            if(out_path) {
+                                *out_path = AST::AbsolutePath(crate_name,{});
+                            }
+                            ASSERT_BUG(sp, crate.m_extern_crates.count(crate_name) > 0, "Unable to find crate `" << crate_name << "`");
+                            return get_module_hir(crate.m_extern_crates.at(crate_name).m_hir->m_root_module, path, 1, ignore_last, out_path);
                             }
                         TU_ARMA(Module, m) {
                             return get_module_ast(m, path, 1, ignore_last, out_path);
@@ -308,17 +325,30 @@ namespace {
                         mod = &e->as_Module();
                     }
                     else if( const auto* i = e->opt_Crate() ) {
-                        if(out_path) {
-                            *out_path = AST::AbsolutePath(i->name, {});
-                        }
                         if( i->name == "" )
                         {
+                            if(out_path) {
+                                *out_path = AST::AbsolutePath(i->name, {});
+                            }
                             return get_module_ast(crate.m_root_module, path, idx+1, ignore_last, out_path);
                         }
                         else
                         {
-                            ASSERT_BUG(sp, crate.m_extern_crates.count(i->name) != 0, "Cannot find crate `" << i->name << "`");
-                            return get_module_hir(crate.m_extern_crates.at(i->name).m_hir->m_root_module, path, idx+1, ignore_last, out_path);
+                            // See the equivalent fallback above: `i->name` is the requested
+                            // name of an `extern crate` AST item, which may not yet have been
+                            // rewritten to the real loaded crate name (m_extern_crates' key).
+                            auto crate_name = i->name;
+                            if( crate.m_extern_crates.count(crate_name) == 0 ) {
+                                auto ec_it = AST::g_implicit_crates.find(i->name);
+                                if( ec_it != AST::g_implicit_crates.end() && crate.m_extern_crates.count(ec_it->second) > 0 ) {
+                                    crate_name = ec_it->second;
+                                }
+                            }
+                            if(out_path) {
+                                *out_path = AST::AbsolutePath(crate_name, {});
+                            }
+                            ASSERT_BUG(sp, crate.m_extern_crates.count(crate_name) != 0, "Cannot find crate `" << crate_name << "`");
+                            return get_module_hir(crate.m_extern_crates.at(crate_name).m_hir->m_root_module, path, idx+1, ignore_last, out_path);
                         }
                     }
                     else {
-- 
2.43.0

