From 832b092a6ab662d37052ef282623cd0637f3f329 Mon Sep 17 00:00:00 2001 From: Usman Akinyemi Date: Sun, 19 Jul 2026 03:44:53 +0530 Subject: [PATCH] Reject cfg on expressions that cannot be safely removed Previously, expressions behind stmt_expr_attributes were only rejected when the cfg condition evaluated to false. If the condition was true, the code compiled successfully. This meant code like an attributed binary operand could compile on one platform but fail on another, even though removing the operand would leave an invalid expression. This change always rejects cfg in expression positions where removing the expression would produce invalid code. Expression positions where removal is safe continue to work as before. Signed-off-by: Usman Akinyemi --- compiler/rustc_expand/src/expand.rs | 7 ++ .../cfg-non-opt-expr.rs | 27 +++++++ .../cfg-non-opt-expr.stderr | 70 +++++++++++++++++-- 3 files changed, 100 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 045233c0c4d21..112eb328847ee 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -2427,6 +2427,13 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { Some(sym::cfg) => { let span = attr.span; if self.expand_cfg_true(node, attr, pos).as_bool() { + match Node::KIND { + AstFragmentKind::Expr | AstFragmentKind::MethodReceiverExpr => { + self.cx.dcx().emit_err(RemoveExprNotSupported { span }); + } + AstFragmentKind::Crate => {} + _ => unreachable!(), + } continue; } diff --git a/tests/ui/conditional-compilation/cfg-non-opt-expr.rs b/tests/ui/conditional-compilation/cfg-non-opt-expr.rs index cae07ae0ced10..0ebf625c8f29a 100644 --- a/tests/ui/conditional-compilation/cfg-non-opt-expr.rs +++ b/tests/ui/conditional-compilation/cfg-non-opt-expr.rs @@ -1,11 +1,38 @@ #![feature(stmt_expr_attributes)] #![feature(custom_test_frameworks)] +#[derive(Clone)] +enum E { + V1 = #[cfg(true)] 1, + //~^ ERROR removing an expression is not supported in this position + //~| ERROR removing an expression is not supported in this position + V2 = #[cfg_attr(true, cfg(true))] 2, + //~^ ERROR removing an expression is not supported in this position +} + +macro_rules! mac { + ($expr:expr) => { $expr.clone() } +} + fn main() { + let _ = 1 + #[cfg(unix)] 2; + //~^ ERROR removing an expression is not supported in this position + let _ = 1 + #[cfg(windows)] 2; + //~^ ERROR removing an expression is not supported in this position + let _ = 1 + #[cfg(all())] 2; + //~^ ERROR removing an expression is not supported in this position let _ = #[cfg(false)] (); //~^ ERROR removing an expression is not supported in this position let _ = 1 + 2 + #[cfg(false)] 3; //~^ ERROR removing an expression is not supported in this position let _ = [1, 2, 3][#[cfg(false)] 1]; //~^ ERROR removing an expression is not supported in this position + let _ = mac!(#[cfg(true)] 10); + //~^ ERROR removing an expression is not supported in this position + let _ = #[cfg(true)] (); + //~^ ERROR removing an expression is not supported in this position + let _ = 1 + 2 + #[cfg(true)] 3; + //~^ ERROR removing an expression is not supported in this position + let _ = [1, 2, 3][#[cfg(true)] 1]; + //~^ ERROR removing an expression is not supported in this position } diff --git a/tests/ui/conditional-compilation/cfg-non-opt-expr.stderr b/tests/ui/conditional-compilation/cfg-non-opt-expr.stderr index bd1bfeb06c7ad..5e244687f75d1 100644 --- a/tests/ui/conditional-compilation/cfg-non-opt-expr.stderr +++ b/tests/ui/conditional-compilation/cfg-non-opt-expr.stderr @@ -1,20 +1,82 @@ error: removing an expression is not supported in this position - --> $DIR/cfg-non-opt-expr.rs:5:13 + --> $DIR/cfg-non-opt-expr.rs:18:17 + | +LL | let _ = 1 + #[cfg(unix)] 2; + | ^^^^^^^^^^^^ + +error: removing an expression is not supported in this position + --> $DIR/cfg-non-opt-expr.rs:20:17 + | +LL | let _ = 1 + #[cfg(windows)] 2; + | ^^^^^^^^^^^^^^^ + +error: removing an expression is not supported in this position + --> $DIR/cfg-non-opt-expr.rs:22:17 + | +LL | let _ = 1 + #[cfg(all())] 2; + | ^^^^^^^^^^^^^ + +error: removing an expression is not supported in this position + --> $DIR/cfg-non-opt-expr.rs:24:13 | LL | let _ = #[cfg(false)] (); | ^^^^^^^^^^^^^ error: removing an expression is not supported in this position - --> $DIR/cfg-non-opt-expr.rs:7:21 + --> $DIR/cfg-non-opt-expr.rs:26:21 | LL | let _ = 1 + 2 + #[cfg(false)] 3; | ^^^^^^^^^^^^^ error: removing an expression is not supported in this position - --> $DIR/cfg-non-opt-expr.rs:9:23 + --> $DIR/cfg-non-opt-expr.rs:28:23 | LL | let _ = [1, 2, 3][#[cfg(false)] 1]; | ^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: removing an expression is not supported in this position + --> $DIR/cfg-non-opt-expr.rs:32:13 + | +LL | let _ = #[cfg(true)] (); + | ^^^^^^^^^^^^ + +error: removing an expression is not supported in this position + --> $DIR/cfg-non-opt-expr.rs:34:21 + | +LL | let _ = 1 + 2 + #[cfg(true)] 3; + | ^^^^^^^^^^^^ + +error: removing an expression is not supported in this position + --> $DIR/cfg-non-opt-expr.rs:36:23 + | +LL | let _ = [1, 2, 3][#[cfg(true)] 1]; + | ^^^^^^^^^^^^ + +error: removing an expression is not supported in this position + --> $DIR/cfg-non-opt-expr.rs:6:10 + | +LL | V1 = #[cfg(true)] 1, + | ^^^^^^^^^^^^ + +error: removing an expression is not supported in this position + --> $DIR/cfg-non-opt-expr.rs:6:10 + | +LL | V1 = #[cfg(true)] 1, + | ^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: removing an expression is not supported in this position + --> $DIR/cfg-non-opt-expr.rs:9:27 + | +LL | V2 = #[cfg_attr(true, cfg(true))] 2, + | ^^^^^^^^^ + +error: removing an expression is not supported in this position + --> $DIR/cfg-non-opt-expr.rs:30:18 + | +LL | let _ = mac!(#[cfg(true)] 10); + | ^^^^^^^^^^^^ + +error: aborting due to 13 previous errors