Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit a647ba2

Browse files
committedJun 1, 2023
Remember names of cfg-ed out items to mention them in diagnostics
`#[cfg]`s are frequently used to gate crate content behind cargo features. This can lead to very confusing errors when features are missing. For example, `serde` doesn't have the `derive` feature by default. Therefore, `serde::Serialize` fails to resolve with a generic error, even though the macro is present in the docs. This commit adds a list of all stripped item names to metadata. This is filled during macro expansion and then, through a fed query, persisted in metadata. The downstream resolver can then access the metadata to look at possible candidates for mentioning in the errors. This slightly increases metadata (800k->809k for the feature-heavy windows crate), but not enough to really matter.
1 parent 642c92e commit a647ba2

30 files changed

+599
-84
lines changed
 

‎compiler/rustc_ast/src/expand/mod.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
11
//! Definitions shared by macros / syntax extensions and e.g. `rustc_middle`.
22
3+
use rustc_span::{def_id::DefId, symbol::Ident};
4+
5+
use crate::MetaItem;
6+
37
pub mod allocator;
8+
9+
#[derive(Debug, Clone, Encodable, Decodable, HashStable_Generic)]
10+
pub struct StrippedCfgItem<ModId = DefId> {
11+
pub parent_module: ModId,
12+
pub name: Ident,
13+
pub cfg: MetaItem,
14+
}
15+
16+
impl<ModId> StrippedCfgItem<ModId> {
17+
pub fn map_mod_id<New>(self, f: impl FnOnce(ModId) -> New) -> StrippedCfgItem<New> {
18+
StrippedCfgItem { parent_module: f(self.parent_module), name: self.name, cfg: self.cfg }
19+
}
20+
}

‎compiler/rustc_expand/src/base.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -947,6 +947,8 @@ pub trait ResolverExpand {
947947
/// HIR proc macros items back to their harness items.
948948
fn declare_proc_macro(&mut self, id: NodeId);
949949

950+
fn append_stripped_cfg_item(&mut self, parent_node: NodeId, name: Ident, cfg: ast::MetaItem);
951+
950952
/// Tools registered with `#![register_tool]` and used by tool attributes and lints.
951953
fn registered_tools(&self) -> &RegisteredTools;
952954
}
@@ -965,7 +967,7 @@ pub trait LintStoreExpand {
965967

966968
type LintStoreExpandDyn<'a> = Option<&'a (dyn LintStoreExpand + 'a)>;
967969

968-
#[derive(Clone, Default)]
970+
#[derive(Debug, Clone, Default)]
969971
pub struct ModuleData {
970972
/// Path to the module starting from the crate name, like `my_crate::foo::bar`.
971973
pub mod_path: Vec<Ident>,

‎compiler/rustc_expand/src/config.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -416,20 +416,28 @@ impl<'a> StripUnconfigured<'a> {
416416

417417
/// Determines if a node with the given attributes should be included in this configuration.
418418
fn in_cfg(&self, attrs: &[Attribute]) -> bool {
419-
attrs.iter().all(|attr| !is_cfg(attr) || self.cfg_true(attr))
419+
attrs.iter().all(|attr| !is_cfg(attr) || self.cfg_true(attr).0)
420420
}
421421

422-
pub(crate) fn cfg_true(&self, attr: &Attribute) -> bool {
422+
pub(crate) fn cfg_true(&self, attr: &Attribute) -> (bool, Option<MetaItem>) {
423423
let meta_item = match validate_attr::parse_meta(&self.sess.parse_sess, attr) {
424424
Ok(meta_item) => meta_item,
425425
Err(mut err) => {
426426
err.emit();
427-
return true;
427+
return (true, None);
428428
}
429429
};
430-
parse_cfg(&meta_item, &self.sess).map_or(true, |meta_item| {
431-
attr::cfg_matches(&meta_item, &self.sess.parse_sess, self.lint_node_id, self.features)
432-
})
430+
(
431+
parse_cfg(&meta_item, &self.sess).map_or(true, |meta_item| {
432+
attr::cfg_matches(
433+
&meta_item,
434+
&self.sess.parse_sess,
435+
self.lint_node_id,
436+
self.features,
437+
)
438+
}),
439+
Some(meta_item),
440+
)
433441
}
434442

435443
/// If attributes are not allowed on expressions, emit an error for `attr`

‎compiler/rustc_expand/src/expand.rs

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,6 +1042,12 @@ trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized {
10421042
fn expand_cfg_false(&mut self, collector: &mut InvocationCollector<'_, '_>, span: Span) {
10431043
collector.cx.emit_err(RemoveNodeNotSupported { span, descr: Self::descr() });
10441044
}
1045+
1046+
/// All of the names (items) declared by this node.
1047+
/// This is an approximation and should only be used for diagnostics.
1048+
fn declared_names(&self) -> Vec<Ident> {
1049+
vec![]
1050+
}
10451051
}
10461052

10471053
impl InvocationCollectorNode for P<ast::Item> {
@@ -1148,6 +1154,27 @@ impl InvocationCollectorNode for P<ast::Item> {
11481154
collector.cx.current_expansion.module = orig_module;
11491155
res
11501156
}
1157+
fn declared_names(&self) -> Vec<Ident> {
1158+
if let ItemKind::Use(ut) = &self.kind {
1159+
fn collect_use_tree_leaves(ut: &ast::UseTree, idents: &mut Vec<Ident>) {
1160+
match &ut.kind {
1161+
ast::UseTreeKind::Glob => {}
1162+
ast::UseTreeKind::Simple(_) => idents.push(ut.ident()),
1163+
ast::UseTreeKind::Nested(nested) => {
1164+
for (ut, _) in nested {
1165+
collect_use_tree_leaves(&ut, idents);
1166+
}
1167+
}
1168+
}
1169+
}
1170+
1171+
let mut idents = Vec::new();
1172+
collect_use_tree_leaves(&ut, &mut idents);
1173+
return idents;
1174+
}
1175+
1176+
vec![self.ident]
1177+
}
11511178
}
11521179

11531180
struct TraitItemTag;
@@ -1685,16 +1712,17 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
16851712
node: &mut impl HasAttrs,
16861713
attr: ast::Attribute,
16871714
pos: usize,
1688-
) -> bool {
1689-
let res = self.cfg().cfg_true(&attr);
1715+
) -> (bool, Option<ast::MetaItem>) {
1716+
let (res, meta_item) = self.cfg().cfg_true(&attr);
16901717
if res {
16911718
// FIXME: `cfg(TRUE)` attributes do not currently remove themselves during expansion,
16921719
// and some tools like rustdoc and clippy rely on that. Find a way to remove them
16931720
// while keeping the tools working.
16941721
self.cx.expanded_inert_attrs.mark(&attr);
16951722
node.visit_attrs(|attrs| attrs.insert(pos, attr));
16961723
}
1697-
res
1724+
1725+
(res, meta_item)
16981726
}
16991727

17001728
fn expand_cfg_attr(&self, node: &mut impl HasAttrs, attr: &ast::Attribute, pos: usize) {
@@ -1715,9 +1743,20 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
17151743
return match self.take_first_attr(&mut node) {
17161744
Some((attr, pos, derives)) => match attr.name_or_empty() {
17171745
sym::cfg => {
1718-
if self.expand_cfg_true(&mut node, attr, pos) {
1746+
let (res, meta_item) = self.expand_cfg_true(&mut node, attr, pos);
1747+
if res {
17191748
continue;
17201749
}
1750+
1751+
if let Some(meta_item) = meta_item {
1752+
for name in node.declared_names() {
1753+
self.cx.resolver.append_stripped_cfg_item(
1754+
self.cx.current_expansion.lint_node_id,
1755+
name,
1756+
meta_item.clone(),
1757+
)
1758+
}
1759+
}
17211760
Default::default()
17221761
}
17231762
sym::cfg_attr => {
@@ -1761,7 +1800,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
17611800
Some((attr, pos, derives)) => match attr.name_or_empty() {
17621801
sym::cfg => {
17631802
let span = attr.span;
1764-
if self.expand_cfg_true(node, attr, pos) {
1803+
if self.expand_cfg_true(node, attr, pos).0 {
17651804
continue;
17661805
}
17671806

‎compiler/rustc_metadata/src/rmeta/decoder.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -995,6 +995,15 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
995995
)
996996
}
997997

998+
fn get_stripped_cfg_items(self, cnum: CrateNum, tcx: TyCtxt<'tcx>) -> &'tcx [StrippedCfgItem] {
999+
let item_names = self
1000+
.root
1001+
.stripped_cfg_items
1002+
.decode((self, tcx))
1003+
.map(|item| item.map_mod_id(|index| DefId { krate: cnum, index }));
1004+
tcx.arena.alloc_from_iter(item_names)
1005+
}
1006+
9981007
/// Iterates over the diagnostic items in the given crate.
9991008
fn get_diagnostic_items(self) -> DiagnosticItems {
10001009
let mut id_to_name = FxHashMap::default();

‎compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,7 @@ provide! { tcx, def_id, other, cdata,
345345
stability_implications => {
346346
cdata.get_stability_implications(tcx).iter().copied().collect()
347347
}
348+
stripped_cfg_items => { cdata.get_stripped_cfg_items(cdata.cnum, tcx) }
348349
is_intrinsic => { cdata.get_is_intrinsic(def_id.index) }
349350
defined_lang_items => { cdata.get_lang_items(tcx) }
350351
diagnostic_items => { cdata.get_diagnostic_items() }

‎compiler/rustc_metadata/src/rmeta/encoder.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::rmeta::def_path_hash_map::DefPathHashMapRef;
33
use crate::rmeta::table::TableBuilder;
44
use crate::rmeta::*;
55

6+
use rustc_ast::expand::StrippedCfgItem;
67
use rustc_ast::Attribute;
78
use rustc_data_structures::fingerprint::Fingerprint;
89
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
@@ -584,6 +585,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
584585
(self.encode_lang_items(), self.encode_lang_items_missing())
585586
});
586587

588+
let stripped_cfg_items = stat!("stripped-cfg-items", || self.encode_stripped_cfg_items());
589+
587590
let diagnostic_items = stat!("diagnostic-items", || self.encode_diagnostic_items());
588591

589592
let native_libraries = stat!("native-libs", || self.encode_native_libraries());
@@ -694,6 +697,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
694697
lang_items,
695698
diagnostic_items,
696699
lang_items_missing,
700+
stripped_cfg_items,
697701
native_libraries,
698702
foreign_modules,
699703
source_map,
@@ -1940,6 +1944,15 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
19401944
self.lazy_array(&tcx.lang_items().missing)
19411945
}
19421946

1947+
fn encode_stripped_cfg_items(&mut self) -> LazyArray<StrippedCfgItem<DefIndex>> {
1948+
self.lazy_array(
1949+
self.tcx
1950+
.stripped_cfg_items(LOCAL_CRATE)
1951+
.into_iter()
1952+
.map(|item| item.clone().map_mod_id(|def_id| def_id.index)),
1953+
)
1954+
}
1955+
19431956
fn encode_traits(&mut self) -> LazyArray<DefIndex> {
19441957
empty_proc_macro!(self);
19451958
self.lazy_array(self.tcx.traits(LOCAL_CRATE).iter().map(|def_id| def_id.index))

‎compiler/rustc_metadata/src/rmeta/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
66
use table::TableBuilder;
77

88
use rustc_ast as ast;
9+
use rustc_ast::expand::StrippedCfgItem;
910
use rustc_attr as attr;
1011
use rustc_data_structures::svh::Svh;
1112
use rustc_hir as hir;
@@ -256,6 +257,7 @@ pub(crate) struct CrateRoot {
256257
stability_implications: LazyArray<(Symbol, Symbol)>,
257258
lang_items: LazyArray<(DefIndex, LangItem)>,
258259
lang_items_missing: LazyArray<LangItem>,
260+
stripped_cfg_items: LazyArray<StrippedCfgItem<DefIndex>>,
259261
diagnostic_items: LazyArray<(Symbol, DefIndex)>,
260262
native_libraries: LazyArray<NativeLib>,
261263
foreign_modules: LazyArray<ForeignModule>,

‎compiler/rustc_middle/src/arena.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ macro_rules! arena_types {
124124
[] predefined_opaques_in_body: rustc_middle::traits::solve::PredefinedOpaquesData<'tcx>,
125125
[decode] doc_link_resolutions: rustc_hir::def::DocLinkResMap,
126126
[] closure_kind_origin: (rustc_span::Span, rustc_middle::hir::place::Place<'tcx>),
127+
[] stripped_cfg_items: rustc_ast::expand::StrippedCfgItem,
127128
[] mod_child: rustc_middle::metadata::ModChild,
128129
]);
129130
)

‎compiler/rustc_middle/src/query/mod.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ use crate::ty::{
5454
};
5555
use rustc_arena::TypedArena;
5656
use rustc_ast as ast;
57-
use rustc_ast::expand::allocator::AllocatorKind;
57+
use rustc_ast::expand::{allocator::AllocatorKind, StrippedCfgItem};
5858
use rustc_attr as attr;
5959
use rustc_data_structures::fingerprint::Fingerprint;
6060
use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
@@ -2173,6 +2173,15 @@ rustc_queries! {
21732173
query check_tys_might_be_eq(arg: Canonical<'tcx, (ty::ParamEnv<'tcx>, Ty<'tcx>, Ty<'tcx>)>) -> Result<(), NoSolution> {
21742174
desc { "check whether two const param are definitely not equal to eachother"}
21752175
}
2176+
2177+
/// Get all item paths that were stripped by a `#[cfg]` in a particular crate.
2178+
/// Should not be called for the local crate before the resolver outputs are created, as it
2179+
/// is only fed there.
2180+
query stripped_cfg_items(cnum: CrateNum) -> &'tcx [StrippedCfgItem] {
2181+
feedable
2182+
desc { "getting cfg-ed out item names" }
2183+
separate_provide_extern
2184+
}
21762185
}
21772186

21782187
rustc_query_append! { define_callbacks! }

‎compiler/rustc_middle/src/ty/parameterized.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ trivially_parameterized_over_tcx! {
7373
ty::fast_reject::SimplifiedType,
7474
rustc_ast::Attribute,
7575
rustc_ast::DelimArgs,
76+
rustc_ast::expand::StrippedCfgItem<rustc_hir::def_id::DefIndex>,
7677
rustc_attr::ConstStability,
7778
rustc_attr::DefaultBodyStability,
7879
rustc_attr::Deprecation,

‎compiler/rustc_resolve/src/diagnostics.rs

Lines changed: 61 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
use std::ptr;
22

3+
use rustc_ast::expand::StrippedCfgItem;
34
use rustc_ast::ptr::P;
45
use rustc_ast::visit::{self, Visitor};
56
use rustc_ast::{self as ast, Crate, ItemKind, ModKind, NodeId, Path, CRATE_NODE_ID};
7+
use rustc_ast::{MetaItemKind, NestedMetaItem};
68
use rustc_ast_pretty::pprust;
79
use rustc_data_structures::fx::FxHashSet;
810
use rustc_errors::{
@@ -776,7 +778,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
776778
.tcx
777779
.sess
778780
.create_err(errs::SelfImportOnlyInImportListWithNonEmptyPrefix { span }),
779-
ResolutionError::FailedToResolve { label, suggestion } => {
781+
ResolutionError::FailedToResolve { last_segment, label, suggestion, module } => {
780782
let mut err =
781783
struct_span_err!(self.tcx.sess, span, E0433, "failed to resolve: {}", &label);
782784
err.span_label(span, label);
@@ -789,6 +791,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
789791
err.multipart_suggestion(msg, suggestions, applicability);
790792
}
791793

794+
if let Some(ModuleOrUniformRoot::Module(module)) = module
795+
&& let Some(module) = module.opt_def_id()
796+
&& let Some(last_segment) = last_segment
797+
{
798+
self.find_cfg_stripped(&mut err, &last_segment, module);
799+
}
800+
792801
err
793802
}
794803
ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => {
@@ -971,9 +980,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
971980
VisResolutionError::AncestorOnly(span) => {
972981
self.tcx.sess.create_err(errs::AncestorOnly(span))
973982
}
974-
VisResolutionError::FailedToResolve(span, label, suggestion) => {
975-
self.into_struct_error(span, ResolutionError::FailedToResolve { label, suggestion })
976-
}
983+
VisResolutionError::FailedToResolve(span, label, suggestion) => self.into_struct_error(
984+
span,
985+
ResolutionError::FailedToResolve {
986+
last_segment: None,
987+
label,
988+
suggestion,
989+
module: None,
990+
},
991+
),
977992
VisResolutionError::ExpectedFound(span, path_str, res) => {
978993
self.tcx.sess.create_err(errs::ExpectedFound { span, res, path_str })
979994
}
@@ -1721,10 +1736,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
17211736
ribs: Option<&PerNS<Vec<Rib<'a>>>>,
17221737
ignore_binding: Option<&'a NameBinding<'a>>,
17231738
module: Option<ModuleOrUniformRoot<'a>>,
1724-
i: usize,
1739+
failed_segment_idx: usize,
17251740
ident: Ident,
17261741
) -> (String, Option<Suggestion>) {
1727-
let is_last = i == path.len() - 1;
1742+
let is_last = failed_segment_idx == path.len() - 1;
17281743
let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS };
17291744
let module_res = match module {
17301745
Some(ModuleOrUniformRoot::Module(module)) => module.res(),
@@ -1758,8 +1773,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
17581773
} else {
17591774
(format!("could not find `{ident}` in the crate root"), None)
17601775
}
1761-
} else if i > 0 {
1762-
let parent = path[i - 1].ident.name;
1776+
} else if failed_segment_idx > 0 {
1777+
let parent = path[failed_segment_idx - 1].ident.name;
17631778
let parent = match parent {
17641779
// ::foo is mounted at the crate root for 2015, and is the extern
17651780
// prelude for 2018+
@@ -2207,6 +2222,44 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
22072222
None
22082223
}
22092224
}
2225+
2226+
/// Finds a cfg-ed out item inside `module` with the matching name.
2227+
pub(crate) fn find_cfg_stripped(
2228+
&mut self,
2229+
err: &mut Diagnostic,
2230+
last_segment: &Symbol,
2231+
module: DefId,
2232+
) {
2233+
let local_items;
2234+
let symbols = if module.is_local() {
2235+
local_items = self
2236+
.stripped_cfg_items
2237+
.iter()
2238+
.filter_map(|item| {
2239+
let parent_module = self.opt_local_def_id(item.parent_module)?.to_def_id();
2240+
Some(StrippedCfgItem { parent_module, name: item.name, cfg: item.cfg.clone() })
2241+
})
2242+
.collect::<Vec<_>>();
2243+
local_items.as_slice()
2244+
} else {
2245+
self.tcx.stripped_cfg_items(module.krate)
2246+
};
2247+
2248+
for &StrippedCfgItem { parent_module, name, ref cfg } in symbols {
2249+
if parent_module != module || name.name != *last_segment {
2250+
continue;
2251+
}
2252+
2253+
err.span_note(name.span, "found an item that was configured out");
2254+
2255+
if let MetaItemKind::List(nested) = &cfg.kind
2256+
&& let NestedMetaItem::MetaItem(meta_item) = &nested[0]
2257+
&& let MetaItemKind::NameValue(feature_name) = &meta_item.kind
2258+
{
2259+
err.note(format!("the item is gated behind the `{}` feature", feature_name.symbol));
2260+
}
2261+
}
2262+
}
22102263
}
22112264

22122265
/// Given a `binding_span` of a binding within a use statement:

‎compiler/rustc_resolve/src/errors.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,7 @@ pub(crate) struct ParamInTyOfConstParam {
330330
pub(crate) param_kind: Option<ParamKindInTyOfConstParam>,
331331
}
332332

333+
#[derive(Debug)]
333334
#[derive(Subdiagnostic)]
334335
pub(crate) enum ParamKindInTyOfConstParam {
335336
#[note(resolve_type_param_in_ty_of_const_param)]
@@ -365,6 +366,7 @@ pub(crate) struct ParamInNonTrivialAnonConst {
365366
#[help(resolve_param_in_non_trivial_anon_const_help)]
366367
pub(crate) struct ParamInNonTrivialAnonConstHelp;
367368

369+
#[derive(Debug)]
368370
#[derive(Subdiagnostic)]
369371
pub(crate) enum ParamKindInNonTrivialAnonConst {
370372
#[note(resolve_type_param_in_non_trivial_anon_const)]
@@ -562,6 +564,7 @@ pub(crate) struct CfgAccessibleUnsure {
562564
pub(crate) span: Span,
563565
}
564566

567+
#[derive(Debug)]
565568
#[derive(Diagnostic)]
566569
#[diag(resolve_param_in_enum_discriminant)]
567570
pub(crate) struct ParamInEnumDiscriminant {
@@ -573,6 +576,7 @@ pub(crate) struct ParamInEnumDiscriminant {
573576
pub(crate) param_kind: ParamKindInEnumDiscriminant,
574577
}
575578

579+
#[derive(Debug)]
576580
#[derive(Subdiagnostic)]
577581
pub(crate) enum ParamKindInEnumDiscriminant {
578582
#[note(resolve_type_param_in_enum_discriminant)]

‎compiler/rustc_resolve/src/ident.rs

Lines changed: 50 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1365,20 +1365,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
13651365
ribs: Option<&PerNS<Vec<Rib<'a>>>>,
13661366
ignore_binding: Option<&'a NameBinding<'a>>,
13671367
) -> PathResult<'a> {
1368-
debug!(
1369-
"resolve_path(path={:?}, opt_ns={:?}, finalize={:?}) path_len: {}",
1370-
path,
1371-
opt_ns,
1372-
finalize,
1373-
path.len()
1374-
);
1375-
13761368
let mut module = None;
13771369
let mut allow_super = true;
13781370
let mut second_binding = None;
13791371

1380-
for (i, &Segment { ident, id, .. }) in path.iter().enumerate() {
1381-
debug!("resolve_path ident {} {:?} {:?}", i, ident, id);
1372+
for (segment_idx, &Segment { ident, id, .. }) in path.iter().enumerate() {
1373+
debug!("resolve_path ident {} {:?} {:?}", segment_idx, ident, id);
13821374
let record_segment_res = |this: &mut Self, res| {
13831375
if finalize.is_some() {
13841376
if let Some(id) = id {
@@ -1390,7 +1382,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
13901382
}
13911383
};
13921384

1393-
let is_last = i + 1 == path.len();
1385+
let is_last = segment_idx + 1 == path.len();
13941386
let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS };
13951387
let name = ident.name;
13961388

@@ -1399,7 +1391,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
13991391
if ns == TypeNS {
14001392
if allow_super && name == kw::Super {
14011393
let mut ctxt = ident.span.ctxt().normalize_to_macros_2_0();
1402-
let self_module = match i {
1394+
let self_module = match segment_idx {
14031395
0 => Some(self.resolve_self(&mut ctxt, parent_scope.module)),
14041396
_ => match module {
14051397
Some(ModuleOrUniformRoot::Module(module)) => Some(module),
@@ -1414,11 +1406,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
14141406
continue;
14151407
}
14161408
}
1417-
return PathResult::failed(ident.span, false, finalize.is_some(), || {
1418-
("there are too many leading `super` keywords".to_string(), None)
1419-
});
1409+
return PathResult::failed(
1410+
ident.span,
1411+
false,
1412+
finalize.is_some(),
1413+
module,
1414+
|| ("there are too many leading `super` keywords".to_string(), None),
1415+
);
14201416
}
1421-
if i == 0 {
1417+
if segment_idx == 0 {
14221418
if name == kw::SelfLower {
14231419
let mut ctxt = ident.span.ctxt().normalize_to_macros_2_0();
14241420
module = Some(ModuleOrUniformRoot::Module(
@@ -1447,14 +1443,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
14471443
}
14481444

14491445
// Report special messages for path segment keywords in wrong positions.
1450-
if ident.is_path_segment_keyword() && i != 0 {
1451-
return PathResult::failed(ident.span, false, finalize.is_some(), || {
1446+
if ident.is_path_segment_keyword() && segment_idx != 0 {
1447+
return PathResult::failed(ident.span, false, finalize.is_some(), module, || {
14521448
let name_str = if name == kw::PathRoot {
14531449
"crate root".to_string()
14541450
} else {
14551451
format!("`{}`", name)
14561452
};
1457-
let label = if i == 1 && path[0].ident.name == kw::PathRoot {
1453+
let label = if segment_idx == 1 && path[0].ident.name == kw::PathRoot {
14581454
format!("global paths cannot start with {}", name_str)
14591455
} else {
14601456
format!("{} in paths can only be used in start position", name_str)
@@ -1519,7 +1515,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
15191515
};
15201516
match binding {
15211517
Ok(binding) => {
1522-
if i == 1 {
1518+
if segment_idx == 1 {
15231519
second_binding = Some(binding);
15241520
}
15251521
let res = binding.res();
@@ -1543,17 +1539,23 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
15431539
record_segment_res(self, res);
15441540
return PathResult::NonModule(PartialRes::with_unresolved_segments(
15451541
res,
1546-
path.len() - i - 1,
1542+
path.len() - segment_idx - 1,
15471543
));
15481544
} else {
1549-
return PathResult::failed(ident.span, is_last, finalize.is_some(), || {
1550-
let label = format!(
1551-
"`{ident}` is {} {}, not a module",
1552-
res.article(),
1553-
res.descr()
1554-
);
1555-
(label, None)
1556-
});
1545+
return PathResult::failed(
1546+
ident.span,
1547+
is_last,
1548+
finalize.is_some(),
1549+
module,
1550+
|| {
1551+
let label = format!(
1552+
"`{ident}` is {} {}, not a module",
1553+
res.article(),
1554+
res.descr()
1555+
);
1556+
(label, None)
1557+
},
1558+
);
15571559
}
15581560
}
15591561
Err(Undetermined) => return PathResult::Indeterminate,
@@ -1562,23 +1564,29 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
15621564
if opt_ns.is_some() && !module.is_normal() {
15631565
return PathResult::NonModule(PartialRes::with_unresolved_segments(
15641566
module.res().unwrap(),
1565-
path.len() - i,
1567+
path.len() - segment_idx,
15661568
));
15671569
}
15681570
}
15691571

1570-
return PathResult::failed(ident.span, is_last, finalize.is_some(), || {
1571-
self.report_path_resolution_error(
1572-
path,
1573-
opt_ns,
1574-
parent_scope,
1575-
ribs,
1576-
ignore_binding,
1577-
module,
1578-
i,
1579-
ident,
1580-
)
1581-
});
1572+
return PathResult::failed(
1573+
ident.span,
1574+
is_last,
1575+
finalize.is_some(),
1576+
module,
1577+
|| {
1578+
self.report_path_resolution_error(
1579+
path,
1580+
opt_ns,
1581+
parent_scope,
1582+
ribs,
1583+
ignore_binding,
1584+
module,
1585+
segment_idx,
1586+
ident,
1587+
)
1588+
},
1589+
);
15821590
}
15831591
}
15841592
}

‎compiler/rustc_resolve/src/imports.rs

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -803,14 +803,34 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
803803

804804
module
805805
}
806-
PathResult::Failed { is_error_from_last_segment: false, span, label, suggestion } => {
806+
PathResult::Failed {
807+
is_error_from_last_segment: false,
808+
span,
809+
label,
810+
suggestion,
811+
module,
812+
} => {
807813
if no_ambiguity {
808814
assert!(import.imported_module.get().is_none());
809-
self.report_error(span, ResolutionError::FailedToResolve { label, suggestion });
815+
self.report_error(
816+
span,
817+
ResolutionError::FailedToResolve {
818+
last_segment: None,
819+
label,
820+
suggestion,
821+
module,
822+
},
823+
);
810824
}
811825
return None;
812826
}
813-
PathResult::Failed { is_error_from_last_segment: true, span, label, suggestion } => {
827+
PathResult::Failed {
828+
is_error_from_last_segment: true,
829+
span,
830+
label,
831+
suggestion,
832+
..
833+
} => {
814834
if no_ambiguity {
815835
assert!(import.imported_module.get().is_none());
816836
let err = match self.make_path_suggestion(

‎compiler/rustc_resolve/src/late.rs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3524,15 +3524,17 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
35243524
None
35253525
};
35263526

3527-
this.r.use_injections.push(UseError {
3527+
let ue = UseError {
35283528
err,
35293529
candidates,
35303530
def_id,
35313531
instead,
35323532
suggestion,
35333533
path: path.into(),
35343534
is_call: source.is_call(),
3535-
});
3535+
};
3536+
3537+
this.r.use_injections.push(ue);
35363538
}
35373539

35383540
PartialRes::new(Res::Err)
@@ -3866,8 +3868,22 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
38663868
PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
38673869
PartialRes::new(module.res().unwrap())
38683870
}
3869-
PathResult::Failed { is_error_from_last_segment: false, span, label, suggestion } => {
3870-
return Err(respan(span, ResolutionError::FailedToResolve { label, suggestion }));
3871+
PathResult::Failed {
3872+
is_error_from_last_segment: false,
3873+
span,
3874+
label,
3875+
suggestion,
3876+
module,
3877+
} => {
3878+
return Err(respan(
3879+
span,
3880+
ResolutionError::FailedToResolve {
3881+
last_segment: None,
3882+
label,
3883+
suggestion,
3884+
module,
3885+
},
3886+
));
38713887
}
38723888
PathResult::Module(..) | PathResult::Failed { .. } => return Ok(None),
38733889
PathResult::Indeterminate => bug!("indeterminate path result in resolve_qpath"),

‎compiler/rustc_resolve/src/late/diagnostics.rs

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ struct BaseError {
149149
span_label: Option<(Span, &'static str)>,
150150
could_be_expr: bool,
151151
suggestion: Option<(Span, &'static str, String)>,
152+
module: Option<DefId>,
152153
}
153154

154155
#[derive(Debug)]
@@ -210,10 +211,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
210211
_ => false,
211212
},
212213
suggestion: None,
214+
module: None,
213215
}
214216
} else {
215217
let item_span = path.last().unwrap().ident.span;
216-
let (mod_prefix, mod_str, suggestion) = if path.len() == 1 {
218+
let (mod_prefix, mod_str, module, suggestion) = if path.len() == 1 {
217219
debug!(?self.diagnostic_metadata.current_impl_items);
218220
debug!(?self.diagnostic_metadata.current_function);
219221
let suggestion = if self.current_trait_ref.is_none()
@@ -247,26 +249,37 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
247249
} else {
248250
None
249251
};
250-
(String::new(), "this scope".to_string(), suggestion)
252+
(String::new(), "this scope".to_string(), None, suggestion)
251253
} else if path.len() == 2 && path[0].ident.name == kw::PathRoot {
252254
if self.r.tcx.sess.edition() > Edition::Edition2015 {
253255
// In edition 2018 onwards, the `::foo` syntax may only pull from the extern prelude
254256
// which overrides all other expectations of item type
255257
expected = "crate";
256-
(String::new(), "the list of imported crates".to_string(), None)
258+
(String::new(), "the list of imported crates".to_string(), None, None)
257259
} else {
258-
(String::new(), "the crate root".to_string(), None)
260+
(
261+
String::new(),
262+
"the crate root".to_string(),
263+
Some(CRATE_DEF_ID.to_def_id()),
264+
None,
265+
)
259266
}
260267
} else if path.len() == 2 && path[0].ident.name == kw::Crate {
261-
(String::new(), "the crate root".to_string(), None)
268+
(String::new(), "the crate root".to_string(), Some(CRATE_DEF_ID.to_def_id()), None)
262269
} else {
263270
let mod_path = &path[..path.len() - 1];
264-
let mod_prefix = match self.resolve_path(mod_path, Some(TypeNS), None) {
271+
let mod_res = self.resolve_path(mod_path, Some(TypeNS), None);
272+
let mod_prefix = match mod_res {
265273
PathResult::Module(ModuleOrUniformRoot::Module(module)) => module.res(),
266274
_ => None,
267-
}
268-
.map_or_else(String::new, |res| format!("{} ", res.descr()));
269-
(mod_prefix, format!("`{}`", Segment::names_to_string(mod_path)), None)
275+
};
276+
277+
let module_did = mod_prefix.as_ref().and_then(Res::mod_def_id);
278+
279+
let mod_prefix =
280+
mod_prefix.map_or_else(String::new, |res| (format!("{} ", res.descr())));
281+
282+
(mod_prefix, format!("`{}`", Segment::names_to_string(mod_path)), module_did, None)
270283
};
271284

272285
let (fallback_label, suggestion) = if path_str == "async"
@@ -300,6 +313,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
300313
span_label: None,
301314
could_be_expr: false,
302315
suggestion,
316+
module,
303317
}
304318
}
305319
}
@@ -315,6 +329,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
315329
) -> (DiagnosticBuilder<'tcx, ErrorGuaranteed>, Vec<ImportSuggestion>) {
316330
debug!(?res, ?source);
317331
let base_error = self.make_base_error(path, span, source, res);
332+
318333
let code = source.error_code(res.is_some());
319334
let mut err = self.r.tcx.sess.struct_span_err_with_code(
320335
base_error.span,
@@ -366,6 +381,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
366381
}
367382
self.err_code_special_cases(&mut err, source, path, span);
368383

384+
if let Some(module) = base_error.module {
385+
self.r.find_cfg_stripped(&mut err, &path.last().unwrap().ident.name, module);
386+
}
387+
369388
(err, candidates)
370389
}
371390

‎compiler/rustc_resolve/src/lib.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use errors::{
2525
ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst, ParamKindInTyOfConstParam,
2626
};
2727
use rustc_arena::{DroplessArena, TypedArena};
28+
use rustc_ast::expand::StrippedCfgItem;
2829
use rustc_ast::node_id::NodeMap;
2930
use rustc_ast::{self as ast, attr, NodeId, CRATE_NODE_ID};
3031
use rustc_ast::{AngleBracketedArg, Crate, Expr, ExprKind, GenericArg, GenericArgs, LitKind, Path};
@@ -171,13 +172,15 @@ enum ImplTraitContext {
171172
Universal(LocalDefId),
172173
}
173174

175+
#[derive(Debug)]
174176
struct BindingError {
175177
name: Symbol,
176178
origin: BTreeSet<Span>,
177179
target: BTreeSet<Span>,
178180
could_be_path: bool,
179181
}
180182

183+
#[derive(Debug)]
181184
enum ResolutionError<'a> {
182185
/// Error E0401: can't use type or const parameters from outer function.
183186
GenericParamsFromOuterFunction(Res, HasGenericParams),
@@ -207,7 +210,12 @@ enum ResolutionError<'a> {
207210
/// Error E0431: `self` import can only appear in an import list with a non-empty prefix.
208211
SelfImportOnlyInImportListWithNonEmptyPrefix,
209212
/// Error E0433: failed to resolve.
210-
FailedToResolve { label: String, suggestion: Option<Suggestion> },
213+
FailedToResolve {
214+
last_segment: Option<Symbol>,
215+
label: String,
216+
suggestion: Option<Suggestion>,
217+
module: Option<ModuleOrUniformRoot<'a>>,
218+
},
211219
/// Error E0434: can't capture dynamic environment in a fn item.
212220
CannotCaptureDynamicEnvironmentInFnItem,
213221
/// Error E0435: attempt to use a non-constant value in a constant.
@@ -402,6 +410,7 @@ enum PathResult<'a> {
402410
label: String,
403411
suggestion: Option<Suggestion>,
404412
is_error_from_last_segment: bool,
413+
module: Option<ModuleOrUniformRoot<'a>>,
405414
},
406415
}
407416

@@ -410,11 +419,12 @@ impl<'a> PathResult<'a> {
410419
span: Span,
411420
is_error_from_last_segment: bool,
412421
finalize: bool,
422+
module: Option<ModuleOrUniformRoot<'a>>,
413423
label_and_suggestion: impl FnOnce() -> (String, Option<Suggestion>),
414424
) -> PathResult<'a> {
415425
let (label, suggestion) =
416426
if finalize { label_and_suggestion() } else { (String::new(), None) };
417-
PathResult::Failed { span, label, suggestion, is_error_from_last_segment }
427+
PathResult::Failed { span, label, suggestion, is_error_from_last_segment, module }
418428
}
419429
}
420430

@@ -685,6 +695,7 @@ struct PrivacyError<'a> {
685695
dedup_span: Span,
686696
}
687697

698+
#[derive(Debug)]
688699
struct UseError<'a> {
689700
err: DiagnosticBuilder<'a, ErrorGuaranteed>,
690701
/// Candidates which user could `use` to access the missing type.
@@ -1059,6 +1070,9 @@ pub struct Resolver<'a, 'tcx> {
10591070
/// Whether lifetime elision was successful.
10601071
lifetime_elision_allowed: FxHashSet<NodeId>,
10611072

1073+
/// Names of items that were stripped out via cfg with their corresponding cfg meta item.
1074+
stripped_cfg_items: Vec<StrippedCfgItem<NodeId>>,
1075+
10621076
effective_visibilities: EffectiveVisibilities,
10631077
doc_link_resolutions: FxHashMap<LocalDefId, DocLinkResMap>,
10641078
doc_link_traits_in_scope: FxHashMap<LocalDefId, Vec<DefId>>,
@@ -1353,6 +1367,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
13531367
proc_macros: Default::default(),
13541368
confused_type_with_std_module: Default::default(),
13551369
lifetime_elision_allowed: Default::default(),
1370+
stripped_cfg_items: Default::default(),
13561371
effective_visibilities: Default::default(),
13571372
doc_link_resolutions: Default::default(),
13581373
doc_link_traits_in_scope: Default::default(),
@@ -1410,6 +1425,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
14101425
let main_def = self.main_def;
14111426
let confused_type_with_std_module = self.confused_type_with_std_module;
14121427
let effective_visibilities = self.effective_visibilities;
1428+
1429+
self.tcx.feed_local_crate().stripped_cfg_items(self.tcx.arena.alloc_from_iter(
1430+
self.stripped_cfg_items.into_iter().filter_map(|item| {
1431+
let parent_module = self.node_id_to_def_id.get(&item.parent_module)?.to_def_id();
1432+
Some(StrippedCfgItem { parent_module, name: item.name, cfg: item.cfg })
1433+
}),
1434+
));
1435+
14131436
let global_ctxt = ResolverGlobalCtxt {
14141437
expn_that_defined,
14151438
visibilities,

‎compiler/rustc_resolve/src/macros.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::Namespace::*;
66
use crate::{BuiltinMacroState, Determinacy};
77
use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet};
88
use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment};
9+
use rustc_ast::expand::StrippedCfgItem;
910
use rustc_ast::{self as ast, attr, Inline, ItemKind, ModKind, NodeId};
1011
use rustc_ast_pretty::pprust;
1112
use rustc_attr::StabilityLevel;
@@ -465,6 +466,10 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
465466
self.proc_macros.push(id)
466467
}
467468

469+
fn append_stripped_cfg_item(&mut self, parent_node: NodeId, name: Ident, cfg: ast::MetaItem) {
470+
self.stripped_cfg_items.push(StrippedCfgItem { parent_module: parent_node, name, cfg });
471+
}
472+
468473
fn registered_tools(&self) -> &RegisteredTools {
469474
&self.registered_tools
470475
}
@@ -721,7 +726,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
721726
}
722727
path_res @ (PathResult::NonModule(..) | PathResult::Failed { .. }) => {
723728
let mut suggestion = None;
724-
let (span, label) = if let PathResult::Failed { span, label, .. } = path_res {
729+
let (span, label, module) = if let PathResult::Failed { span, label, module, .. } = path_res {
725730
// try to suggest if it's not a macro, maybe a function
726731
if let PathResult::NonModule(partial_res) = self.maybe_resolve_path(&path, Some(ValueNS), &parent_scope)
727732
&& partial_res.unresolved_segments() == 0 {
@@ -733,7 +738,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
733738
Applicability::MaybeIncorrect
734739
));
735740
}
736-
(span, label)
741+
(span, label, module)
737742
} else {
738743
(
739744
path_span,
@@ -742,11 +747,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
742747
kind.article(),
743748
kind.descr()
744749
),
750+
None,
745751
)
746752
};
747753
self.report_error(
748754
span,
749-
ResolutionError::FailedToResolve { label, suggestion },
755+
ResolutionError::FailedToResolve { last_segment: path.last().map(|segment| segment.ident.name), label, suggestion, module },
750756
);
751757
}
752758
PathResult::Module(..) | PathResult::Indeterminate => unreachable!(),

‎tests/ui/cfg/auxiliary/cfged_out.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
pub mod inner {
2+
#[cfg(FALSE)]
3+
pub fn uwu() {}
4+
5+
#[cfg(FALSE)]
6+
pub mod doesnt_exist {
7+
pub fn hello() {}
8+
}
9+
10+
pub mod wrong {
11+
#[cfg(feature = "suggesting me fails the test!!")]
12+
pub fn meow() {}
13+
}
14+
15+
pub mod right {
16+
#[cfg(feature = "what-a-cool-feature")]
17+
pub fn meow() {}
18+
}
19+
}
20+
21+
#[cfg(i_dont_exist_and_you_can_do_nothing_about_it)]
22+
pub fn vanished() {}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// aux-build:cfged_out.rs
2+
3+
extern crate cfged_out;
4+
5+
fn main() {
6+
// There is no uwu at this path - no diagnostic.
7+
cfged_out::uwu(); //~ ERROR cannot find function
8+
//~^ NOTE not found in `cfged_out`
9+
10+
// It does exist here - diagnostic.
11+
cfged_out::inner::uwu(); //~ ERROR cannot find function
12+
//~^ NOTE found an item that was configured out
13+
//~| NOTE not found in `cfged_out::inner`
14+
15+
// The module isn't found - we would like to get a diagnostic, but currently don't due to
16+
// the awkward way the resolver diagnostics are currently implemented.
17+
// FIXME(Nilstrieb): Also add a note to the cfg diagnostic here
18+
cfged_out::inner::doesnt_exist::hello(); //~ ERROR failed to resolve
19+
//~^ NOTE could not find `doesnt_exist` in `inner`
20+
21+
// It should find the one in the right module, not the wrong one.
22+
cfged_out::inner::right::meow(); //~ ERROR cannot find function
23+
//~^ NOTE found an item that was configured out
24+
//~| NOTE not found in `cfged_out::inner::right
25+
//~| NOTE the item is gated behind the `what-a-cool-feature` feature
26+
27+
// Exists in the crate root - diagnostic.
28+
cfged_out::vanished(); //~ ERROR cannot find function
29+
//~^ NOTE found an item that was configured out
30+
//~| NOTE not found in `cfged_out`
31+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
error[E0433]: failed to resolve: could not find `doesnt_exist` in `inner`
2+
--> $DIR/diagnostics-cross-crate.rs:18:23
3+
|
4+
LL | cfged_out::inner::doesnt_exist::hello();
5+
| ^^^^^^^^^^^^ could not find `doesnt_exist` in `inner`
6+
7+
error[E0425]: cannot find function `uwu` in crate `cfged_out`
8+
--> $DIR/diagnostics-cross-crate.rs:7:16
9+
|
10+
LL | cfged_out::uwu();
11+
| ^^^ not found in `cfged_out`
12+
13+
error[E0425]: cannot find function `uwu` in module `cfged_out::inner`
14+
--> $DIR/diagnostics-cross-crate.rs:11:23
15+
|
16+
LL | cfged_out::inner::uwu();
17+
| ^^^ not found in `cfged_out::inner`
18+
|
19+
note: found an item that was configured out
20+
--> $DIR/auxiliary/cfged_out.rs:3:12
21+
|
22+
LL | pub fn uwu() {}
23+
| ^^^
24+
25+
error[E0425]: cannot find function `meow` in module `cfged_out::inner::right`
26+
--> $DIR/diagnostics-cross-crate.rs:22:30
27+
|
28+
LL | cfged_out::inner::right::meow();
29+
| ^^^^ not found in `cfged_out::inner::right`
30+
|
31+
note: found an item that was configured out
32+
--> $DIR/auxiliary/cfged_out.rs:17:16
33+
|
34+
LL | pub fn meow() {}
35+
| ^^^^
36+
= note: the item is gated behind the `what-a-cool-feature` feature
37+
38+
error[E0425]: cannot find function `vanished` in crate `cfged_out`
39+
--> $DIR/diagnostics-cross-crate.rs:28:16
40+
|
41+
LL | cfged_out::vanished();
42+
| ^^^^^^^^ not found in `cfged_out`
43+
|
44+
note: found an item that was configured out
45+
--> $DIR/auxiliary/cfged_out.rs:22:8
46+
|
47+
LL | pub fn vanished() {}
48+
| ^^^^^^^^
49+
50+
error: aborting due to 5 previous errors
51+
52+
Some errors have detailed explanations: E0425, E0433.
53+
For more information about an error, try `rustc --explain E0425`.

‎tests/ui/cfg/diagnostics-not-a-def.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
pub mod inner {
2+
pub fn i_am_here() {
3+
#[cfg(feature = "another one that doesn't exist")]
4+
loop {}
5+
}
6+
}
7+
8+
fn main() {
9+
inner::i_am_here();
10+
// ensure that nothing bad happens when we are checking for cfgs
11+
inner::i_am_not(); //~ ERROR cannot find function
12+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0425]: cannot find function `i_am_not` in module `inner`
2+
--> $DIR/diagnostics-not-a-def.rs:11:12
3+
|
4+
LL | inner::i_am_not();
5+
| ^^^^^^^^ not found in `inner`
6+
7+
error: aborting due to previous error
8+
9+
For more information about this error, try `rustc --explain E0425`.

‎tests/ui/cfg/diagnostics-reexport.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
pub mod inner {
2+
#[cfg(FALSE)]
3+
mod gone {
4+
pub fn uwu() {}
5+
}
6+
7+
#[cfg(FALSE)]
8+
pub use super::uwu;
9+
//~^ NOTE found an item that was configured out
10+
}
11+
12+
fn main() {
13+
// There is no uwu at this path - no diagnostic.
14+
inner::uwu(); //~ ERROR cannot find function
15+
//~^ NOTE not found in `inner`
16+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0425]: cannot find function `uwu` in module `inner`
2+
--> $DIR/diagnostics-reexport.rs:14:12
3+
|
4+
LL | inner::uwu();
5+
| ^^^ not found in `inner`
6+
|
7+
note: found an item that was configured out
8+
--> $DIR/diagnostics-reexport.rs:8:20
9+
|
10+
LL | pub use super::uwu;
11+
| ^^^
12+
13+
error: aborting due to previous error
14+
15+
For more information about this error, try `rustc --explain E0425`.
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
pub mod inner {
2+
#[cfg(FALSE)]
3+
pub fn uwu() {}
4+
//~^ NOTE found an item that was configured out
5+
6+
#[cfg(FALSE)]
7+
pub mod doesnt_exist {
8+
pub fn hello() {}
9+
}
10+
11+
pub mod wrong {
12+
#[cfg(feature = "suggesting me fails the test!!")]
13+
pub fn meow() {}
14+
}
15+
16+
pub mod right {
17+
#[cfg(feature = "what-a-cool-feature")]
18+
pub fn meow() {}
19+
//~^ NOTE found an item that was configured out
20+
}
21+
}
22+
23+
#[cfg(i_dont_exist_and_you_can_do_nothing_about_it)]
24+
pub fn vanished() {}
25+
26+
fn main() {
27+
// There is no uwu at this path - no diagnostic.
28+
uwu(); //~ ERROR cannot find function
29+
//~^ NOTE not found in this scope
30+
31+
// It does exist here - diagnostic.
32+
inner::uwu(); //~ ERROR cannot find function
33+
//~| NOTE not found in `inner`
34+
35+
// The module isn't found - we would like to get a diagnostic, but currently don't due to
36+
// the awkward way the resolver diagnostics are currently implemented.
37+
// FIXME(Nilstrieb): Also add a note to the cfg diagnostic here
38+
inner::doesnt_exist::hello(); //~ ERROR failed to resolve
39+
//~| NOTE could not find `doesnt_exist` in `inner`
40+
41+
// It should find the one in the right module, not the wrong one.
42+
inner::right::meow(); //~ ERROR cannot find function
43+
//~| NOTE not found in `inner::right
44+
//~| NOTE the item is gated behind the `what-a-cool-feature` feature
45+
46+
// Exists in the crate root - we would generally want a diagnostic,
47+
// but currently don't have one.
48+
// Not that it matters much though, this is highly unlikely to confuse anyone.
49+
vanished(); //~ ERROR cannot find function
50+
//~^ NOTE not found in this scope
51+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
error[E0433]: failed to resolve: could not find `doesnt_exist` in `inner`
2+
--> $DIR/diagnostics-same-crate.rs:38:12
3+
|
4+
LL | inner::doesnt_exist::hello();
5+
| ^^^^^^^^^^^^ could not find `doesnt_exist` in `inner`
6+
7+
error[E0425]: cannot find function `uwu` in module `inner`
8+
--> $DIR/diagnostics-same-crate.rs:32:12
9+
|
10+
LL | inner::uwu();
11+
| ^^^ not found in `inner`
12+
|
13+
note: found an item that was configured out
14+
--> $DIR/diagnostics-same-crate.rs:3:12
15+
|
16+
LL | pub fn uwu() {}
17+
| ^^^
18+
19+
error[E0425]: cannot find function `meow` in module `inner::right`
20+
--> $DIR/diagnostics-same-crate.rs:42:19
21+
|
22+
LL | inner::right::meow();
23+
| ^^^^ not found in `inner::right`
24+
|
25+
note: found an item that was configured out
26+
--> $DIR/diagnostics-same-crate.rs:18:16
27+
|
28+
LL | pub fn meow() {}
29+
| ^^^^
30+
= note: the item is gated behind the `what-a-cool-feature` feature
31+
32+
error[E0425]: cannot find function `uwu` in this scope
33+
--> $DIR/diagnostics-same-crate.rs:28:5
34+
|
35+
LL | uwu();
36+
| ^^^ not found in this scope
37+
38+
error[E0425]: cannot find function `vanished` in this scope
39+
--> $DIR/diagnostics-same-crate.rs:49:5
40+
|
41+
LL | vanished();
42+
| ^^^^^^^^ not found in this scope
43+
44+
error: aborting due to 5 previous errors
45+
46+
Some errors have detailed explanations: E0425, E0433.
47+
For more information about an error, try `rustc --explain E0425`.

‎tests/ui/macros/builtin-std-paths-fail.stderr

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ error[E0433]: failed to resolve: could not find `test` in `std`
9393
|
9494
LL | #[std::test]
9595
| ^^^^ could not find `test` in `std`
96+
|
97+
note: found an item that was configured out
98+
--> $SRC_DIR/std/src/lib.rs:LL:COL
9699

97100
error: aborting due to 16 previous errors
98101

‎tests/ui/macros/macro-outer-attributes.stderr

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ error[E0425]: cannot find function `bar` in module `a`
44
LL | a::bar();
55
| ^^^ not found in `a`
66
|
7+
note: found an item that was configured out
8+
--> $DIR/macro-outer-attributes.rs:9:14
9+
|
10+
LL | pub fn bar() { });
11+
| ^^^
712
help: consider importing this function
813
|
914
LL + use b::bar;

0 commit comments

Comments
 (0)
Please sign in to comment.