From 2447f8604a8077d8422762ce7a1d0984485079ec Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Thu, 23 Jul 2026 01:46:20 +0000 Subject: [PATCH 13/25] 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 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 168bfde2..9f4f8662 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -2457,7 +2457,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); } @@ -2493,7 +2500,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