diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 55ddd24c48a83..5eb7bf6347f7b 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -377,7 +377,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere fn print_string(&mut self, st: &str, style: ast::StrStyle) { let st = match style { - ast::StrStyle::Cooked => (format!("\"{}\"", st.escape_debug())), + ast::StrStyle::Cooked => format!("\"{}\"", st.escape_debug()), ast::StrStyle::Raw(n) => { format!("r{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = st) } diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 8c23756db3313..8bc8964bbd7cc 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -16,9 +16,7 @@ use rustc_middle::mir::{ FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm, }; -use rustc_middle::ty::{ - self, subst::Subst, suggest_constraining_type_params, EarlyBinder, PredicateKind, Ty, -}; +use rustc_middle::ty::{self, subst::Subst, suggest_constraining_type_params, PredicateKind, Ty}; use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex}; use rustc_span::def_id::LocalDefId; use rustc_span::hygiene::DesugaringKind; @@ -461,23 +459,24 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let tcx = self.infcx.tcx; // Find out if the predicates show that the type is a Fn or FnMut - let find_fn_kind_from_did = |predicates: &[(ty::Predicate<'tcx>, Span)], substs| { - predicates.iter().find_map(|(pred, _)| { - let pred = if let Some(substs) = substs { - EarlyBinder(*pred).subst(tcx, substs).kind().skip_binder() - } else { - pred.kind().skip_binder() - }; - if let ty::PredicateKind::Trait(pred) = pred && pred.self_ty() == ty { + let find_fn_kind_from_did = + |predicates: ty::EarlyBinder<&[(ty::Predicate<'tcx>, Span)]>, substs| { + predicates.0.iter().find_map(|(pred, _)| { + let pred = if let Some(substs) = substs { + predicates.rebind(*pred).subst(tcx, substs).kind().skip_binder() + } else { + pred.kind().skip_binder() + }; + if let ty::PredicateKind::Trait(pred) = pred && pred.self_ty() == ty { if Some(pred.def_id()) == tcx.lang_items().fn_trait() { return Some(hir::Mutability::Not); } else if Some(pred.def_id()) == tcx.lang_items().fn_mut_trait() { return Some(hir::Mutability::Mut); } } - None - }) - }; + None + }) + }; // If the type is opaque/param/closure, and it is Fn or FnMut, let's suggest (mutably) // borrowing the type, since `&mut F: FnMut` iff `F: FnMut` and similarly for `Fn`. @@ -485,11 +484,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // borrowed variants in a function body when we see a move error. let borrow_level = match ty.kind() { ty::Param(_) => find_fn_kind_from_did( - tcx.explicit_predicates_of(self.mir_def_id().to_def_id()).predicates, + tcx.bound_explicit_predicates_of(self.mir_def_id().to_def_id()) + .map_bound(|p| p.predicates), None, ), ty::Opaque(did, substs) => { - find_fn_kind_from_did(tcx.explicit_item_bounds(*did), Some(*substs)) + find_fn_kind_from_did(tcx.bound_explicit_item_bounds(*did), Some(*substs)) } ty::Closure(_, substs) => match substs.as_closure().kind() { ty::ClosureKind::Fn => Some(hir::Mutability::Not), diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index f68358ecfe6d2..a87e8bd5ba16f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -839,7 +839,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }), .. - }) => (tcx.sess.source_map().end_point(fn_decl_span)), + }) => tcx.sess.source_map().end_point(fn_decl_span), _ => self.body.span, }; diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index cec574e38c579..9eb96ec76800c 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -280,6 +280,11 @@ struct Context<'a, 'b> { unused_names_lint: PositionalNamedArgsLint, } +pub struct FormatArg { + expr: P, + named: bool, +} + /// Parses the arguments from the given list of tokens, returning the diagnostic /// if there's a parse error so we can continue parsing other format! /// expressions. @@ -293,8 +298,8 @@ fn parse_args<'a>( ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream, -) -> PResult<'a, (P, Vec>, FxHashMap)> { - let mut args = Vec::>::new(); +) -> PResult<'a, (P, Vec, FxHashMap)> { + let mut args = Vec::::new(); let mut names = FxHashMap::::default(); let mut p = ecx.new_parser_from_tts(tts); @@ -362,7 +367,7 @@ fn parse_args<'a>( let e = p.parse_expr()?; if let Some((prev, _)) = names.get(&ident.name) { ecx.struct_span_err(e.span, &format!("duplicate argument named `{}`", ident)) - .span_label(args[*prev].span, "previously here") + .span_label(args[*prev].expr.span, "previously here") .span_label(e.span, "duplicate argument") .emit(); continue; @@ -374,7 +379,7 @@ fn parse_args<'a>( // args. And remember the names. let slot = args.len(); names.insert(ident.name, (slot, ident.span)); - args.push(e); + args.push(FormatArg { expr: e, named: true }); } _ => { let e = p.parse_expr()?; @@ -385,11 +390,11 @@ fn parse_args<'a>( ); err.span_label(e.span, "positional arguments must be before named arguments"); for pos in names.values() { - err.span_label(args[pos.0].span, "named argument"); + err.span_label(args[pos.0].expr.span, "named argument"); } err.emit(); } - args.push(e); + args.push(FormatArg { expr: e, named: false }); } } } @@ -1214,7 +1219,7 @@ pub fn expand_preparsed_format_args( ecx: &mut ExtCtxt<'_>, sp: Span, efmt: P, - args: Vec>, + args: Vec, names: FxHashMap, append_newline: bool, ) -> P { @@ -1304,6 +1309,25 @@ pub fn expand_preparsed_format_args( e.span_label(fmt_span.from_inner(InnerSpan::new(span.start, span.end)), label); } } + if err.should_be_replaced_with_positional_argument { + let captured_arg_span = + fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end)); + let positional_args = args.iter().filter(|arg| !arg.named).collect::>(); + if let Ok(arg) = ecx.source_map().span_to_snippet(captured_arg_span) { + let span = match positional_args.last() { + Some(arg) => arg.expr.span, + None => fmt_sp, + }; + e.multipart_suggestion_verbose( + "consider using a positional formatting argument instead", + vec![ + (captured_arg_span, positional_args.len().to_string()), + (span.shrink_to_hi(), format!(", {}", arg)), + ], + Applicability::MachineApplicable, + ); + } + } e.emit(); return DummyResult::raw_expr(sp, true); } @@ -1318,7 +1342,7 @@ pub fn expand_preparsed_format_args( let mut cx = Context { ecx, - args, + args: args.into_iter().map(|arg| arg.expr).collect(), num_captured_args: 0, arg_types, arg_unique_types, diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index ba8222dc15218..936044fbe24b2 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -13,7 +13,7 @@ use rustc_middle::mir::pretty::display_allocation; use rustc_middle::traits::Reveal; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, subst::Subst, EarlyBinder, TyCtxt}; +use rustc_middle::ty::{self, subst::Subst, TyCtxt}; use rustc_span::source_map::Span; use rustc_target::abi::{self, Abi}; use std::borrow::Cow; @@ -45,7 +45,7 @@ fn eval_body_using_ecx<'mir, 'tcx>( "Unexpected DefKind: {:?}", ecx.tcx.def_kind(cid.instance.def_id()) ); - let layout = ecx.layout_of(EarlyBinder(body.return_ty()).subst(tcx, cid.instance.substs))?; + let layout = ecx.layout_of(body.bound_return_ty().subst(tcx, cid.instance.substs))?; assert!(!layout.is_unsized()); let ret = ecx.allocate(layout, MemoryKind::Stack)?; diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 53269d1852703..b6cf182916cb9 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -396,6 +396,7 @@ enum UnusedDelimsCtx { LetScrutineeExpr, ArrayLenExpr, AnonConst, + MatchArmExpr, } impl From for &'static str { @@ -414,6 +415,7 @@ impl From for &'static str { UnusedDelimsCtx::BlockRetValue => "block return value", UnusedDelimsCtx::LetScrutineeExpr => "`let` scrutinee expression", UnusedDelimsCtx::ArrayLenExpr | UnusedDelimsCtx::AnonConst => "const expression", + UnusedDelimsCtx::MatchArmExpr => "match arm expression", } } } @@ -805,6 +807,18 @@ impl EarlyLintPass for UnusedParens { } return; } + ExprKind::Match(ref _expr, ref arm) => { + for a in arm { + self.check_unused_delims_expr( + cx, + &a.body, + UnusedDelimsCtx::MatchArmExpr, + false, + None, + None, + ); + } + } _ => {} } diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index c333738ded458..5f5b5de790e43 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1311,10 +1311,15 @@ extern "C" LLVMTypeKind LLVMRustGetTypeKind(LLVMTypeRef Ty) { return LLVMBFloatTypeKind; case Type::X86_AMXTyID: return LLVMX86_AMXTypeKind; -#if LLVM_VERSION_GE(15, 0) +#if LLVM_VERSION_GE(15, 0) && LLVM_VERSION_LT(16, 0) case Type::DXILPointerTyID: report_fatal_error("Rust does not support DirectX typed pointers."); break; +#endif +#if LLVM_VERSION_GE(16, 0) + case Type::TypedPointerTyID: + report_fatal_error("Rust does not support typed pointers."); + break; #endif } report_fatal_error("Unhandled TypeID."); diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 64e158ba348fc..7ab71f9009d04 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -431,6 +431,12 @@ impl<'tcx> Body<'tcx> { self.local_decls[RETURN_PLACE].ty } + /// Returns the return type; it always return first element from `local_decls` array. + #[inline] + pub fn bound_return_ty(&self) -> ty::EarlyBinder> { + ty::EarlyBinder(self.local_decls[RETURN_PLACE].ty) + } + /// Gets the location of the terminator for the given block. #[inline] pub fn terminator_loc(&self, bb: BasicBlock) -> Location { diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 809406aff1878..2e596b275276e 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -563,7 +563,7 @@ impl<'tcx> AdtDef<'tcx> { /// /// Due to normalization being eager, this applies even if /// the associated type is behind a pointer (e.g., issue #31299). - pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> &'tcx [Ty<'tcx>] { - tcx.adt_sized_constraint(self.did()).0 + pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> ty::EarlyBinder<&'tcx [Ty<'tcx>]> { + ty::EarlyBinder(tcx.adt_sized_constraint(self.did()).0) } } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index fb0a4b4e8f402..52c3a38861e65 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2191,7 +2191,7 @@ impl<'tcx> Ty<'tcx> { ty::Tuple(tys) => tys.iter().all(|ty| ty.is_trivially_sized(tcx)), - ty::Adt(def, _substs) => def.sized_constraint(tcx).is_empty(), + ty::Adt(def, _substs) => def.sized_constraint(tcx).0.is_empty(), ty::Projection(_) | ty::Param(_) | ty::Opaque(..) => false, diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 4b5bf80c071a6..591bb7831b5b6 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -680,6 +680,24 @@ impl<'tcx> TyCtxt<'tcx> { pub fn bound_const_param_default(self, def_id: DefId) -> ty::EarlyBinder> { ty::EarlyBinder(self.const_param_default(def_id)) } + + pub fn bound_predicates_of( + self, + def_id: DefId, + ) -> ty::EarlyBinder> { + ty::EarlyBinder(self.predicates_of(def_id)) + } + + pub fn bound_explicit_predicates_of( + self, + def_id: DefId, + ) -> ty::EarlyBinder> { + ty::EarlyBinder(self.explicit_predicates_of(def_id)) + } + + pub fn bound_impl_subject(self, def_id: DefId) -> ty::EarlyBinder> { + ty::EarlyBinder(self.impl_subject(def_id)) + } } struct OpaqueTypeExpander<'tcx> { diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 98eb6e170ab76..8d6f8efb6003f 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -617,7 +617,7 @@ impl SplitVarLenSlice { // The only admissible fixed-length slice is one of the array size. Whether `max_slice` // is fixed-length or variable-length, it will be the only relevant slice to output // here. - Some(_) => (0..0), // empty range + Some(_) => 0..0, // empty range // We cover all arities in the range `(self.arity..infinity)`. We split that range into // two: lengths smaller than `max_slice.arity()` are treated independently as // fixed-lengths slices, and lengths above are captured by `max_slice`. diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index 85ad6b8f2feff..fbc0a767f0766 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -18,9 +18,7 @@ use rustc_middle::mir::{ }; use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout}; use rustc_middle::ty::subst::{InternalSubsts, Subst}; -use rustc_middle::ty::{ - self, ConstKind, EarlyBinder, Instance, ParamEnv, Ty, TyCtxt, TypeVisitable, -}; +use rustc_middle::ty::{self, ConstKind, Instance, ParamEnv, Ty, TyCtxt, TypeVisitable}; use rustc_span::{def_id::DefId, Span}; use rustc_target::abi::{self, HasDataLayout, Size, TargetDataLayout}; use rustc_target::spec::abi::Abi as CallAbi; @@ -387,7 +385,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { ); let ret_layout = ecx - .layout_of(EarlyBinder(body.return_ty()).subst(tcx, substs)) + .layout_of(body.bound_return_ty().subst(tcx, substs)) .ok() // Don't bother allocating memory for large values. // I don't know how return types can seem to be unsized but this happens in the diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index 3ae6a88a140ea..c2ea55af48a1e 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -23,8 +23,7 @@ use rustc_middle::mir::{ use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout}; use rustc_middle::ty::subst::{InternalSubsts, Subst}; use rustc_middle::ty::{ - self, ConstInt, ConstKind, EarlyBinder, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, - TypeVisitable, + self, ConstInt, ConstKind, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitable, }; use rustc_session::lint; use rustc_span::Span; @@ -196,7 +195,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { ); let ret_layout = ecx - .layout_of(EarlyBinder(body.return_ty()).subst(tcx, substs)) + .layout_of(body.bound_return_ty().subst(tcx, substs)) .ok() // Don't bother allocating memory for large values. // I don't know how return types can seem to be unsized but this happens in the diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 09329f18c679d..a2155ac1d1ad4 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -560,7 +560,8 @@ impl<'a> Parser<'a> { || (sm.is_multiline( self.prev_token.span.shrink_to_hi().until(self.token.span.shrink_to_lo()) ) && t == &token::Pound) - }) { + }) && !expected.contains(&TokenType::Token(token::Comma)) + { // Missing semicolon typo. This is triggered if the next token could either start a // new statement or is a block close. For example: // diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index a7ff9711691fb..4890fade50faf 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -175,6 +175,7 @@ pub struct ParseError { pub label: string::String, pub span: InnerSpan, pub secondary_label: Option<(string::String, InnerSpan)>, + pub should_be_replaced_with_positional_argument: bool, } /// The parser structure for interpreting the input format string. This is @@ -236,6 +237,8 @@ impl<'a> Iterator for Parser<'a> { lbrace_inner_offset.to(InnerOffset(rbrace_inner_offset.0 + 1)), ); } + } else { + self.suggest_positional_arg_instead_of_captured_arg(arg); } Some(NextArgument(arg)) } @@ -313,6 +316,7 @@ impl<'a> Parser<'a> { label: label.into(), span, secondary_label: None, + should_be_replaced_with_positional_argument: false, }); } @@ -336,6 +340,7 @@ impl<'a> Parser<'a> { label: label.into(), span, secondary_label: None, + should_be_replaced_with_positional_argument: false, }); } @@ -407,6 +412,7 @@ impl<'a> Parser<'a> { label, span: pos.to(pos), secondary_label, + should_be_replaced_with_positional_argument: false, }); None } @@ -434,6 +440,7 @@ impl<'a> Parser<'a> { label, span: pos.to(pos), secondary_label, + should_be_replaced_with_positional_argument: false, }); } else { self.err(description, format!("expected `{:?}`", c), pos.to(pos)); @@ -750,6 +757,34 @@ impl<'a> Parser<'a> { } if found { Some(cur) } else { None } } + + fn suggest_positional_arg_instead_of_captured_arg(&mut self, arg: Argument<'a>) { + if let Some(end) = self.consume_pos('.') { + let byte_pos = self.to_span_index(end); + let start = InnerOffset(byte_pos.0 + 1); + let field = self.argument(start); + // We can only parse `foo.bar` field access, any deeper nesting, + // or another type of expression, like method calls, are not supported + if !self.consume('}') { + return; + } + if let ArgumentNamed(_) = arg.position { + if let ArgumentNamed(_) = field.position { + self.errors.insert( + 0, + ParseError { + description: "field access isn't supported".to_string(), + note: None, + label: "not supported".to_string(), + span: InnerSpan::new(arg.position_span.start, field.position_span.end), + secondary_label: None, + should_be_replaced_with_positional_argument: true, + }, + ); + } + } + } + } } /// Finds the indices of all characters that have been processed and differ between the actual diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 6a4f582ac5044..adf47ece69d99 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -32,7 +32,7 @@ use rustc_middle::traits::select::OverflowError; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable}; -use rustc_middle::ty::{self, EarlyBinder, Term, ToPredicate, Ty, TyCtxt}; +use rustc_middle::ty::{self, Term, ToPredicate, Ty, TyCtxt}; use rustc_span::symbol::sym; use std::collections::BTreeMap; @@ -2005,16 +2005,16 @@ fn confirm_impl_candidate<'cx, 'tcx>( let substs = obligation.predicate.substs.rebase_onto(tcx, trait_def_id, substs); let substs = translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.defining_node); - let ty = tcx.type_of(assoc_ty.item.def_id); + let ty = tcx.bound_type_of(assoc_ty.item.def_id); let is_const = matches!(tcx.def_kind(assoc_ty.item.def_id), DefKind::AssocConst); - let term: ty::Term<'tcx> = if is_const { + let term: ty::EarlyBinder> = if is_const { let identity_substs = crate::traits::InternalSubsts::identity_for_item(tcx, assoc_ty.item.def_id); let did = ty::WithOptConstParam::unknown(assoc_ty.item.def_id); let kind = ty::ConstKind::Unevaluated(ty::Unevaluated::new(did, identity_substs)); - tcx.mk_const(ty::ConstS { ty, kind }).into() + ty.map_bound(|ty| tcx.mk_const(ty::ConstS { ty, kind }).into()) } else { - ty.into() + ty.map_bound(|ty| ty.into()) }; if substs.len() != tcx.generics_of(assoc_ty.item.def_id).count() { let err = tcx.ty_error_with_message( @@ -2024,7 +2024,7 @@ fn confirm_impl_candidate<'cx, 'tcx>( Progress { term: err.into(), obligations: nested } } else { assoc_ty_own_obligations(selcx, obligation, &mut nested); - Progress { term: EarlyBinder(term).subst(tcx, substs), obligations: nested } + Progress { term: term.subst(tcx, substs), obligations: nested } } } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index d7d29005f80fd..c01ac19799106 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1886,7 +1886,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let sized_crit = def.sized_constraint(self.tcx()); // (*) binder moved here Where(obligation.predicate.rebind({ - sized_crit.iter().map(|ty| EarlyBinder(*ty).subst(self.tcx(), substs)).collect() + sized_crit + .0 + .iter() + .map(|ty| sized_crit.rebind(*ty).subst(self.tcx(), substs)) + .collect() })) } @@ -2357,11 +2361,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // obligation will normalize to `<$0 as Iterator>::Item = $1` and // `$1: Copy`, so we must ensure the obligations are emitted in // that order. - let predicates = tcx.predicates_of(def_id); + let predicates = tcx.bound_predicates_of(def_id); debug!(?predicates); - assert_eq!(predicates.parent, None); - let mut obligations = Vec::with_capacity(predicates.predicates.len()); - for (predicate, span) in predicates.predicates { + assert_eq!(predicates.0.parent, None); + let mut obligations = Vec::with_capacity(predicates.0.predicates.len()); + for (predicate, span) in predicates.0.predicates { let span = *span; let cause = cause.clone().derived_cause(parent_trait_pred, |derived| { ImplDerivedObligation(Box::new(ImplDerivedObligationCause { @@ -2375,7 +2379,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { param_env, cause.clone(), recursion_depth, - EarlyBinder(*predicate).subst(tcx, substs), + predicates.rebind(*predicate).subst(tcx, substs), &mut obligations, ); obligations.push(Obligation { cause, recursion_depth, param_env, predicate }); diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index b9259196c48aa..d25006016629c 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -6,7 +6,7 @@ use smallvec::SmallVec; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::DefId; use rustc_middle::ty::subst::{GenericArg, Subst, SubstsRef}; -use rustc_middle::ty::{self, EarlyBinder, ImplSubject, ToPredicate, Ty, TyCtxt, TypeVisitable}; +use rustc_middle::ty::{self, ImplSubject, ToPredicate, Ty, TyCtxt, TypeVisitable}; use super::{Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext}; pub use rustc_infer::traits::{self, util::*}; @@ -200,8 +200,8 @@ pub fn impl_subject_and_oblig<'a, 'tcx>( impl_def_id: DefId, impl_substs: SubstsRef<'tcx>, ) -> (ImplSubject<'tcx>, impl Iterator>) { - let subject = selcx.tcx().impl_subject(impl_def_id); - let subject = EarlyBinder(subject).subst(selcx.tcx(), impl_substs); + let subject = selcx.tcx().bound_impl_subject(impl_def_id); + let subject = subject.subst(selcx.tcx(), impl_substs); let Normalized { value: subject, obligations: normalization_obligations1 } = super::normalize(selcx, param_env, ObligationCause::dummy(), subject); diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index 14a60ace44186..ff5ca0cbcb7b1 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -51,11 +51,11 @@ impl<'tcx> RustIrDatabase<'tcx> { where ty::Predicate<'tcx>: LowerInto<'tcx, std::option::Option>, { - self.interner - .tcx - .explicit_item_bounds(def_id) + let bounds = self.interner.tcx.bound_explicit_item_bounds(def_id); + bounds + .0 .iter() - .map(|(bound, _)| EarlyBinder(*bound).subst(self.interner.tcx, &bound_vars)) + .map(|(bound, _)| bounds.rebind(*bound).subst(self.interner.tcx, &bound_vars)) .filter_map(|bound| LowerInto::>::lower_into(bound, self.interner)) .collect() } @@ -268,21 +268,20 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t let where_clauses = self.where_clauses_for(def_id, bound_vars); - let sig = self.interner.tcx.fn_sig(def_id); + let sig = self.interner.tcx.bound_fn_sig(def_id); let (inputs_and_output, iobinders, _) = crate::chalk::lowering::collect_bound_vars( self.interner, self.interner.tcx, - EarlyBinder(sig.inputs_and_output()).subst(self.interner.tcx, bound_vars), + sig.map_bound(|s| s.inputs_and_output()).subst(self.interner.tcx, bound_vars), ); let argument_types = inputs_and_output[..inputs_and_output.len() - 1] .iter() - .map(|t| { - EarlyBinder(*t).subst(self.interner.tcx, &bound_vars).lower_into(self.interner) - }) + .map(|t| sig.rebind(*t).subst(self.interner.tcx, &bound_vars).lower_into(self.interner)) .collect(); - let return_type = EarlyBinder(inputs_and_output[inputs_and_output.len() - 1]) + let return_type = sig + .rebind(inputs_and_output[inputs_and_output.len() - 1]) .subst(self.interner.tcx, &bound_vars) .lower_into(self.interner); @@ -295,7 +294,7 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t }; Arc::new(chalk_solve::rust_ir::FnDefDatum { id: fn_def_id, - sig: sig.lower_into(self.interner), + sig: sig.0.lower_into(self.interner), binders: chalk_ir::Binders::new(binders, bound), }) } @@ -503,12 +502,14 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t let identity_substs = InternalSubsts::identity_for_item(self.interner.tcx, opaque_ty_id.0); + let explicit_item_bounds = self.interner.tcx.bound_explicit_item_bounds(opaque_ty_id.0); let bounds = - self.interner - .tcx - .explicit_item_bounds(opaque_ty_id.0) + explicit_item_bounds + .0 .iter() - .map(|(bound, _)| EarlyBinder(*bound).subst(self.interner.tcx, &bound_vars)) + .map(|(bound, _)| { + explicit_item_bounds.rebind(*bound).subst(self.interner.tcx, &bound_vars) + }) .map(|bound| { bound.fold_with(&mut ReplaceOpaqueTyFolder { tcx: self.interner.tcx, diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 7007e76b86e28..db0d45b86fc03 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -2,9 +2,7 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::ty::subst::Subst; -use rustc_middle::ty::{ - self, Binder, EarlyBinder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt, -}; +use rustc_middle::ty::{self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt}; use rustc_trait_selection::traits; fn sized_constraint_for_ty<'tcx>( @@ -33,8 +31,9 @@ fn sized_constraint_for_ty<'tcx>( let adt_tys = adt.sized_constraint(tcx); debug!("sized_constraint_for_ty({:?}) intermediate = {:?}", ty, adt_tys); adt_tys + .0 .iter() - .map(|ty| EarlyBinder(*ty).subst(tcx, substs)) + .map(|ty| adt_tys.rebind(*ty).subst(tcx, substs)) .flat_map(|ty| sized_constraint_for_ty(tcx, adtdef, ty)) .collect() } diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 95f327112253a..d0334cd0df7bb 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -15,8 +15,8 @@ use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst}; use rustc_middle::ty::trait_def::TraitSpecializationKind; use rustc_middle::ty::{ - self, AdtKind, DefIdTree, EarlyBinder, GenericParamDefKind, ToPredicate, Ty, TyCtxt, - TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor, + self, AdtKind, DefIdTree, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, + TypeSuperVisitable, TypeVisitable, TypeVisitor, }; use rustc_session::parse::feature_err; use rustc_span::symbol::{sym, Ident, Symbol}; @@ -1295,7 +1295,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id let infcx = wfcx.infcx; let tcx = wfcx.tcx(); - let predicates = tcx.predicates_of(def_id); + let predicates = tcx.bound_predicates_of(def_id.to_def_id()); let generics = tcx.generics_of(def_id); let is_our_default = |def: &ty::GenericParamDef| match def.kind { @@ -1392,6 +1392,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id // Now we build the substituted predicates. let default_obligations = predicates + .0 .predicates .iter() .flat_map(|&(pred, sp)| { @@ -1422,7 +1423,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id } let mut param_count = CountParams::default(); let has_region = pred.visit_with(&mut param_count).is_break(); - let substituted_pred = EarlyBinder(pred).subst(tcx, substs); + let substituted_pred = predicates.rebind(pred).subst(tcx, substs); // Don't check non-defaulted params, dependent defaults (including lifetimes) // or preds with multiple params. if substituted_pred.has_param_types_or_consts() @@ -1430,7 +1431,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id || has_region { None - } else if predicates.predicates.iter().any(|&(p, _)| p == substituted_pred) { + } else if predicates.0.predicates.iter().any(|&(p, _)| p == substituted_pred) { // Avoid duplication of predicates that contain no parameters, for example. None } else { @@ -1456,7 +1457,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id traits::Obligation::new(cause, wfcx.param_env, pred) }); - let predicates = predicates.instantiate_identity(tcx); + let predicates = predicates.0.instantiate_identity(tcx); let predicates = wfcx.normalize(span, None, predicates); diff --git a/src/ci/scripts/checkout-submodules.sh b/src/ci/scripts/checkout-submodules.sh index 3eb4b8f905832..f6cb8f8a6da65 100755 --- a/src/ci/scripts/checkout-submodules.sh +++ b/src/ci/scripts/checkout-submodules.sh @@ -36,10 +36,7 @@ function fetch_github_commit_archive { rm $cached } -# Archive downloads are temporarily disabled due to sudden 504 -# gateway timeout errors. -# included="src/llvm-project src/doc/book src/doc/rust-by-example" -included="" +included="src/llvm-project src/doc/book src/doc/rust-by-example" modules="$(git config --file .gitmodules --get-regexp '\.path$' | cut -d' ' -f2)" modules=($modules) use_git="" @@ -63,9 +60,9 @@ done retry sh -c "git submodule deinit -f $use_git && \ git submodule sync && \ git submodule update -j 16 --init --recursive --depth 1 $use_git" -# STATUS=0 -# for pid in ${bg_pids[*]} -# do -# wait $pid || STATUS=1 -# done -# exit ${STATUS} +STATUS=0 +for pid in ${bg_pids[*]} +do + wait $pid || STATUS=1 +done +exit ${STATUS} diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 5e81db363ee5c..790727c918a1f 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -956,7 +956,11 @@ fn clean_fn_decl_with_args<'tcx>( decl: &hir::FnDecl<'tcx>, args: Arguments, ) -> FnDecl { - FnDecl { inputs: args, output: decl.output.clean(cx), c_variadic: decl.c_variadic } + let output = match decl.output { + hir::FnRetTy::Return(typ) => Return(clean_ty(typ, cx)), + hir::FnRetTy::DefaultReturn(..) => DefaultReturn, + }; + FnDecl { inputs: args, output, c_variadic: decl.c_variadic } } fn clean_fn_decl_from_did_and_sig<'tcx>( @@ -991,27 +995,16 @@ fn clean_fn_decl_from_did_and_sig<'tcx>( } } -impl<'tcx> Clean<'tcx, FnRetTy> for hir::FnRetTy<'tcx> { - fn clean(&self, cx: &mut DocContext<'tcx>) -> FnRetTy { - match *self { - Self::Return(typ) => Return(clean_ty(typ, cx)), - Self::DefaultReturn(..) => DefaultReturn, - } - } -} - -impl<'tcx> Clean<'tcx, Path> for hir::TraitRef<'tcx> { - fn clean(&self, cx: &mut DocContext<'tcx>) -> Path { - let path = clean_path(self.path, cx); - register_res(cx, path.res); - path - } +fn clean_trait_ref<'tcx>(trait_ref: &hir::TraitRef<'tcx>, cx: &mut DocContext<'tcx>) -> Path { + let path = clean_path(trait_ref.path, cx); + register_res(cx, path.res); + path } impl<'tcx> Clean<'tcx, PolyTrait> for hir::PolyTraitRef<'tcx> { fn clean(&self, cx: &mut DocContext<'tcx>) -> PolyTrait { PolyTrait { - trait_: self.trait_ref.clean(cx), + trait_: clean_trait_ref(&self.trait_ref, cx), generic_params: self .bound_generic_params .iter() @@ -2000,7 +1993,7 @@ fn clean_impl<'tcx>( ) -> Vec { let tcx = cx.tcx; let mut ret = Vec::new(); - let trait_ = impl_.of_trait.as_ref().map(|t| t.clean(cx)); + let trait_ = impl_.of_trait.as_ref().map(|t| clean_trait_ref(t, cx)); let items = impl_.items.iter().map(|ii| tcx.hir().impl_item(ii.id).clean(cx)).collect::>(); let def_id = tcx.hir().local_def_id(hir_id); diff --git a/src/test/ui/fmt/struct-field-as-captured-argument.fixed b/src/test/ui/fmt/struct-field-as-captured-argument.fixed new file mode 100644 index 0000000000000..f7244f6744f3a --- /dev/null +++ b/src/test/ui/fmt/struct-field-as-captured-argument.fixed @@ -0,0 +1,18 @@ +// run-rustfix + +#[derive(Debug)] +struct Foo { + field: usize, +} + +fn main() { + let foo = Foo { field: 0 }; + let bar = 3; + format!("{0}", foo.field); //~ ERROR invalid format string: field access isn't supported + format!("{1} {} {bar}", "aa", foo.field); //~ ERROR invalid format string: field access isn't supported + format!("{2} {} {1} {bar}", "aa", "bb", foo.field); //~ ERROR invalid format string: field access isn't supported + format!("{1} {} {baz}", "aa", foo.field, baz = 3); //~ ERROR invalid format string: field access isn't supported + format!("{1:?} {} {baz}", "aa", foo.field, baz = 3); //~ ERROR invalid format string: field access isn't supported + format!("{1:#?} {} {baz}", "aa", foo.field, baz = 3); //~ ERROR invalid format string: field access isn't supported + format!("{1:.3} {} {baz}", "aa", foo.field, baz = 3); //~ ERROR invalid format string: field access isn't supported +} diff --git a/src/test/ui/fmt/struct-field-as-captured-argument.rs b/src/test/ui/fmt/struct-field-as-captured-argument.rs new file mode 100644 index 0000000000000..ab5f2552bd323 --- /dev/null +++ b/src/test/ui/fmt/struct-field-as-captured-argument.rs @@ -0,0 +1,18 @@ +// run-rustfix + +#[derive(Debug)] +struct Foo { + field: usize, +} + +fn main() { + let foo = Foo { field: 0 }; + let bar = 3; + format!("{foo.field}"); //~ ERROR invalid format string: field access isn't supported + format!("{foo.field} {} {bar}", "aa"); //~ ERROR invalid format string: field access isn't supported + format!("{foo.field} {} {1} {bar}", "aa", "bb"); //~ ERROR invalid format string: field access isn't supported + format!("{foo.field} {} {baz}", "aa", baz = 3); //~ ERROR invalid format string: field access isn't supported + format!("{foo.field:?} {} {baz}", "aa", baz = 3); //~ ERROR invalid format string: field access isn't supported + format!("{foo.field:#?} {} {baz}", "aa", baz = 3); //~ ERROR invalid format string: field access isn't supported + format!("{foo.field:.3} {} {baz}", "aa", baz = 3); //~ ERROR invalid format string: field access isn't supported +} diff --git a/src/test/ui/fmt/struct-field-as-captured-argument.stderr b/src/test/ui/fmt/struct-field-as-captured-argument.stderr new file mode 100644 index 0000000000000..7ea8b4068f272 --- /dev/null +++ b/src/test/ui/fmt/struct-field-as-captured-argument.stderr @@ -0,0 +1,79 @@ +error: invalid format string: field access isn't supported + --> $DIR/struct-field-as-captured-argument.rs:11:15 + | +LL | format!("{foo.field}"); + | ^^^^^^^^^ not supported in format string + | +help: consider using a positional formatting argument instead + | +LL | format!("{0}", foo.field); + | ~ +++++++++++ + +error: invalid format string: field access isn't supported + --> $DIR/struct-field-as-captured-argument.rs:12:15 + | +LL | format!("{foo.field} {} {bar}", "aa"); + | ^^^^^^^^^ not supported in format string + | +help: consider using a positional formatting argument instead + | +LL | format!("{1} {} {bar}", "aa", foo.field); + | ~ +++++++++++ + +error: invalid format string: field access isn't supported + --> $DIR/struct-field-as-captured-argument.rs:13:15 + | +LL | format!("{foo.field} {} {1} {bar}", "aa", "bb"); + | ^^^^^^^^^ not supported in format string + | +help: consider using a positional formatting argument instead + | +LL | format!("{2} {} {1} {bar}", "aa", "bb", foo.field); + | ~ +++++++++++ + +error: invalid format string: field access isn't supported + --> $DIR/struct-field-as-captured-argument.rs:14:15 + | +LL | format!("{foo.field} {} {baz}", "aa", baz = 3); + | ^^^^^^^^^ not supported in format string + | +help: consider using a positional formatting argument instead + | +LL | format!("{1} {} {baz}", "aa", foo.field, baz = 3); + | ~ +++++++++++ + +error: invalid format string: field access isn't supported + --> $DIR/struct-field-as-captured-argument.rs:15:15 + | +LL | format!("{foo.field:?} {} {baz}", "aa", baz = 3); + | ^^^^^^^^^ not supported in format string + | +help: consider using a positional formatting argument instead + | +LL | format!("{1:?} {} {baz}", "aa", foo.field, baz = 3); + | ~ +++++++++++ + +error: invalid format string: field access isn't supported + --> $DIR/struct-field-as-captured-argument.rs:16:15 + | +LL | format!("{foo.field:#?} {} {baz}", "aa", baz = 3); + | ^^^^^^^^^ not supported in format string + | +help: consider using a positional formatting argument instead + | +LL | format!("{1:#?} {} {baz}", "aa", foo.field, baz = 3); + | ~ +++++++++++ + +error: invalid format string: field access isn't supported + --> $DIR/struct-field-as-captured-argument.rs:17:15 + | +LL | format!("{foo.field:.3} {} {baz}", "aa", baz = 3); + | ^^^^^^^^^ not supported in format string + | +help: consider using a positional formatting argument instead + | +LL | format!("{1:.3} {} {baz}", "aa", foo.field, baz = 3); + | ~ +++++++++++ + +error: aborting due to 7 previous errors + diff --git a/src/test/ui/lint/unused/issue-92751.rs b/src/test/ui/lint/unused/issue-92751.rs new file mode 100644 index 0000000000000..2fb292736d136 --- /dev/null +++ b/src/test/ui/lint/unused/issue-92751.rs @@ -0,0 +1,9 @@ +#[deny(unused)] +pub fn broken(x: Option<()>) -> i32 { + match x { + Some(()) => (1), //~ ERROR unnecessary parentheses around match arm expression + None => (2), //~ ERROR unnecessary parentheses around match arm expression + } +} + +fn main() { } diff --git a/src/test/ui/lint/unused/issue-92751.stderr b/src/test/ui/lint/unused/issue-92751.stderr new file mode 100644 index 0000000000000..0a8d8e6729cf5 --- /dev/null +++ b/src/test/ui/lint/unused/issue-92751.stderr @@ -0,0 +1,32 @@ +error: unnecessary parentheses around match arm expression + --> $DIR/issue-92751.rs:4:21 + | +LL | Some(()) => (1), + | ^ ^ + | +note: the lint level is defined here + --> $DIR/issue-92751.rs:1:8 + | +LL | #[deny(unused)] + | ^^^^^^ + = note: `#[deny(unused_parens)]` implied by `#[deny(unused)]` +help: remove these parentheses + | +LL - Some(()) => (1), +LL + Some(()) => 1, + | + +error: unnecessary parentheses around match arm expression + --> $DIR/issue-92751.rs:5:17 + | +LL | None => (2), + | ^ ^ + | +help: remove these parentheses + | +LL - None => (2), +LL + None => 2, + | + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/parser/issues/issue-88770.rs b/src/test/ui/parser/issues/issue-88770.rs index bf89033f560e9..bb69951c7b4ea 100644 --- a/src/test/ui/parser/issues/issue-88770.rs +++ b/src/test/ui/parser/issues/issue-88770.rs @@ -3,7 +3,7 @@ // error-pattern:this file contains an unclosed delimiter // error-pattern:expected one of // error-pattern:missing `in` in `for` loop -// error-pattern:expected `;`, found `e` +// error-pattern:expected one of `!`, `)`, `,`, `.`, `::`, `;`, `?`, `{`, or an operator, found `e` fn m(){print!("",(c for&g u diff --git a/src/test/ui/parser/issues/issue-88770.stderr b/src/test/ui/parser/issues/issue-88770.stderr index c7e24155d1692..4e3a21613ec78 100644 --- a/src/test/ui/parser/issues/issue-88770.stderr +++ b/src/test/ui/parser/issues/issue-88770.stderr @@ -48,19 +48,13 @@ error: expected one of `!`, `)`, `,`, `.`, `::`, `?`, `{`, or an operator, found LL | fn m(){print!("",(c for&g | ^^^ expected one of 8 possible tokens -error: expected `;`, found `e` - --> $DIR/issue-88770.rs:10:2 +error: expected one of `!`, `)`, `,`, `.`, `::`, `;`, `?`, `{`, or an operator, found `e` + --> $DIR/issue-88770.rs:11:1 | LL | e - | ^ help: add `;` here + | - expected one of 9 possible tokens LL | e - | - unexpected token + | ^ unexpected token -error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `)` - --> $DIR/issue-88770.rs:11:3 - | -LL | e - | ^ expected one of 7 possible tokens - -error: aborting due to 7 previous errors +error: aborting due to 6 previous errors diff --git a/src/test/ui/parser/suggest-semi-in-array.rs b/src/test/ui/parser/suggest-semi-in-array.rs new file mode 100644 index 0000000000000..9ce2e59e53ba6 --- /dev/null +++ b/src/test/ui/parser/suggest-semi-in-array.rs @@ -0,0 +1,5 @@ +fn main() { + let v = [1 + 2]; + //~^ ERROR expected one of `,`, `.`, `;`, `?`, `]`, or an operator, found `2` +} diff --git a/src/test/ui/parser/suggest-semi-in-array.stderr b/src/test/ui/parser/suggest-semi-in-array.stderr new file mode 100644 index 0000000000000..d7cd6efae41d3 --- /dev/null +++ b/src/test/ui/parser/suggest-semi-in-array.stderr @@ -0,0 +1,10 @@ +error: expected one of `,`, `.`, `;`, `?`, `]`, or an operator, found `2` + --> $DIR/suggest-semi-in-array.rs:3:5 + | +LL | let v = [1 + | - expected one of `,`, `.`, `;`, `?`, `]`, or an operator +LL | 2]; + | ^ unexpected token + +error: aborting due to previous error +