Skip to content

Commit eafd9c2

Browse files
committed
Disallow cast with trailing braced macro in let-else
1 parent 75a34ca commit eafd9c2

File tree

3 files changed

+88
-3
lines changed

3 files changed

+88
-3
lines changed

compiler/rustc_ast/src/util/classify.rs

+72-1
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,10 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
113113
| While(..)
114114
| ConstBlock(_) => break Some(expr),
115115

116+
Cast(_, ty) => {
117+
break type_trailing_brace(ty).then_some(expr);
118+
}
119+
116120
MacCall(mac) => {
117121
break (mac.args.delim == Delimiter::Brace).then_some(expr);
118122
}
@@ -131,7 +135,6 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
131135
| MethodCall(_)
132136
| Tup(_)
133137
| Lit(_)
134-
| Cast(_, _)
135138
| Type(_, _)
136139
| Await(_, _)
137140
| Field(_, _)
@@ -148,3 +151,71 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
148151
}
149152
}
150153
}
154+
155+
/// Whether the type's last token is `}`.
156+
fn type_trailing_brace(mut ty: &ast::Ty) -> bool {
157+
loop {
158+
match &ty.kind {
159+
ast::TyKind::AnonStruct(..) | ast::TyKind::AnonUnion(..) => break true,
160+
161+
ast::TyKind::MacCall(mac) => break mac.args.delim == Delimiter::Brace,
162+
163+
ast::TyKind::Ptr(mut_ty) | ast::TyKind::Ref(_, mut_ty) => {
164+
ty = &mut_ty.ty;
165+
}
166+
167+
ast::TyKind::BareFn(fn_ty) => match &fn_ty.decl.output {
168+
ast::FnRetTy::Default(_) => break false,
169+
ast::FnRetTy::Ty(ret) => ty = ret,
170+
},
171+
172+
ast::TyKind::Path(_, path) => match path_return_type(path) {
173+
Some(trailing_ty) => ty = trailing_ty,
174+
None => break false,
175+
},
176+
177+
ast::TyKind::TraitObject(bounds, _) | ast::TyKind::ImplTrait(_, bounds, _) => {
178+
match bounds.last() {
179+
Some(ast::GenericBound::Trait(bound, _)) => {
180+
match path_return_type(&bound.trait_ref.path) {
181+
Some(trailing_ty) => ty = trailing_ty,
182+
None => break false,
183+
}
184+
}
185+
Some(ast::GenericBound::Outlives(_)) | None => break false,
186+
}
187+
}
188+
189+
ast::TyKind::Slice(..)
190+
| ast::TyKind::Array(..)
191+
| ast::TyKind::Never
192+
| ast::TyKind::Tup(..)
193+
| ast::TyKind::Paren(..)
194+
| ast::TyKind::Typeof(..)
195+
| ast::TyKind::Infer
196+
| ast::TyKind::ImplicitSelf
197+
| ast::TyKind::CVarArgs
198+
| ast::TyKind::Pat(..)
199+
| ast::TyKind::Dummy
200+
| ast::TyKind::Err(..) => break false,
201+
}
202+
}
203+
}
204+
205+
/// Returns the trailing return type in the given path, if it has one.
206+
///
207+
/// ```ignore (illustrative)
208+
/// ::std::ops::FnOnce(&str) -> fn() -> *const c_void
209+
/// ^^^^^^^^^^^^^^^^^^^^^
210+
/// ```
211+
fn path_return_type(path: &ast::Path) -> Option<&ast::Ty> {
212+
let last_segment = path.segments.last()?;
213+
let args = last_segment.args.as_ref()?;
214+
match &**args {
215+
ast::GenericArgs::Parenthesized(args) => match &args.output {
216+
ast::FnRetTy::Default(_) => None,
217+
ast::FnRetTy::Ty(ret) => Some(ret),
218+
},
219+
ast::GenericArgs::AngleBracketed(_) => None,
220+
}
221+
}

tests/ui/parser/bad-let-else-statement.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ fn t() {
205205
//~^ WARN irrefutable `let...else` pattern
206206
8
207207
} else {
208-
// FIXME: right curly brace `}` before `else` in a `let...else` statement not allowed
208+
//~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
209209
return;
210210
};
211211
}

tests/ui/parser/bad-let-else-statement.stderr

+15-1
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,20 @@ help: use parentheses instead of braces for this macro
241241
LL | let bad = format_args! ("") else { return; };
242242
| ~ ~
243243

244+
error: right curly brace `}` before `else` in a `let...else` statement not allowed
245+
--> $DIR/bad-let-else-statement.rs:207:5
246+
|
247+
LL | } else {
248+
| ^
249+
|
250+
help: wrap the expression in parentheses
251+
|
252+
LL ~ let foo = (&std::ptr::null as &'static dyn std::ops::Fn() -> *const primitive! {
253+
LL |
254+
LL | 8
255+
LL ~ }) else {
256+
|
257+
244258
error: right curly brace `}` before `else` in a `let...else` statement not allowed
245259
--> $DIR/bad-let-else-statement.rs:190:25
246260
|
@@ -311,5 +325,5 @@ LL | | } else {
311325
= note: this pattern will always match, so the `else` clause is useless
312326
= help: consider removing the `else` clause
313327

314-
error: aborting due to 19 previous errors; 5 warnings emitted
328+
error: aborting due to 20 previous errors; 5 warnings emitted
315329

0 commit comments

Comments
 (0)