Skip to content

Commit

Permalink
Disallow cast with trailing braced macro in let-else
Browse files Browse the repository at this point in the history
  • Loading branch information
dtolnay committed May 12, 2024
1 parent 75a34ca commit eafd9c2
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 3 deletions.
73 changes: 72 additions & 1 deletion compiler/rustc_ast/src/util/classify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
| While(..)
| ConstBlock(_) => break Some(expr),

Cast(_, ty) => {
break type_trailing_brace(ty).then_some(expr);
}

MacCall(mac) => {
break (mac.args.delim == Delimiter::Brace).then_some(expr);
}
Expand All @@ -131,7 +135,6 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
| MethodCall(_)
| Tup(_)
| Lit(_)
| Cast(_, _)
| Type(_, _)
| Await(_, _)
| Field(_, _)
Expand All @@ -148,3 +151,71 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
}
}
}

/// Whether the type's last token is `}`.
fn type_trailing_brace(mut ty: &ast::Ty) -> bool {
loop {
match &ty.kind {
ast::TyKind::AnonStruct(..) | ast::TyKind::AnonUnion(..) => break true,

ast::TyKind::MacCall(mac) => break mac.args.delim == Delimiter::Brace,

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 false,
ast::FnRetTy::Ty(ret) => ty = ret,
},

ast::TyKind::Path(_, path) => match path_return_type(path) {
Some(trailing_ty) => ty = trailing_ty,
None => break false,
},

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 false,
}
}
Some(ast::GenericBound::Outlives(_)) | None => break false,
}
}

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 false,
}
}
}

/// 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,
}
}
2 changes: 1 addition & 1 deletion tests/ui/parser/bad-let-else-statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ fn t() {
//~^ WARN irrefutable `let...else` pattern
8
} else {
// FIXME: right curly brace `}` before `else` in a `let...else` statement not allowed
//~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
return;
};
}
Expand Down
16 changes: 15 additions & 1 deletion tests/ui/parser/bad-let-else-statement.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,20 @@ help: use parentheses instead of braces for this macro
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:207:5
|
LL | } else {
| ^
|
help: wrap the expression in parentheses
|
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
|
Expand Down Expand Up @@ -311,5 +325,5 @@ LL | | } else {
= note: this pattern will always match, so the `else` clause is useless
= help: consider removing the `else` clause

error: aborting due to 19 previous errors; 5 warnings emitted
error: aborting due to 20 previous errors; 5 warnings emitted

0 comments on commit eafd9c2

Please sign in to comment.