Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir-def/src/attrs.rs23
-rw-r--r--crates/hir-def/src/find_path.rs40
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]