Unnamed repository; edit this file 'description' to name the repository.
| -rw-r--r-- | crates/hir-def/src/attrs.rs | 23 | ||||
| -rw-r--r-- | crates/hir-def/src/find_path.rs | 40 |
2 files changed, 60 insertions, 3 deletions
diff --git a/crates/hir-def/src/attrs.rs b/crates/hir-def/src/attrs.rs index 27f9763f08..d55509e2f0 100644 --- a/crates/hir-def/src/attrs.rs +++ b/crates/hir-def/src/attrs.rs @@ -380,6 +380,29 @@ pub fn parse_extra_crate_attrs(db: &dyn SourceDatabase, krate: Crate) -> Option< Some(p.tree()) } +/// Whether the crate root declares `#![no_std]`, looking through `cfg_attr` gating. +#[salsa::tracked(returns(copy))] +pub(crate) fn crate_supports_no_std(db: &dyn SourceDatabase, krate: Crate) -> bool { + fn contains_no_std(meta: ast::Meta) -> bool { + match meta { + ast::Meta::PathMeta(meta) => meta.path().is1("no_std"), + ast::Meta::CfgAttrMeta(meta) => meta.metas().any(contains_no_std), + ast::Meta::UnsafeMeta(meta) => meta.meta().is_some_and(contains_no_std), + ast::Meta::CfgMeta(_) | ast::Meta::KeyValueMeta(_) | ast::Meta::TokenTreeMeta(_) => { + false + } + } + } + + let root_file = krate.root_file_id(db).parse(db).tree(); + parse_extra_crate_attrs(db, krate) + .into_iter() + .flat_map(|extra| extra.attrs()) + .chain(root_file.attrs()) + .filter_map(|attr| attr.meta()) + .any(contains_no_std) +} + fn attrs_source( db: &dyn SourceDatabase, owner: AttrDefId, diff --git a/crates/hir-def/src/find_path.rs b/crates/hir-def/src/find_path.rs index f6bef86933..2f502e4915 100644 --- a/crates/hir-def/src/find_path.rs +++ b/crates/hir-def/src/find_path.rs @@ -13,6 +13,7 @@ use rustc_hash::FxHashSet; use crate::{ ModuleDefId, ModuleIdLt, + attrs::crate_supports_no_std, import_map::ImportMap, item_scope::ItemInNs, nameres::DefMap, @@ -59,7 +60,9 @@ pub fn find_path( let from_def_map = from.def_map(db); - cfg.prefer_no_std = cfg.prefer_no_std || from_def_map.is_no_std(); + let from_crate = from.krate(db); + cfg.prefer_no_std = + cfg.prefer_no_std || from_def_map.is_no_std() || crate_supports_no_std(db, from_crate); find_path_inner( &FindPathCtx { @@ -69,7 +72,7 @@ pub fn find_path( ignore_local_imports, is_std_item: item_module.krate(db).data(db).origin.is_lang(), from, - from_crate: from.krate(db), + from_crate, crate_root: from_def_map.crate_root(db), from_def_map, fuel: Cell::new(FIND_PATH_FUEL), @@ -1485,7 +1488,7 @@ pub mod fmt { "#]], ); - // Should also work (on a best-effort basis) if `no_std` is conditional. + // Should also work (on a best-effort basis) if `no_std` is conditionally enabled. check_found_path( r#" //- /main.rs crate:main deps:core,std @@ -1515,6 +1518,37 @@ pub mod fmt { BySelf (imports ✖): core::fmt::Error "#]], ); + + // Should also work (on a best-effort basis) if `no_std` is conditionally disabled. + check_found_path( + r#" +//- /main.rs crate:main deps:core,std cfg:test +#![cfg_attr(not(test), no_std)] + +$0 + +//- /std.rs crate:std deps:core + +pub mod fmt { + pub use core::fmt::Error; +} + +//- /zzz.rs crate:core + +pub mod fmt { + pub struct Error; +} + "#, + "core::fmt::Error", + expect![[r#" + Plain (imports ✔): core::fmt::Error + Plain (imports ✖): core::fmt::Error + ByCrate(imports ✔): core::fmt::Error + ByCrate(imports ✖): core::fmt::Error + BySelf (imports ✔): core::fmt::Error + BySelf (imports ✖): core::fmt::Error + "#]], + ); } #[test] |