From eb20cada00d0623dc0fd367e24f29384d29c472a Mon Sep 17 00:00:00 2001 From: Sasha Pourcelot Date: Mon, 30 Mar 2026 14:07:12 +0000 Subject: [PATCH] make sure the right target is passed to `#[cfg()]` when it is parsed --- compiler/rustc_expand/src/expand.rs | 90 ++++++++++++++++++- tests/ui/cfg/suggest-any-or-all.stderr | 6 +- .../cfg-attr-syntax-validation.stderr | 6 +- 3 files changed, 93 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index c8ef295b2a79..98e097ac4002 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1306,6 +1306,8 @@ fn expand_cfg_false( fn declared_idents(&self) -> Vec { vec![] } + + fn as_target(&self) -> Target; } impl InvocationCollectorNode for Box { @@ -1457,6 +1459,10 @@ fn collect_use_tree_leaves(ut: &ast::UseTree, idents: &mut Vec) { self.kind.ident().into_iter().collect() } } + + fn as_target(&self) -> Target { + Target::from_ast_item(&*self) + } } struct TraitItemTag; @@ -1498,6 +1504,9 @@ fn from_item(item: ast::Item) -> Self { fn flatten_outputs(items: impl Iterator) -> Self::OutputTy { items.flatten().collect() } + fn as_target(&self) -> Target { + Target::from_assoc_item_kind(&self.wrapped.kind, AssocCtxt::Trait) + } } struct ImplItemTag; @@ -1539,6 +1548,9 @@ fn from_item(item: ast::Item) -> Self { fn flatten_outputs(items: impl Iterator) -> Self::OutputTy { items.flatten().collect() } + fn as_target(&self) -> Target { + Target::from_assoc_item_kind(&self.wrapped.kind, AssocCtxt::Impl { of_trait: false }) + } } struct TraitImplItemTag; @@ -1580,6 +1592,9 @@ fn from_item(item: ast::Item) -> Self { fn flatten_outputs(items: impl Iterator) -> Self::OutputTy { items.flatten().collect() } + fn as_target(&self) -> Target { + Target::from_assoc_item_kind(&self.wrapped.kind, AssocCtxt::Impl { of_trait: true }) + } } impl InvocationCollectorNode for Box { @@ -1602,6 +1617,14 @@ fn take_mac_call(self) -> (Box, ast::AttrVec, AddSemicolon) { _ => unreachable!(), } } + fn as_target(&self) -> Target { + match &self.kind { + ForeignItemKind::Static(_) => Target::ForeignStatic, + ForeignItemKind::Fn(_) => Target::ForeignFn, + ForeignItemKind::TyAlias(_) => Target::ForeignTy, + ForeignItemKind::MacCall(_) => Target::MacroCall, + } + } } impl InvocationCollectorNode for ast::Variant { @@ -1615,6 +1638,9 @@ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { walk_flat_map_variant(collector, self) } + fn as_target(&self) -> Target { + Target::Variant + } } impl InvocationCollectorNode for ast::WherePredicate { @@ -1628,6 +1654,9 @@ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { walk_flat_map_where_predicate(collector, self) } + fn as_target(&self) -> Target { + Target::WherePredicate + } } impl InvocationCollectorNode for ast::FieldDef { @@ -1641,6 +1670,9 @@ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { walk_flat_map_field_def(collector, self) } + fn as_target(&self) -> Target { + Target::Field + } } impl InvocationCollectorNode for ast::PatField { @@ -1654,6 +1686,9 @@ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { walk_flat_map_pat_field(collector, self) } + fn as_target(&self) -> Target { + Target::PatField + } } impl InvocationCollectorNode for ast::ExprField { @@ -1667,6 +1702,9 @@ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { walk_flat_map_expr_field(collector, self) } + fn as_target(&self) -> Target { + Target::ExprField + } } impl InvocationCollectorNode for ast::Param { @@ -1680,6 +1718,9 @@ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { walk_flat_map_param(collector, self) } + fn as_target(&self) -> Target { + Target::Param + } } impl InvocationCollectorNode for ast::GenericParam { @@ -1693,6 +1734,25 @@ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { walk_flat_map_generic_param(collector, self) } + fn as_target(&self) -> Target { + let mut has_default = false; + Target::GenericParam { + kind: match &self.kind { + rustc_ast::GenericParamKind::Lifetime => { + rustc_hir::target::GenericParamKind::Lifetime + } + rustc_ast::GenericParamKind::Type { default } => { + has_default = default.is_some(); + rustc_hir::target::GenericParamKind::Type + } + rustc_ast::GenericParamKind::Const { default, .. } => { + has_default = default.is_some(); + rustc_hir::target::GenericParamKind::Const + } + }, + has_default, + } + } } impl InvocationCollectorNode for ast::Arm { @@ -1706,6 +1766,9 @@ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { walk_flat_map_arm(collector, self) } + fn as_target(&self) -> Target { + Target::Arm + } } impl InvocationCollectorNode for ast::Stmt { @@ -1779,6 +1842,9 @@ fn post_flat_map_node_collect_bang(stmts: &mut Self::OutputTy, add_semicolon: Ad } } } + fn as_target(&self) -> Target { + Target::Statement + } } impl InvocationCollectorNode for ast::Crate { @@ -1805,6 +1871,9 @@ fn expand_cfg_false( // Standard prelude imports are left in the crate for backward compatibility. self.items.truncate(collector.cx.num_standard_library_imports); } + fn as_target(&self) -> Target { + Target::Crate + } } impl InvocationCollectorNode for ast::Ty { @@ -1838,6 +1907,10 @@ fn take_mac_call(self) -> (Box, ast::AttrVec, AddSemicolon) { _ => unreachable!(), } } + fn as_target(&self) -> Target { + // This is only used for attribute parsing, which are not allowed on types. + unreachable!() + } } impl InvocationCollectorNode for ast::Pat { @@ -1861,6 +1934,9 @@ fn take_mac_call(self) -> (Box, ast::AttrVec, AddSemicolon) { _ => unreachable!(), } } + fn as_target(&self) -> Target { + todo!(); + } } impl InvocationCollectorNode for ast::Expr { @@ -1887,6 +1963,9 @@ fn take_mac_call(self) -> (Box, ast::AttrVec, AddSemicolon) { _ => unreachable!(), } } + fn as_target(&self) -> Target { + Target::Expression + } } struct OptExprTag; @@ -1916,6 +1995,9 @@ fn take_mac_call(self) -> (Box, ast::AttrVec, AddSemicolon) { fn pre_flat_map_node_collect_attr(cfg: &StripUnconfigured<'_>, attr: &ast::Attribute) { cfg.maybe_emit_expr_attr_err(attr); } + fn as_target(&self) -> Target { + Target::Expression + } } /// This struct is a hack to workaround unstable of `stmt_expr_attributes`. @@ -1947,6 +2029,9 @@ fn take_mac_call(self) -> (Box, ast::AttrVec, AddSemicolon) { _ => unreachable!(), } } + fn as_target(&self) -> Target { + Target::Expression + } } fn build_single_delegations<'a, Node: InvocationCollectorNode>( @@ -2210,7 +2295,7 @@ fn check_attributes(&self, attrs: &[ast::Attribute], call: &ast::MacCall) { fn expand_cfg_true( &mut self, - node: &mut (impl HasAttrs + HasNodeId), + node: &mut impl InvocationCollectorNode, attr: ast::Attribute, pos: usize, ) -> EvalConfigResult { @@ -2219,8 +2304,7 @@ fn expand_cfg_true( &attr, attr.span, self.cfg().lint_node_id, - // Target doesn't matter for `cfg` parsing. - Target::Crate, + node.as_target(), self.cfg().features, ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed }, parse_cfg, diff --git a/tests/ui/cfg/suggest-any-or-all.stderr b/tests/ui/cfg/suggest-any-or-all.stderr index 67ff6f178d12..3d3bc7e05164 100644 --- a/tests/ui/cfg/suggest-any-or-all.stderr +++ b/tests/ui/cfg/suggest-any-or-all.stderr @@ -7,12 +7,12 @@ LL | #[cfg(foo, bar)] | expected a single argument here | = note: for more information, visit -help: if the crate should be enabled when all these predicates are, wrap them in `all` +help: if the function should be enabled when all these predicates are, wrap them in `all` | LL - #[cfg(foo, bar)] LL + #[cfg(all(foo, bar))] | -help: alternately, if the crate should be enabled when any of these predicates are, wrap them in `any` +help: alternately, if the function should be enabled when any of these predicates are, wrap them in `any` | LL - #[cfg(foo, bar)] LL + #[cfg(any(foo, bar))] @@ -27,7 +27,7 @@ LL | #[cfg()] | expected a single argument here | = note: for more information, visit -help: if the crate should be disabled, use `#[cfg(false)]` +help: if the struct should be disabled, use `#[cfg(false)]` | LL | #[cfg(false)] | +++++ diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr index ddb5cd84097f..6187c36b0d6c 100644 --- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr +++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr @@ -29,7 +29,7 @@ LL | #[cfg()] | expected a single argument here | = note: for more information, visit -help: if the crate should be disabled, use `#[cfg(false)]` +help: if the struct should be disabled, use `#[cfg(false)]` | LL | #[cfg(false)] | +++++ @@ -43,12 +43,12 @@ LL | #[cfg(a, b)] | expected a single argument here | = note: for more information, visit -help: if the crate should be enabled when all these predicates are, wrap them in `all` +help: if the struct should be enabled when all these predicates are, wrap them in `all` | LL - #[cfg(a, b)] LL + #[cfg(all(a, b))] | -help: alternately, if the crate should be enabled when any of these predicates are, wrap them in `any` +help: alternately, if the struct should be enabled when any of these predicates are, wrap them in `any` | LL - #[cfg(a, b)] LL + #[cfg(any(a, b))]