diff --git a/crates/hir-def/src/attrs.rs b/crates/hir-def/src/attrs.rs index 5286cb258739..ca085b825f1e 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 82ddaff18997..406a688a5a5a 100644 --- a/crates/hir-def/src/find_path.rs +++ b/crates/hir-def/src/find_path.rs @@ -1485,7 +1485,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 @@ -1501,6 +1501,37 @@ pub mod fmt { //- /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 + "#]], + ); + + // 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; }