Rollup merge of #125049 - dtolnay:castbrace, r=compiler-errors

Disallow cast with trailing braced macro in let-else

This fixes an edge case I noticed while porting #118880 and #119062 to syn.

Previously, rustc incorrectly accepted code such as:

```rust
let foo = &std::ptr::null as &'static dyn std::ops::Fn() -> *const primitive! {
    8
} else {
    return;
};
```

even though a right curl brace `}` directly before `else` in a `let...else` statement is not supposed to be valid syntax.
This commit is contained in:
León Orell Valerian Liehr 2024-05-22 19:04:44 +02:00 committed by GitHub
commit 5b485f04de
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 210 additions and 298 deletions

View File

@ -81,8 +81,17 @@ pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
}
}
pub enum TrailingBrace<'a> {
/// Trailing brace in a macro call, like the one in `x as *const brace! {}`.
/// We will suggest changing the macro call to a different delimiter.
MacCall(&'a ast::MacCall),
/// Trailing brace in any other expression, such as `a + B {}`. We will
/// suggest wrapping the innermost expression in parentheses: `a + (B {})`.
Expr(&'a ast::Expr),
}
/// If an expression ends with `}`, returns the innermost expression ending in the `}`
pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<TrailingBrace<'_>> {
loop {
match &expr.kind {
AddrOf(_, _, e)
@ -111,10 +120,14 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
| Struct(..)
| TryBlock(..)
| While(..)
| ConstBlock(_) => break Some(expr),
| ConstBlock(_) => break Some(TrailingBrace::Expr(expr)),
Cast(_, ty) => {
break type_trailing_braced_mac_call(ty).map(TrailingBrace::MacCall);
}
MacCall(mac) => {
break (mac.args.delim == Delimiter::Brace).then_some(expr);
break (mac.args.delim == Delimiter::Brace).then_some(TrailingBrace::MacCall(mac));
}
InlineAsm(_) | OffsetOf(_, _) | IncludedBytes(_) | FormatArgs(_) => {
@ -131,7 +144,6 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
| MethodCall(_)
| Tup(_)
| Lit(_)
| Cast(_, _)
| Type(_, _)
| Await(_, _)
| Field(_, _)
@ -148,3 +160,78 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
}
}
}
/// If the type's last token is `}`, it must be due to a braced macro call, such
/// as in `*const brace! { ... }`. Returns that trailing macro call.
fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> {
loop {
match &ty.kind {
ast::TyKind::MacCall(mac) => {
break (mac.args.delim == Delimiter::Brace).then_some(mac);
}
ast::TyKind::Ptr(mut_ty) | ast::TyKind::Ref(_, mut_ty) => {
ty = &mut_ty.ty;
}
ast::TyKind::BareFn(fn_ty) => match &fn_ty.decl.output {
ast::FnRetTy::Default(_) => break None,
ast::FnRetTy::Ty(ret) => ty = ret,
},
ast::TyKind::Path(_, path) => match path_return_type(path) {
Some(trailing_ty) => ty = trailing_ty,
None => break None,
},
ast::TyKind::TraitObject(bounds, _) | ast::TyKind::ImplTrait(_, bounds, _) => {
match bounds.last() {
Some(ast::GenericBound::Trait(bound, _)) => {
match path_return_type(&bound.trait_ref.path) {
Some(trailing_ty) => ty = trailing_ty,
None => break None,
}
}
Some(ast::GenericBound::Outlives(_)) | None => break None,
}
}
ast::TyKind::Slice(..)
| ast::TyKind::Array(..)
| ast::TyKind::Never
| ast::TyKind::Tup(..)
| ast::TyKind::Paren(..)
| ast::TyKind::Typeof(..)
| ast::TyKind::Infer
| ast::TyKind::ImplicitSelf
| ast::TyKind::CVarArgs
| ast::TyKind::Pat(..)
| ast::TyKind::Dummy
| ast::TyKind::Err(..) => break None,
// These end in brace, but cannot occur in a let-else statement.
// They are only parsed as fields of a data structure. For the
// purpose of denying trailing braces in the expression of a
// let-else, we can disregard these.
ast::TyKind::AnonStruct(..) | ast::TyKind::AnonUnion(..) => break None,
}
}
}
/// Returns the trailing return type in the given path, if it has one.
///
/// ```ignore (illustrative)
/// ::std::ops::FnOnce(&str) -> fn() -> *const c_void
/// ^^^^^^^^^^^^^^^^^^^^^
/// ```
fn path_return_type(path: &ast::Path) -> Option<&ast::Ty> {
let last_segment = path.segments.last()?;
let args = last_segment.args.as_ref()?;
match &**args {
ast::GenericArgs::Parenthesized(args) => match &args.output {
ast::FnRetTy::Default(_) => None,
ast::FnRetTy::Ty(ret) => Some(ret),
},
ast::GenericArgs::AngleBracketed(_) => None,
}
}

View File

@ -15,7 +15,7 @@ use ast::Label;
use rustc_ast as ast;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter, TokenKind};
use rustc_ast::util::classify;
use rustc_ast::util::classify::{self, TrailingBrace};
use rustc_ast::{AttrStyle, AttrVec, LocalKind, MacCall, MacCallStmt, MacStmtStyle};
use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, HasAttrs, Local, Recovered, Stmt};
use rustc_ast::{StmtKind, DUMMY_NODE_ID};
@ -407,18 +407,24 @@ impl<'a> Parser<'a> {
fn check_let_else_init_trailing_brace(&self, init: &ast::Expr) {
if let Some(trailing) = classify::expr_trailing_brace(init) {
let sugg = match &trailing.kind {
ExprKind::MacCall(mac) => errors::WrapInParentheses::MacroArgs {
let (span, sugg) = match trailing {
TrailingBrace::MacCall(mac) => (
mac.span(),
errors::WrapInParentheses::MacroArgs {
left: mac.args.dspan.open,
right: mac.args.dspan.close,
},
_ => errors::WrapInParentheses::Expression {
left: trailing.span.shrink_to_lo(),
right: trailing.span.shrink_to_hi(),
),
TrailingBrace::Expr(expr) => (
expr.span,
errors::WrapInParentheses::Expression {
left: expr.span.shrink_to_lo(),
right: expr.span.shrink_to_hi(),
},
),
};
self.dcx().emit_err(errors::InvalidCurlyInLetElse {
span: trailing.span.with_lo(trailing.span.hi() - BytePos(1)),
span: span.with_lo(span.hi() - BytePos(1)),
sugg,
});
}

View File

@ -3,8 +3,7 @@
#![feature(explicit_tail_calls)]
fn a() {
let foo = {
//~^ WARN irrefutable `let...else` pattern
let 0 = {
1
} else {
//~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
@ -22,8 +21,7 @@ fn b() {
}
fn c() {
let foo = if true {
//~^ WARN irrefutable `let...else` pattern
let 0 = if true {
1
} else {
0
@ -43,8 +41,7 @@ fn d() {
}
fn e() {
let foo = match true {
//~^ WARN irrefutable `let...else` pattern
let 0 = match true {
true => 1,
false => 0
} else {
@ -53,10 +50,12 @@ fn e() {
};
}
struct X {a: i32}
fn f() {
let foo = X {
//~^ WARN irrefutable `let...else` pattern
struct X {
a: i32,
}
let X { a: 0 } = X {
a: 1
} else {
//~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
@ -74,8 +73,7 @@ fn g() {
}
fn h() {
let foo = const {
//~^ WARN irrefutable `let...else` pattern
let 0 = const {
1
} else {
//~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
@ -84,8 +82,7 @@ fn h() {
}
fn i() {
let foo = &{
//~^ WARN irrefutable `let...else` pattern
let 0 = &{
1
} else {
//~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
@ -94,8 +91,8 @@ fn i() {
}
fn j() {
let bar = 0;
let foo = bar = { //~ ERROR: cannot assign twice
let mut bar = 0;
let foo = bar = {
//~^ WARN irrefutable `let...else` pattern
1
} else {
@ -105,8 +102,7 @@ fn j() {
}
fn k() {
let foo = 1 + {
//~^ WARN irrefutable `let...else` pattern
let 0 = 1 + {
1
} else {
//~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
@ -115,8 +111,8 @@ fn k() {
}
fn l() {
let foo = 1..{
//~^ WARN irrefutable `let...else` pattern
const RANGE: std::ops::Range<u8> = 0..0;
let RANGE = 1..{
1
} else {
//~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
@ -125,8 +121,7 @@ fn l() {
}
fn m() {
let foo = return {
//~^ WARN irrefutable `let...else` pattern
let 0 = return {
()
} else {
//~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
@ -135,8 +130,7 @@ fn m() {
}
fn n() {
let foo = -{
//~^ WARN irrefutable `let...else` pattern
let 0 = -{
1
} else {
//~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
@ -145,8 +139,7 @@ fn n() {
}
fn o() -> Result<(), ()> {
let foo = do yeet {
//~^ WARN irrefutable `let...else` pattern
let 0 = do yeet {
()
} else {
//~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
@ -155,8 +148,7 @@ fn o() -> Result<(), ()> {
}
fn p() {
let foo = become {
//~^ WARN irrefutable `let...else` pattern
let 0 = become {
()
} else {
//~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
@ -185,22 +177,37 @@ fn r() {
fn s() {
macro_rules! a {
() => { {} }
//~^ WARN irrefutable `let...else` pattern
//~| WARN irrefutable `let...else` pattern
() => {
{ 1 }
};
}
macro_rules! b {
(1) => {
let x = a!() else { return; };
let 0 = a!() else { return; };
};
(2) => {
let x = a! {} else { return; };
let 0 = a! {} else { return; };
//~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
};
}
b!(1); b!(2);
b!(1);
b!(2);
}
fn t() {
macro_rules! primitive {
(8) => { u8 };
}
let foo = &std::ptr::null as &'static dyn std::ops::Fn() -> *const primitive! {
//~^ WARN irrefutable `let...else` pattern
8
} else {
//~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
return;
};
}
fn main() {}

View File

@ -1,19 +1,18 @@
error: right curly brace `}` before `else` in a `let...else` statement not allowed
--> $DIR/bad-let-else-statement.rs:9:5
--> $DIR/bad-let-else-statement.rs:8:5
|
LL | } else {
| ^
|
help: wrap the expression in parentheses
|
LL ~ let foo = ({
LL |
LL ~ let 0 = ({
LL | 1
LL ~ }) else {
|
error: `for...else` loops are not supported
--> $DIR/bad-let-else-statement.rs:18:7
--> $DIR/bad-let-else-statement.rs:17:7
|
LL | let foo = for i in 1..2 {
| --- `else` is attached to this loop
@ -28,22 +27,22 @@ LL | | };
= note: consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run
error: right curly brace `}` before `else` in a `let...else` statement not allowed
--> $DIR/bad-let-else-statement.rs:30:5
--> $DIR/bad-let-else-statement.rs:28:5
|
LL | } else {
| ^
|
help: wrap the expression in parentheses
|
LL ~ let foo = (if true {
LL |
...
LL ~ let 0 = (if true {
LL | 1
LL | } else {
LL | 0
LL ~ }) else {
|
error: `loop...else` loops are not supported
--> $DIR/bad-let-else-statement.rs:39:7
--> $DIR/bad-let-else-statement.rs:37:7
|
LL | let foo = loop {
| ---- `else` is attached to this loop
@ -58,36 +57,34 @@ LL | | };
= note: consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run
error: right curly brace `}` before `else` in a `let...else` statement not allowed
--> $DIR/bad-let-else-statement.rs:50:5
--> $DIR/bad-let-else-statement.rs:47:5
|
LL | } else {
| ^
|
help: wrap the expression in parentheses
|
LL ~ let foo = (match true {
LL |
LL ~ let 0 = (match true {
LL | true => 1,
LL | false => 0
LL ~ }) else {
|
error: right curly brace `}` before `else` in a `let...else` statement not allowed
--> $DIR/bad-let-else-statement.rs:61:5
--> $DIR/bad-let-else-statement.rs:60:5
|
LL | } else {
| ^
|
help: wrap the expression in parentheses
|
LL ~ let foo = (X {
LL |
LL ~ let X { a: 0 } = (X {
LL | a: 1
LL ~ }) else {
|
error: `while...else` loops are not supported
--> $DIR/bad-let-else-statement.rs:70:7
--> $DIR/bad-let-else-statement.rs:69:7
|
LL | let foo = while false {
| ----- `else` is attached to this loop
@ -102,35 +99,33 @@ LL | | };
= note: consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run
error: right curly brace `}` before `else` in a `let...else` statement not allowed
--> $DIR/bad-let-else-statement.rs:80:5
--> $DIR/bad-let-else-statement.rs:78:5
|
LL | } else {
| ^
|
help: wrap the expression in parentheses
|
LL ~ let foo = (const {
LL |
LL ~ let 0 = (const {
LL | 1
LL ~ }) else {
|
error: right curly brace `}` before `else` in a `let...else` statement not allowed
--> $DIR/bad-let-else-statement.rs:90:5
--> $DIR/bad-let-else-statement.rs:87:5
|
LL | } else {
| ^
|
help: wrap the expression in parentheses
|
LL ~ let foo = &({
LL |
LL ~ let 0 = &({
LL | 1
LL ~ }) else {
|
error: right curly brace `}` before `else` in a `let...else` statement not allowed
--> $DIR/bad-let-else-statement.rs:101:5
--> $DIR/bad-let-else-statement.rs:98:5
|
LL | } else {
| ^
@ -144,91 +139,85 @@ LL ~ }) else {
|
error: right curly brace `}` before `else` in a `let...else` statement not allowed
--> $DIR/bad-let-else-statement.rs:111:5
--> $DIR/bad-let-else-statement.rs:107:5
|
LL | } else {
| ^
|
help: wrap the expression in parentheses
|
LL ~ let foo = 1 + ({
LL |
LL ~ let 0 = 1 + ({
LL | 1
LL ~ }) else {
|
error: right curly brace `}` before `else` in a `let...else` statement not allowed
--> $DIR/bad-let-else-statement.rs:121:5
--> $DIR/bad-let-else-statement.rs:117:5
|
LL | } else {
| ^
|
help: wrap the expression in parentheses
|
LL ~ let foo = 1..({
LL |
LL ~ let RANGE = 1..({
LL | 1
LL ~ }) else {
|
error: right curly brace `}` before `else` in a `let...else` statement not allowed
--> $DIR/bad-let-else-statement.rs:131:5
--> $DIR/bad-let-else-statement.rs:126:5
|
LL | } else {
| ^
|
help: wrap the expression in parentheses
|
LL ~ let foo = return ({
LL |
LL ~ let 0 = return ({
LL | ()
LL ~ }) else {
|
error: right curly brace `}` before `else` in a `let...else` statement not allowed
--> $DIR/bad-let-else-statement.rs:141:5
--> $DIR/bad-let-else-statement.rs:135:5
|
LL | } else {
| ^
|
help: wrap the expression in parentheses
|
LL ~ let foo = -({
LL |
LL ~ let 0 = -({
LL | 1
LL ~ }) else {
|
error: right curly brace `}` before `else` in a `let...else` statement not allowed
--> $DIR/bad-let-else-statement.rs:151:5
--> $DIR/bad-let-else-statement.rs:144:5
|
LL | } else {
| ^
|
help: wrap the expression in parentheses
|
LL ~ let foo = do yeet ({
LL |
LL ~ let 0 = do yeet ({
LL | ()
LL ~ }) else {
|
error: right curly brace `}` before `else` in a `let...else` statement not allowed
--> $DIR/bad-let-else-statement.rs:161:5
--> $DIR/bad-let-else-statement.rs:153:5
|
LL | } else {
| ^
|
help: wrap the expression in parentheses
|
LL ~ let foo = become ({
LL |
LL ~ let 0 = become ({
LL | ()
LL ~ }) else {
|
error: right curly brace `}` before `else` in a `let...else` statement not allowed
--> $DIR/bad-let-else-statement.rs:171:5
--> $DIR/bad-let-else-statement.rs:163:5
|
LL | } else {
| ^
@ -242,7 +231,7 @@ LL ~ }) else {
|
error: right curly brace `}` before `else` in a `let...else` statement not allowed
--> $DIR/bad-let-else-statement.rs:181:31
--> $DIR/bad-let-else-statement.rs:173:31
|
LL | let bad = format_args! {""} else { return; };
| ^
@ -253,24 +242,38 @@ LL | let bad = format_args! ("") else { return; };
| ~ ~
error: right curly brace `}` before `else` in a `let...else` statement not allowed
--> $DIR/bad-let-else-statement.rs:198:25
--> $DIR/bad-let-else-statement.rs:207:5
|
LL | let x = a! {} else { return; };
LL | } else {
| ^
|
help: use parentheses instead of braces for this macro
|
LL ~ let foo = &std::ptr::null as &'static dyn std::ops::Fn() -> *const primitive! (
LL |
LL | 8
LL ~ ) else {
|
error: right curly brace `}` before `else` in a `let...else` statement not allowed
--> $DIR/bad-let-else-statement.rs:190:25
|
LL | let 0 = a! {} else { return; };
| ^
...
LL | b!(1); b!(2);
LL | b!(2);
| ----- in this macro invocation
|
= note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info)
help: use parentheses instead of braces for this macro
|
LL | let x = a! () else { return; };
LL | let 0 = a! () else { return; };
| ~~
warning: irrefutable `let...else` pattern
--> $DIR/bad-let-else-statement.rs:6:5
--> $DIR/bad-let-else-statement.rs:95:5
|
LL | / let foo = {
LL | / let foo = bar = {
LL | |
LL | | 1
LL | | } else {
@ -281,169 +284,7 @@ LL | | } else {
= note: `#[warn(irrefutable_let_patterns)]` on by default
warning: irrefutable `let...else` pattern
--> $DIR/bad-let-else-statement.rs:25:5
|
LL | / let foo = if true {
LL | |
LL | | 1
LL | | } else {
LL | | 0
LL | | } else {
| |_____^
|
= note: this pattern will always match, so the `else` clause is useless
= help: consider removing the `else` clause
warning: irrefutable `let...else` pattern
--> $DIR/bad-let-else-statement.rs:46:5
|
LL | / let foo = match true {
LL | |
LL | | true => 1,
LL | | false => 0
LL | | } else {
| |_____^
|
= note: this pattern will always match, so the `else` clause is useless
= help: consider removing the `else` clause
warning: irrefutable `let...else` pattern
--> $DIR/bad-let-else-statement.rs:58:5
|
LL | / let foo = X {
LL | |
LL | | a: 1
LL | | } else {
| |_____^
|
= note: this pattern will always match, so the `else` clause is useless
= help: consider removing the `else` clause
warning: irrefutable `let...else` pattern
--> $DIR/bad-let-else-statement.rs:77:5
|
LL | / let foo = const {
LL | |
LL | | 1
LL | | } else {
| |_____^
|
= note: this pattern will always match, so the `else` clause is useless
= help: consider removing the `else` clause
warning: irrefutable `let...else` pattern
--> $DIR/bad-let-else-statement.rs:87:5
|
LL | / let foo = &{
LL | |
LL | | 1
LL | | } else {
| |_____^
|
= note: this pattern will always match, so the `else` clause is useless
= help: consider removing the `else` clause
warning: irrefutable `let...else` pattern
--> $DIR/bad-let-else-statement.rs:98:5
|
LL | / let foo = bar = {
LL | |
LL | | 1
LL | | } else {
| |_____^
|
= note: this pattern will always match, so the `else` clause is useless
= help: consider removing the `else` clause
error[E0384]: cannot assign twice to immutable variable `bar`
--> $DIR/bad-let-else-statement.rs:98:15
|
LL | let bar = 0;
| ---
| |
| first assignment to `bar`
| help: consider making this binding mutable: `mut bar`
LL | let foo = bar = {
| _______________^
LL | |
LL | | 1
LL | | } else {
| |_____^ cannot assign twice to immutable variable
warning: irrefutable `let...else` pattern
--> $DIR/bad-let-else-statement.rs:108:5
|
LL | / let foo = 1 + {
LL | |
LL | | 1
LL | | } else {
| |_____^
|
= note: this pattern will always match, so the `else` clause is useless
= help: consider removing the `else` clause
warning: irrefutable `let...else` pattern
--> $DIR/bad-let-else-statement.rs:118:5
|
LL | / let foo = 1..{
LL | |
LL | | 1
LL | | } else {
| |_____^
|
= note: this pattern will always match, so the `else` clause is useless
= help: consider removing the `else` clause
warning: irrefutable `let...else` pattern
--> $DIR/bad-let-else-statement.rs:128:5
|
LL | / let foo = return {
LL | |
LL | | ()
LL | | } else {
| |_____^
|
= note: this pattern will always match, so the `else` clause is useless
= help: consider removing the `else` clause
warning: irrefutable `let...else` pattern
--> $DIR/bad-let-else-statement.rs:138:5
|
LL | / let foo = -{
LL | |
LL | | 1
LL | | } else {
| |_____^
|
= note: this pattern will always match, so the `else` clause is useless
= help: consider removing the `else` clause
warning: irrefutable `let...else` pattern
--> $DIR/bad-let-else-statement.rs:148:5
|
LL | / let foo = do yeet {
LL | |
LL | | ()
LL | | } else {
| |_____^
|
= note: this pattern will always match, so the `else` clause is useless
= help: consider removing the `else` clause
warning: irrefutable `let...else` pattern
--> $DIR/bad-let-else-statement.rs:158:5
|
LL | / let foo = become {
LL | |
LL | | ()
LL | | } else {
| |_____^
|
= note: this pattern will always match, so the `else` clause is useless
= help: consider removing the `else` clause
warning: irrefutable `let...else` pattern
--> $DIR/bad-let-else-statement.rs:168:5
--> $DIR/bad-let-else-statement.rs:160:5
|
LL | / let foo = |x: i32| {
LL | |
@ -455,7 +296,7 @@ LL | | } else {
= help: consider removing the `else` clause
warning: irrefutable `let...else` pattern
--> $DIR/bad-let-else-statement.rs:178:5
--> $DIR/bad-let-else-statement.rs:170:5
|
LL | let ok = format_args!("") else { return; };
| ^^^^^^^^^^^^^^^^^^^^^^^^^
@ -464,7 +305,7 @@ LL | let ok = format_args!("") else { return; };
= help: consider removing the `else` clause
warning: irrefutable `let...else` pattern
--> $DIR/bad-let-else-statement.rs:181:5
--> $DIR/bad-let-else-statement.rs:173:5
|
LL | let bad = format_args! {""} else { return; };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -473,45 +314,16 @@ LL | let bad = format_args! {""} else { return; };
= help: consider removing the `else` clause
warning: irrefutable `let...else` pattern
--> $DIR/bad-let-else-statement.rs:188:19
--> $DIR/bad-let-else-statement.rs:204:5
|
LL | () => { {} }
| ___________________^
LL | / let foo = &std::ptr::null as &'static dyn std::ops::Fn() -> *const primitive! {
LL | |
LL | |
LL | | }
... |
LL | | (1) => {
LL | | let x = a!() else { return; };
| |____________^
...
LL | b!(1); b!(2);
| ----- in this macro invocation
LL | | 8
LL | | } else {
| |_____^
|
= note: this pattern will always match, so the `else` clause is useless
= help: consider removing the `else` clause
= note: this warning originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info)
warning: irrefutable `let...else` pattern
--> $DIR/bad-let-else-statement.rs:188:19
|
LL | () => { {} }
| ___________________^
LL | |
LL | |
LL | | }
... |
LL | | (2) => {
LL | | let x = a! {} else { return; };
| |____________^
...
LL | b!(1); b!(2);
| ----- in this macro invocation
|
= note: this pattern will always match, so the `else` clause is useless
= help: consider removing the `else` clause
= note: this warning originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 20 previous errors; 5 warnings emitted
error: aborting due to 20 previous errors; 18 warnings emitted
For more information about this error, try `rustc --explain E0384`.