Skip to content

Commit 3bda70a

Browse files
committed
Auto merge of rust-lang#12041 - jonas-schievink:prefer-core-cfg-attr-no-std, r=jonas-schievink
feat: prefer core/alloc over std in auto-imports if `#[no_std]` is conditional We already did this if `#![no_std]` was present, this PR makes it work with `#![cfg_attr(not(test), no_std)]` too, which is very common in libraries. Fixes rust-lang/rust-analyzer#12035 cc rust-lang/rust-analyzer#10718
2 parents 34c3e0b + dd4a921 commit 3bda70a

File tree

2 files changed

+66
-4
lines changed

2 files changed

+66
-4
lines changed

crates/hir_def/src/db.rs

+38-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use crate::{
1818
generics::GenericParams,
1919
import_map::ImportMap,
2020
intern::Interned,
21-
item_tree::ItemTree,
21+
item_tree::{AttrOwner, ItemTree},
2222
lang_item::{LangItemTarget, LangItems},
2323
nameres::DefMap,
2424
visibility::{self, Visibility},
@@ -184,6 +184,8 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {
184184

185185
#[salsa::transparent]
186186
fn crate_limits(&self, crate_id: CrateId) -> CrateLimits;
187+
188+
fn crate_supports_no_std(&self, crate_id: CrateId) -> bool;
187189
}
188190

189191
fn crate_def_map_wait(db: &dyn DefDatabase, krate: CrateId) -> Arc<DefMap> {
@@ -204,3 +206,38 @@ fn crate_limits(db: &dyn DefDatabase, crate_id: CrateId) -> CrateLimits {
204206
recursion_limit: def_map.recursion_limit().unwrap_or(128),
205207
}
206208
}
209+
210+
fn crate_supports_no_std(db: &dyn DefDatabase, crate_id: CrateId) -> bool {
211+
let file = db.crate_graph()[crate_id].root_file_id;
212+
let item_tree = db.file_item_tree(file.into());
213+
let attrs = item_tree.raw_attrs(AttrOwner::TopLevel);
214+
for attr in &**attrs {
215+
match attr.path().as_ident().and_then(|id| id.as_text()) {
216+
Some(ident) if ident == "no_std" => return true,
217+
Some(ident) if ident == "cfg_attr" => {}
218+
_ => continue,
219+
}
220+
221+
// This is a `cfg_attr`; check if it could possibly expand to `no_std`.
222+
// Syntax is: `#[cfg_attr(condition(cfg, style), attr0, attr1, <...>)]`
223+
let tt = match attr.token_tree_value() {
224+
Some(tt) => &tt.token_trees,
225+
None => continue,
226+
};
227+
228+
let segments = tt.split(|tt| match tt {
229+
tt::TokenTree::Leaf(tt::Leaf::Punct(p)) if p.char == ',' => true,
230+
_ => false,
231+
});
232+
for output in segments.skip(1) {
233+
match output {
234+
[tt::TokenTree::Leaf(tt::Leaf::Ident(ident))] if ident.text == "no_std" => {
235+
return true
236+
}
237+
_ => {}
238+
}
239+
}
240+
}
241+
242+
false
243+
}

crates/hir_def/src/find_path.rs

+28-3
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,7 @@ impl ModPathExt for ModPath {
4343
self.segments().first() == Some(&known::std)
4444
}
4545

46-
// When std library is present, paths starting with `std::`
47-
// should be preferred over paths starting with `core::` and `alloc::`
46+
// Can we replace the first segment with `std::` and still get a valid, identical path?
4847
fn can_start_with_std(&self) -> bool {
4948
let first_segment = self.segments().first();
5049
first_segment == Some(&known::alloc) || first_segment == Some(&known::core)
@@ -203,7 +202,7 @@ fn find_path_inner_(
203202
}
204203

205204
// - otherwise, look for modules containing (reexporting) it and import it from one of those
206-
let prefer_no_std = db.attrs(crate_root.into()).by_key("no_std").exists();
205+
let prefer_no_std = db.crate_supports_no_std(crate_root.krate);
207206
let mut best_path = None;
208207
let mut best_path_len = max_len;
209208

@@ -830,6 +829,32 @@ pub mod fmt {
830829
831830
//- /zzz.rs crate:core
832831
832+
pub mod fmt {
833+
pub struct Error;
834+
}
835+
"#,
836+
"core::fmt::Error",
837+
"core::fmt::Error",
838+
"core::fmt::Error",
839+
"core::fmt::Error",
840+
);
841+
842+
// Should also work (on a best-effort basis) if `no_std` is conditional.
843+
check_found_path(
844+
r#"
845+
//- /main.rs crate:main deps:core,std
846+
#![cfg_attr(not(test), no_std)]
847+
848+
$0
849+
850+
//- /std.rs crate:std deps:core
851+
852+
pub mod fmt {
853+
pub use core::fmt::Error;
854+
}
855+
856+
//- /zzz.rs crate:core
857+
833858
pub mod fmt {
834859
pub struct Error;
835860
}

0 commit comments

Comments
 (0)