Change:
Error code: Metadata:
What is the issue you are reporting here ?
Well, I thought that compiler can understand that is related to the block of code, but it fails.
Can you post a minimal reproducible example that demonstrates your issue? Or at least mention exactly what you'd expect to happen and why. Even code that is cfged out is still required to parse successfully.
Let's show you what exactly problem I have. Full code: And I get this error:
You seem to already have posted this a month ago. What you're asking seems a rather big change to me, I'm not that familiar with how the compiler parser works but I believe it currently requires your program syntax to be correct before macros are expanded, which is not true for your example, so some fundamental changes would be needed.
Oh, damn, sorry. I totally forgot that I made a post. Well, if it's not a bug and parser works like this it is bad, anyway, exists alternative way to write like this. But for me my issue is a candidate to feature request or a bug. Anyway, I'm not a lang dev, so I don't know what scales of this defect (?).
The workaround for this is to wrap the expressions in a block:
I solved this issue exactly as you did.
Another way to do this is using the macro and . I personally thinks it is more clear, and should optimize the same.
Work is not the same, due to compile-time evaluating an expression that we pass in it and evaluates only it, but at the same time everything compiles what is inside of .

Discussion:
use crate::fluent_generated as fluent; use crate::parser; <ins> use crate::parser::attr::InnerAttrPolicy; </ins> use rustc_ast as ast; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, Lit, LitKind, TokenKind};

Err(err) } <ins> pub(super) fn attr_on_non_tail_expr(&self, expr: &Expr) { // Missing semicolon typo error. let span = self.prev_token.span.shrink_to_hi(); let mut err = self.sess.create_err(ExpectedSemi { span, token: self.token.clone(), unexpected_token_label: Some(self.token.span), sugg: ExpectedSemiSugg::AddSemi(span), }); let attr_span = match &expr.attrs[..] { [] => unreachable!(), [only] => only.span, [first, rest @ ..] => { for attr in rest { err.span_label(attr.span, ""); } first.span } }; err.span_label( attr_span, format!( "only `;` terminated statements or tail expressions are allowed after {}", if expr.attrs.len() == 1 { "this attribute" } else { "these attributes" }, ), ); if self.token == token::Pound && self.look_ahead(1, |t| t.kind == token::OpenDelim(Delimiter::Bracket)) { // We have // #[attr] // expr // #[not_attr] // other_expr err.span_label(span, "expected `;` here"); err.multipart_suggestion( "alternatively, consider surrounding the expression with a block", vec![ (expr.span.shrink_to_lo(), "{ ".to_string()), (expr.span.shrink_to_hi(), " }".to_string()), ], Applicability::MachineApplicable, ); let mut snapshot = self.create_snapshot_for_diagnostic(); if let [attr] = &expr.attrs[..] && let ast::AttrKind::Normal(attr_kind) = &attr.kind && let [segment] = &attr_kind.item.path.segments[..] && segment.ident.name == sym::cfg && let Ok(next_attr) = snapshot.parse_attribute(InnerAttrPolicy::Forbidden(None)) && let ast::AttrKind::Normal(next_attr_kind) = next_attr.kind && let [next_segment] = &next_attr_kind.item.path.segments[..] && segment.ident.name == sym::cfg && let Ok(next_expr) = snapshot.parse_expr() { // We have for sure // #[cfg(..)] // expr // #[cfg(..)] // other_expr // So we suggest using `if cfg!(..) { expr } else if cfg!(..) { other_expr }`. let margin = self.sess.source_map().span_to_margin(next_expr.span).unwrap_or(0); let sugg = vec![ (attr.span.with_hi(segment.span().hi()), "if cfg!".to_string()), ( attr_kind.item.args.span().unwrap().shrink_to_hi().with_hi(attr.span.hi()), " {".to_string(), ), (expr.span.shrink_to_lo(), "    ".to_string()), ( next_attr.span.with_hi(next_segment.span().hi()), "} else if cfg!".to_string(), ), ( next_attr_kind .item .args .span() .unwrap() .shrink_to_hi() .with_hi(next_attr.span.hi()), " {".to_string(), ), (next_expr.span.shrink_to_lo(), "    ".to_string()), (next_expr.span.shrink_to_hi(), format!("n{}}}", " ".repeat(margin))), ]; err.multipart_suggestion( "it seems like you are trying to provide different expressions depending on  `cfg`, consider using `if cfg!(..)`", sugg, Applicability::MachineApplicable, ); } } err.emit(); } </ins> fn check_too_many_raw_str_terminators(&mut self, err: &mut Diagnostic) -> bool { let sm = self.sess.source_map(); match (&self.prev_token.kind, &self.token.kind) {

match &mut stmt.kind { // Expression without semicolon. StmtKind::Expr(expr) <ins> if classify::expr_requires_semi_to_be_stmt(expr) && !expr.attrs.is_empty() && ![token::Eof, token::Semi, token::CloseDelim(Delimiter::Brace)] .contains(&self.token.kind) => { // The user has written `#[attr] expr` which is unsupported. (#106020) self.attr_on_non_tail_expr(&expr); // We already emitted an error, so don't emit another type error let sp = expr.span.to(self.prev_token.span); *expr = self.mk_expr_err(sp); } // Expression without semicolon. StmtKind::Expr(expr) </ins> if self.token != token::Eof && classify::expr_requires_semi_to_be_stmt(expr) => { // Just check for errors and recover; do not eat semicolon yet.

<ins> #![feature(stmt_expr_attributes)] fn foo() -> String { #[cfg(feature = "validation")] [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>() //~ ERROR expected `;`, found `#` #[cfg(not(feature = "validation"))] String::new() } fn bar() -> String { #[attr] [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>() //~ ERROR expected `;`, found `#` #[attr] //~ ERROR cannot find attribute `attr` in this scope String::new() } fn main() { println!("{}", foo()); } </ins>

<ins> error: expected `;`, found `#` --> $DIR/multiple-tail-expr-behind-cfg.rs:5:64 | LL |     #[cfg(feature = "validation")] |     ------------------------------ only `;` terminated statements or tail expressions are allowed after this attribute LL |     [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>() |                                                                ^ expected `;` here LL |     #[cfg(not(feature = "validation"))] |     - unexpected token | help: add `;` here | LL |     [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>(); |                                                                + help: alternatively, consider surrounding the expression with a block | LL |     { [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>() } |     +                                                             + help: it seems like you are trying to provide different expressions depending on `cfg`, consider using `if cfg!(..)` | LL ~     if cfg!(feature = "validation") { LL ~         [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>() LL ~     } else if cfg!(not(feature = "validation")) { LL ~         String::new() LL +     } | error: expected `;`, found `#` --> $DIR/multiple-tail-expr-behind-cfg.rs:12:64 | LL |     #[attr] |     ------- only `;` terminated statements or tail expressions are allowed after this attribute LL |     [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>() |                                                                ^ expected `;` here LL |     #[attr] |     - unexpected token | help: add `;` here | LL |     [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>(); |                                                                + help: alternatively, consider surrounding the expression with a block | LL |     { [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>() } |     +                                                             + error: cannot find attribute `attr` in this scope --> $DIR/multiple-tail-expr-behind-cfg.rs:13:7 | LL |     #[attr] |       ^^^^ error: aborting due to 3 previous errors </ins>