From 910ba237debcc7671e4b11d39ef96dbd404b971a Mon Sep 17 00:00:00 2001
From: Sergey Fedorov <barracuda@macos-powerpc.org>
Date: Thu, 23 Jul 2026 01:46:20 +0000
Subject: [PATCH 17/30] parse: use the crate's edition for module files, not
 the stream's

A `mod name;` item emitted by a foreign macro was loading the module
file with the macro's edition: `Lexer sub_lex(path, lex.get_edition(),
...)` picks up the expansion stream's edition. Seen with dirs 2.0.2
(edition 2015), whose `mod mac;` is emitted by `cfg_if!` from cfg-if
0.1.10 (edition 2018): mac.rs was parsed as edition 2018, so its
`use std::path::PathBuf;` was treated as module-relative and failed
with "Cannot find component 1 of crate::mac::std::path::PathBuf".

A module file's tokens belong to the crate being compiled, so parse it
with the crate's edition (via ParseState::crate, which is set on both
top-level and macro-expansion streams; same-file fallback keeps the old
behaviour if it is ever null). Inline `mod name { ... }` bodies passed
through a foreign macro would need per-token edition preservation in
the $:tt capture path and are not covered here.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013wCVW89GjmNyYviEcANPHM
---
 src/parse/root.cpp | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/src/parse/root.cpp b/src/parse/root.cpp
index 31b97775..59b04df6 100644
--- a/src/parse/root.cpp
+++ b/src/parse/root.cpp
@@ -2430,7 +2430,14 @@ namespace {
                     ERROR(lex.point_span(), E0000, "Can't find file for '" << name << "' in '" << mod_fileinfo.path << "'");
                 }
                 DEBUG("- path = " << submod.m_file_info.path);
-                Lexer sub_lex(submod.m_file_info.path, lex.get_edition(), lex.parse_state());
+                // NOTE: A module file's tokens belong to the crate being parsed, so use the
+                // crate's edition - the stream's edition here can be a foreign macro's when
+                // the `mod` item was emitted by e.g. `cfg_if!` (edition 2018) expanding
+                // inside an edition-2015 crate (seen with `dirs` 2.0.2's `mod mac;`, whose
+                // `use std::path::PathBuf` then mis-resolved module-relative).
+                Lexer sub_lex(submod.m_file_info.path,
+                    lex.parse_state().crate ? lex.parse_state().crate->m_edition : lex.get_edition(),
+                    lex.parse_state());
                 Parse_ModRoot(sub_lex, submod, meta_items);
                 GET_CHECK_TOK(tok, sub_lex, TOK_EOF);
             }
@@ -2466,7 +2473,14 @@ namespace {
                     ERROR(lex.point_span(), E0000, "Can't find file for '" << name << "' in '" << mod_fileinfo.path << "'");
                 }
                 DEBUG("- path = " << submod.m_file_info.path);
-                Lexer sub_lex(submod.m_file_info.path, lex.get_edition(), lex.parse_state());
+                // NOTE: A module file's tokens belong to the crate being parsed, so use the
+                // crate's edition - the stream's edition here can be a foreign macro's when
+                // the `mod` item was emitted by e.g. `cfg_if!` (edition 2018) expanding
+                // inside an edition-2015 crate (seen with `dirs` 2.0.2's `mod mac;`, whose
+                // `use std::path::PathBuf` then mis-resolved module-relative).
+                Lexer sub_lex(submod.m_file_info.path,
+                    lex.parse_state().crate ? lex.parse_state().crate->m_edition : lex.get_edition(),
+                    lex.parse_state());
                 Parse_ModRoot(sub_lex, submod, meta_items);
                 GET_CHECK_TOK(tok, sub_lex, TOK_EOF);
             }
-- 
2.43.0

