Merge from rustc · rust-lang/rust@f1ffb8d
@@ -81,8 +81,17 @@ pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
8181}
8282}
838384+pub enum TrailingBrace<'a> {
85+/// Trailing brace in a macro call, like the one in `x as *const brace! {}`.
86+ /// We will suggest changing the macro call to a different delimiter.
87+ MacCall(&'a ast::MacCall),
88+/// Trailing brace in any other expression, such as `a + B {}`. We will
89+ /// suggest wrapping the innermost expression in parentheses: `a + (B {})`.
90+ Expr(&'a ast::Expr),
91+}
92+8493/// If an expression ends with `}`, returns the innermost expression ending in the `}`
85-pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
94+pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<TrailingBrace<'_>> {
8695loop {
8796match &expr.kind {
8897AddrOf(_, _, e)
@@ -111,10 +120,14 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
111120 | Struct(..)
112121 | TryBlock(..)
113122 | While(..)
114- | ConstBlock(_) => break Some(expr),
123+ | ConstBlock(_) => break Some(TrailingBrace::Expr(expr)),
124+125+Cast(_, ty) => {
126+break type_trailing_braced_mac_call(ty).map(TrailingBrace::MacCall);
127+}
115128116129MacCall(mac) => {
117-break (mac.args.delim == Delimiter::Brace).then_some(expr);
130+break (mac.args.delim == Delimiter::Brace).then_some(TrailingBrace::MacCall(mac));
118131}
119132120133InlineAsm(_) | OffsetOf(_, _) | IncludedBytes(_) | FormatArgs(_) => {
@@ -131,7 +144,6 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
131144 | MethodCall(_)
132145 | Tup(_)
133146 | Lit(_)
134- | Cast(_, _)
135147 | Type(_, _)
136148 | Await(_, _)
137149 | Field(_, _)
@@ -148,3 +160,78 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
148160}
149161}
150162}
163+164+/// If the type's last token is `}`, it must be due to a braced macro call, such
165+/// as in `*const brace! { ... }`. Returns that trailing macro call.
166+fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> {
167+loop {
168+match &ty.kind {
169+ ast::TyKind::MacCall(mac) => {
170+break (mac.args.delim == Delimiter::Brace).then_some(mac);
171+}
172+173+ ast::TyKind::Ptr(mut_ty) | ast::TyKind::Ref(_, mut_ty) => {
174+ ty = &mut_ty.ty;
175+}
176+177+ ast::TyKind::BareFn(fn_ty) => match &fn_ty.decl.output {
178+ ast::FnRetTy::Default(_) => break None,
179+ ast::FnRetTy::Ty(ret) => ty = ret,
180+},
181+182+ ast::TyKind::Path(_, path) => match path_return_type(path) {
183+Some(trailing_ty) => ty = trailing_ty,
184+None => break None,
185+},
186+187+ ast::TyKind::TraitObject(bounds, _) | ast::TyKind::ImplTrait(_, bounds, _) => {
188+match bounds.last() {
189+Some(ast::GenericBound::Trait(bound, _)) => {
190+match path_return_type(&bound.trait_ref.path) {
191+Some(trailing_ty) => ty = trailing_ty,
192+None => break None,
193+}
194+}
195+Some(ast::GenericBound::Outlives(_)) | None => break None,
196+}
197+}
198+199+ ast::TyKind::Slice(..)
200+ | ast::TyKind::Array(..)
201+ | ast::TyKind::Never
202+ | ast::TyKind::Tup(..)
203+ | ast::TyKind::Paren(..)
204+ | ast::TyKind::Typeof(..)
205+ | ast::TyKind::Infer
206+ | ast::TyKind::ImplicitSelf
207+ | ast::TyKind::CVarArgs
208+ | ast::TyKind::Pat(..)
209+ | ast::TyKind::Dummy
210+ | ast::TyKind::Err(..) => break None,
211+212+// These end in brace, but cannot occur in a let-else statement.
213+// They are only parsed as fields of a data structure. For the
214+// purpose of denying trailing braces in the expression of a
215+// let-else, we can disregard these.
216+ ast::TyKind::AnonStruct(..) | ast::TyKind::AnonUnion(..) => break None,
217+}
218+}
219+}
220+221+/// Returns the trailing return type in the given path, if it has one.
222+///
223+/// ```ignore (illustrative)
224+/// ::std::ops::FnOnce(&str) -> fn() -> *const c_void
225+/// ^^^^^^^^^^^^^^^^^^^^^
226+/// ```
227+fn path_return_type(path: &ast::Path) -> Option<&ast::Ty> {
228+let last_segment = path.segments.last()?;
229+let args = last_segment.args.as_ref()?;
230+match &**args {
231+ ast::GenericArgs::Parenthesized(args) => match &args.output {
232+ ast::FnRetTy::Default(_) => None,
233+ ast::FnRetTy::Ty(ret) => Some(ret),
234+},
235+ ast::GenericArgs::AngleBracketed(_) => None,
236+}
237+}