diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs index 373c0ebcc5cba..ad92bf2cd4071 100644 --- a/compiler/rustc_ast/src/util/parser.rs +++ b/compiler/rustc_ast/src/util/parser.rs @@ -233,8 +233,7 @@ pub const PREC_JUMP: i8 = -30; pub const PREC_RANGE: i8 = -10; // The range 2..=14 is reserved for AssocOp binary operator precedences. pub const PREC_PREFIX: i8 = 50; -pub const PREC_POSTFIX: i8 = 60; -pub const PREC_PAREN: i8 = 99; +pub const PREC_UNAMBIGUOUS: i8 = 60; pub const PREC_FORCE_PAREN: i8 = 100; #[derive(Debug, Clone, Copy)] @@ -325,37 +324,35 @@ impl ExprPrecedence { | ExprPrecedence::Let | ExprPrecedence::Unary => PREC_PREFIX, - // Unary, postfix - ExprPrecedence::Await + // Never need parens + ExprPrecedence::Array + | ExprPrecedence::Await + | ExprPrecedence::Block | ExprPrecedence::Call - | ExprPrecedence::MethodCall + | ExprPrecedence::ConstBlock | ExprPrecedence::Field + | ExprPrecedence::ForLoop + | ExprPrecedence::FormatArgs + | ExprPrecedence::Gen + | ExprPrecedence::If | ExprPrecedence::Index - | ExprPrecedence::Try | ExprPrecedence::InlineAsm + | ExprPrecedence::Lit + | ExprPrecedence::Loop | ExprPrecedence::Mac - | ExprPrecedence::FormatArgs + | ExprPrecedence::Match + | ExprPrecedence::MethodCall | ExprPrecedence::OffsetOf - | ExprPrecedence::PostfixMatch => PREC_POSTFIX, - - // Never need parens - ExprPrecedence::Array + | ExprPrecedence::Paren + | ExprPrecedence::Path + | ExprPrecedence::PostfixMatch | ExprPrecedence::Repeat + | ExprPrecedence::Struct + | ExprPrecedence::Try + | ExprPrecedence::TryBlock | ExprPrecedence::Tup - | ExprPrecedence::Lit - | ExprPrecedence::Path - | ExprPrecedence::Paren - | ExprPrecedence::If | ExprPrecedence::While - | ExprPrecedence::ForLoop - | ExprPrecedence::Loop - | ExprPrecedence::Match - | ExprPrecedence::ConstBlock - | ExprPrecedence::Block - | ExprPrecedence::TryBlock - | ExprPrecedence::Gen - | ExprPrecedence::Struct - | ExprPrecedence::Err => PREC_PAREN, + | ExprPrecedence::Err => PREC_UNAMBIGUOUS, } } } diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index 52164d6ef1648..58f65f1257fc7 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -130,6 +130,9 @@ ast_lowering_never_pattern_with_guard = ast_lowering_no_precise_captures_on_apit = `use<...>` precise capturing syntax not allowed in argument-position `impl Trait` +ast_lowering_no_precise_captures_on_rpitit = `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits + .note = currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope + ast_lowering_previously_used_here = previously used here ast_lowering_register1 = register `{$reg1_name}` diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index d9dd0b3bca534..678cac210f413 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -66,14 +66,18 @@ impl<'hir> LoweringContext<'_, 'hir> { let Ok(sig_id) = sig_id else { return false; }; - if let Some(local_sig_id) = sig_id.as_local() { + self.has_self(sig_id, span) + } + + fn has_self(&self, def_id: DefId, span: Span) -> bool { + if let Some(local_sig_id) = def_id.as_local() { // The value may be missing due to recursive delegation. // Error will be emmited later during HIR ty lowering. self.resolver.delegation_fn_sigs.get(&local_sig_id).map_or(false, |sig| sig.has_self) } else { - match self.tcx.def_kind(sig_id) { + match self.tcx.def_kind(def_id) { DefKind::Fn => false, - DefKind::AssocFn => self.tcx.associated_item(sig_id).fn_has_self_parameter, + DefKind::AssocFn => self.tcx.associated_item(def_id).fn_has_self_parameter, _ => span_bug!(span, "unexpected DefKind for delegation item"), } } @@ -107,12 +111,17 @@ impl<'hir> LoweringContext<'_, 'hir> { span: Span, ) -> Result { let sig_id = if self.is_in_trait_impl { item_id } else { path_id }; - let sig_id = - self.resolver.get_partial_res(sig_id).and_then(|r| r.expect_full_res().opt_def_id()); - sig_id.ok_or_else(|| { - self.tcx - .dcx() - .span_delayed_bug(span, "LoweringContext: couldn't resolve delegation item") + self.get_resolution_id(sig_id, span) + } + + fn get_resolution_id(&self, node_id: NodeId, span: Span) -> Result { + let def_id = + self.resolver.get_partial_res(node_id).and_then(|r| r.expect_full_res().opt_def_id()); + def_id.ok_or_else(|| { + self.tcx.dcx().span_delayed_bug( + span, + format!("LoweringContext: couldn't resolve node {:?} in delegation item", node_id), + ) }) } @@ -122,7 +131,7 @@ impl<'hir> LoweringContext<'_, 'hir> { predicates: &[], has_where_clause_predicates: false, where_clause_span: span, - span: span, + span, }) } @@ -222,12 +231,7 @@ impl<'hir> LoweringContext<'_, 'hir> { })); let path = self.arena.alloc(hir::Path { span, res: Res::Local(param_id), segments }); - - hir::Expr { - hir_id: self.next_id(), - kind: hir::ExprKind::Path(hir::QPath::Resolved(None, path)), - span, - } + self.mk_expr(hir::ExprKind::Path(hir::QPath::Resolved(None, path)), span) } fn lower_delegation_body( @@ -236,19 +240,11 @@ impl<'hir> LoweringContext<'_, 'hir> { param_count: usize, span: Span, ) -> BodyId { - let path = self.lower_qpath( - delegation.id, - &delegation.qself, - &delegation.path, - ParamMode::Optional, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), - None, - ); let block = delegation.body.as_deref(); self.lower_body(|this| { - let mut parameters: Vec> = Vec::new(); - let mut args: Vec> = Vec::new(); + let mut parameters: Vec> = Vec::with_capacity(param_count); + let mut args: Vec> = Vec::with_capacity(param_count); for idx in 0..param_count { let (param, pat_node_id) = this.generate_param(span); @@ -264,11 +260,7 @@ impl<'hir> LoweringContext<'_, 'hir> { }; self_resolver.visit_block(block); let block = this.lower_block(block, false); - hir::Expr { - hir_id: this.next_id(), - kind: hir::ExprKind::Block(block, None), - span: block.span, - } + this.mk_expr(hir::ExprKind::Block(block, None), block.span) } else { let pat_hir_id = this.lower_node_id(pat_node_id); this.generate_arg(pat_hir_id, span) @@ -276,43 +268,41 @@ impl<'hir> LoweringContext<'_, 'hir> { args.push(arg); } - let args = self.arena.alloc_from_iter(args); - let final_expr = this.generate_call(path, args); + let final_expr = this.finalize_body_lowering(delegation, args, span); (this.arena.alloc_from_iter(parameters), final_expr) }) } - fn generate_call( + // Generates fully qualified call for the resulting body. + fn finalize_body_lowering( &mut self, - path: hir::QPath<'hir>, - args: &'hir [hir::Expr<'hir>], + delegation: &Delegation, + args: Vec>, + span: Span, ) -> hir::Expr<'hir> { - let callee = self.arena.alloc(hir::Expr { - hir_id: self.next_id(), - kind: hir::ExprKind::Path(path), - span: path.span(), - }); + let path = self.lower_qpath( + delegation.id, + &delegation.qself, + &delegation.path, + ParamMode::Optional, + ImplTraitContext::Disallowed(ImplTraitPosition::Path), + None, + ); - let expr = self.arena.alloc(hir::Expr { - hir_id: self.next_id(), - kind: hir::ExprKind::Call(callee, args), - span: path.span(), - }); + let args = self.arena.alloc_from_iter(args); + let path_expr = self.arena.alloc(self.mk_expr(hir::ExprKind::Path(path), span)); + let call = self.arena.alloc(self.mk_expr(hir::ExprKind::Call(path_expr, args), span)); let block = self.arena.alloc(hir::Block { stmts: &[], - expr: Some(expr), + expr: Some(call), hir_id: self.next_id(), rules: hir::BlockCheckMode::DefaultBlock, - span: path.span(), + span, targeted_by_break: false, }); - hir::Expr { - hir_id: self.next_id(), - kind: hir::ExprKind::Block(block, None), - span: path.span(), - } + self.mk_expr(hir::ExprKind::Block(block, None), span) } fn generate_delegation_error( @@ -333,11 +323,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let header = self.generate_header_error(); let sig = hir::FnSig { decl, header, span }; - let body_id = self.lower_body(|this| { - let expr = - hir::Expr { hir_id: this.next_id(), kind: hir::ExprKind::Err(err), span: span }; - (&[], expr) - }); + let body_id = self.lower_body(|this| (&[], this.mk_expr(hir::ExprKind::Err(err), span))); DelegationResults { generics, body_id, sig } } @@ -349,6 +335,11 @@ impl<'hir> LoweringContext<'_, 'hir> { abi: abi::Abi::Rust, } } + + #[inline] + fn mk_expr(&mut self, kind: hir::ExprKind<'hir>, span: Span) -> hir::Expr<'hir> { + hir::Expr { hir_id: self.next_id(), kind, span } + } } struct SelfResolver<'a> { diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 02744d16b422f..3d4b6a1f033fb 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -424,6 +424,14 @@ pub(crate) struct NoPreciseCapturesOnApit { pub span: Span, } +#[derive(Diagnostic)] +#[diag(ast_lowering_no_precise_captures_on_rpitit)] +#[note] +pub(crate) struct NoPreciseCapturesOnRpitit { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(ast_lowering_yield_in_closure)] pub(crate) struct YieldInClosure { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index da8682d3d095d..0a06304fcecfa 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1594,6 +1594,26 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }; debug!(?captured_lifetimes_to_duplicate); + match fn_kind { + // Deny `use<>` on RPITIT in trait/trait-impl for now. + Some(FnDeclKind::Trait | FnDeclKind::Impl) => { + if let Some(span) = bounds.iter().find_map(|bound| match *bound { + ast::GenericBound::Use(_, span) => Some(span), + _ => None, + }) { + self.tcx.dcx().emit_err(errors::NoPreciseCapturesOnRpitit { span }); + } + } + None + | Some( + FnDeclKind::Fn + | FnDeclKind::Inherent + | FnDeclKind::ExternFn + | FnDeclKind::Closure + | FnDeclKind::Pointer, + ) => {} + } + self.lower_opaque_inner( opaque_ty_node_id, origin, diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 1e117c46b6e29..f2f6594e6869d 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -217,7 +217,7 @@ impl<'a> State<'a> { fn print_expr_call(&mut self, func: &ast::Expr, args: &[P], fixup: FixupContext) { let prec = match func.kind { ast::ExprKind::Field(..) => parser::PREC_FORCE_PAREN, - _ => parser::PREC_POSTFIX, + _ => parser::PREC_UNAMBIGUOUS, }; // Independent of parenthesization related to precedence, we must @@ -257,7 +257,7 @@ impl<'a> State<'a> { // boundaries, `$receiver.method()` can be parsed back as a statement // containing an expression if and only if `$receiver` can be parsed as // a statement containing an expression. - self.print_expr_maybe_paren(receiver, parser::PREC_POSTFIX, fixup); + self.print_expr_maybe_paren(receiver, parser::PREC_UNAMBIGUOUS, fixup); self.word("."); self.print_ident(segment.ident); @@ -489,7 +489,7 @@ impl<'a> State<'a> { self.space(); } MatchKind::Postfix => { - self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX, fixup); + self.print_expr_maybe_paren(expr, parser::PREC_UNAMBIGUOUS, fixup); self.word_nbsp(".match"); } } @@ -549,7 +549,7 @@ impl<'a> State<'a> { self.print_block_with_attrs(blk, attrs); } ast::ExprKind::Await(expr, _) => { - self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX, fixup); + self.print_expr_maybe_paren(expr, parser::PREC_UNAMBIGUOUS, fixup); self.word(".await"); } ast::ExprKind::Assign(lhs, rhs, _) => { @@ -568,14 +568,14 @@ impl<'a> State<'a> { self.print_expr_maybe_paren(rhs, prec, fixup.subsequent_subexpression()); } ast::ExprKind::Field(expr, ident) => { - self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX, fixup); + self.print_expr_maybe_paren(expr, parser::PREC_UNAMBIGUOUS, fixup); self.word("."); self.print_ident(*ident); } ast::ExprKind::Index(expr, index, _) => { self.print_expr_maybe_paren( expr, - parser::PREC_POSTFIX, + parser::PREC_UNAMBIGUOUS, fixup.leftmost_subexpression(), ); self.word("["); @@ -713,7 +713,7 @@ impl<'a> State<'a> { } } ast::ExprKind::Try(e) => { - self.print_expr_maybe_paren(e, parser::PREC_POSTFIX, fixup); + self.print_expr_maybe_paren(e, parser::PREC_UNAMBIGUOUS, fixup); self.word("?") } ast::ExprKind::TryBlock(blk) => { diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 245ce790e4987..db78edc45b9de 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -1151,7 +1151,9 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { // Get the arguments for the found method, only specifying that `Self` is the receiver type. let Some(possible_rcvr_ty) = typeck_results.node_type_opt(rcvr.hir_id) else { return }; let args = GenericArgs::for_item(tcx, method_def_id, |param, _| { - if param.index == 0 { + if let ty::GenericParamDefKind::Lifetime = param.kind { + tcx.lifetimes.re_erased.into() + } else if param.index == 0 && param.name == kw::SelfUpper { possible_rcvr_ty.into() } else if param.index == closure_param.index { closure_ty.into() @@ -1168,7 +1170,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { Obligation::misc(tcx, span, self.mir_def_id(), self.param_env, pred) })); - if ocx.select_all_or_error().is_empty() { + if ocx.select_all_or_error().is_empty() && count > 0 { diag.span_suggestion_verbose( tcx.hir().body(*body).value.peel_blocks().span.shrink_to_lo(), "dereference the return value", diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 4d1b96d9c1bac..8469cbbbc7d61 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -211,11 +211,18 @@ fn missing_items_err( .collect::>() .join("`, `"); - // `Span` before impl block closing brace. - let hi = full_impl_span.hi() - BytePos(1); - // Point at the place right before the closing brace of the relevant `impl` to suggest - // adding the associated item at the end of its body. - let sugg_sp = full_impl_span.with_lo(hi).with_hi(hi); + let sugg_sp = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(full_impl_span) + && snippet.ends_with("}") + { + // `Span` before impl block closing brace. + let hi = full_impl_span.hi() - BytePos(1); + // Point at the place right before the closing brace of the relevant `impl` to suggest + // adding the associated item at the end of its body. + full_impl_span.with_lo(hi).with_hi(hi) + } else { + full_impl_span.shrink_to_hi() + }; + // Obtain the level of indentation ending in `sugg_sp`. let padding = tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(|| String::new()); diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index b21f1eadfb7a3..25b0cbdc026af 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1120,7 +1120,7 @@ impl<'a> State<'a> { fn print_expr_call(&mut self, func: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { let prec = match func.kind { hir::ExprKind::Field(..) => parser::PREC_FORCE_PAREN, - _ => parser::PREC_POSTFIX, + _ => parser::PREC_UNAMBIGUOUS, }; self.print_expr_maybe_paren(func, prec); @@ -1134,7 +1134,7 @@ impl<'a> State<'a> { args: &[hir::Expr<'_>], ) { let base_args = args; - self.print_expr_maybe_paren(receiver, parser::PREC_POSTFIX); + self.print_expr_maybe_paren(receiver, parser::PREC_UNAMBIGUOUS); self.word("."); self.print_ident(segment.ident); @@ -1478,12 +1478,12 @@ impl<'a> State<'a> { self.print_expr_maybe_paren(rhs, prec); } hir::ExprKind::Field(expr, ident) => { - self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX); + self.print_expr_maybe_paren(expr, parser::PREC_UNAMBIGUOUS); self.word("."); self.print_ident(ident); } hir::ExprKind::Index(expr, index, _) => { - self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX); + self.print_expr_maybe_paren(expr, parser::PREC_UNAMBIGUOUS); self.word("["); self.print_expr(index); self.word("]"); diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 46c855155753d..3b199b7e3c26d 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -3,7 +3,7 @@ use super::method::MethodCallee; use super::{Expectation, FnCtxt, TupleArgumentsFlag}; use crate::errors; -use rustc_ast::util::parser::PREC_POSTFIX; +use rustc_ast::util::parser::PREC_UNAMBIGUOUS; use rustc_errors::{Applicability, Diag, ErrorGuaranteed, StashKey}; use rustc_hir::def::{self, CtorKind, Namespace, Res}; use rustc_hir::def_id::DefId; @@ -656,7 +656,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if let Ok(rest_snippet) = rest_snippet { - let sugg = if callee_expr.precedence().order() >= PREC_POSTFIX { + let sugg = if callee_expr.precedence().order() >= PREC_UNAMBIGUOUS { vec![ (up_to_rcvr_span, "".to_string()), (rest_span, format!(".{}({rest_snippet}", segment.ident)), diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 5870851028215..92f2d3254bb22 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -946,7 +946,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { fn lossy_provenance_ptr2int_lint(&self, fcx: &FnCtxt<'a, 'tcx>, t_c: ty::cast::IntTy) { let expr_prec = self.expr.precedence().order(); - let needs_parens = expr_prec < rustc_ast::util::parser::PREC_POSTFIX; + let needs_parens = expr_prec < rustc_ast::util::parser::PREC_UNAMBIGUOUS; let needs_cast = !matches!(t_c, ty::cast::IntTy::U(ty::UintTy::Usize)); let cast_span = self.expr_span.shrink_to_hi().to(self.cast_span); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index b3ebc0621cbd6..8d380caf91628 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -9,7 +9,7 @@ use crate::method::probe::{IsSuggestion, Mode, ProbeScope}; use core::cmp::min; use core::iter; use hir::def_id::LocalDefId; -use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX}; +use rustc_ast::util::parser::{ExprPrecedence, PREC_UNAMBIGUOUS}; use rustc_data_structures::packed::Pu128; use rustc_errors::{Applicability, Diag, MultiSpan}; use rustc_hir as hir; @@ -1329,7 +1329,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let span = expr.span.find_oldest_ancestor_in_same_ctxt(); - let mut sugg = if expr.precedence().order() >= PREC_POSTFIX { + let mut sugg = if expr.precedence().order() >= PREC_UNAMBIGUOUS { vec![(span.shrink_to_hi(), ".into()".to_owned())] } else { vec![ @@ -2868,7 +2868,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "change the type of the numeric literal from `{checked_ty}` to `{expected_ty}`", ); - let close_paren = if expr.precedence().order() < PREC_POSTFIX { + let close_paren = if expr.precedence().order() < PREC_UNAMBIGUOUS { sugg.push((expr.span.shrink_to_lo(), "(".to_string())); ")" } else { @@ -2893,7 +2893,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let len = src.trim_end_matches(&checked_ty.to_string()).len(); expr.span.with_lo(expr.span.lo() + BytePos(len as u32)) }, - if expr.precedence().order() < PREC_POSTFIX { + if expr.precedence().order() < PREC_UNAMBIGUOUS { // Readd `)` format!("{expected_ty})") } else { diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index 74c65e93616eb..13b145296a7c9 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -209,8 +209,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } (Some(ty), _) if self.same_type_modulo_infer(ty, exp_found.found) => match cause.code() { - ObligationCauseCode::Pattern { span: Some(then_span), .. } => { - Some(ConsiderAddingAwait::FutureSugg { span: then_span.shrink_to_hi() }) + ObligationCauseCode::Pattern { span: Some(then_span), origin_expr, .. } => { + origin_expr.then_some(ConsiderAddingAwait::FutureSugg { + span: then_span.shrink_to_hi(), + }) } ObligationCauseCode::IfExpression(box IfExpressionCause { then_id, .. }) => { let then_span = self.find_block_span_from_hir_id(*then_id); diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 68244136d1adf..932406fd1aaf2 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -358,8 +358,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { where 'a: 'pat, { - // Assemble a list of candidates: there is one candidate per pattern, - // which means there may be more than one candidate *per arm*. + // Assemble the initial list of candidates. These top-level candidates + // are 1:1 with the original match arms, but other parts of match + // lowering also introduce subcandidates (for subpatterns), and will + // also flatten candidates in some cases. So in general a list of + // candidates does _not_ necessarily correspond to a list of arms. arms.iter() .copied() .map(|arm| { @@ -1031,6 +1034,12 @@ impl<'tcx> PatternExtraData<'tcx> { } /// A pattern in a form suitable for generating code. +/// +/// Here, "flat" indicates that the pattern's match pairs have been recursively +/// simplified by [`Builder::simplify_match_pairs`]. They are not necessarily +/// flat in an absolute sense. +/// +/// Will typically be incorporated into a [`Candidate`]. #[derive(Debug, Clone)] struct FlatPat<'pat, 'tcx> { /// To match the pattern, all of these must be satisfied... @@ -1042,23 +1051,25 @@ struct FlatPat<'pat, 'tcx> { } impl<'tcx, 'pat> FlatPat<'pat, 'tcx> { + /// Creates a `FlatPat` containing a simplified [`MatchPair`] list/forest + /// for the given pattern. fn new( place: PlaceBuilder<'tcx>, pattern: &'pat Pat<'tcx>, cx: &mut Builder<'_, 'tcx>, ) -> Self { - let is_never = pattern.is_never_pattern(); - let mut flat_pat = FlatPat { - match_pairs: vec![MatchPair::new(place, pattern, cx)], - extra_data: PatternExtraData { - span: pattern.span, - bindings: Vec::new(), - ascriptions: Vec::new(), - is_never, - }, + // First, recursively build a tree of match pairs for the given pattern. + let mut match_pairs = vec![MatchPair::new(place, pattern, cx)]; + let mut extra_data = PatternExtraData { + span: pattern.span, + bindings: Vec::new(), + ascriptions: Vec::new(), + is_never: pattern.is_never_pattern(), }; - cx.simplify_match_pairs(&mut flat_pat.match_pairs, &mut flat_pat.extra_data); - flat_pat + // Partly-flatten and sort the match pairs, while recording extra data. + cx.simplify_match_pairs(&mut match_pairs, &mut extra_data); + + Self { match_pairs, extra_data } } } @@ -1104,9 +1115,12 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> { has_guard: bool, cx: &mut Builder<'_, 'tcx>, ) -> Self { + // Use `FlatPat` to build simplified match pairs, then immediately + // incorporate them into a new candidate. Self::from_flat_pat(FlatPat::new(place, pattern, cx), has_guard) } + /// Incorporates an already-simplified [`FlatPat`] into a new candidate. fn from_flat_pat(flat_pat: FlatPat<'pat, 'tcx>, has_guard: bool) -> Self { Candidate { match_pairs: flat_pat.match_pairs, diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index 50f4ca2d819d3..630d0b9438dca 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -95,6 +95,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { + /// Recursively builds a `MatchPair` tree for the given pattern and its + /// subpatterns. pub(in crate::build) fn new( mut place_builder: PlaceBuilder<'tcx>, pattern: &'pat Pat<'tcx>, diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 7c7700dd85963..a51b8dea4ea20 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -155,7 +155,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { fn handle_res(&mut self, res: Res) { match res { - Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::TyAlias, def_id) => { + Res::Def( + DefKind::Const | DefKind::AssocConst | DefKind::AssocTy | DefKind::TyAlias, + def_id, + ) => { self.check_def_id(def_id); } _ if self.in_pat => {} @@ -441,7 +444,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { intravisit::walk_item(self, item) } hir::ItemKind::ForeignMod { .. } => {} - hir::ItemKind::Trait(..) => { + hir::ItemKind::Trait(_, _, _, _, trait_item_refs) => { for impl_def_id in self.tcx.all_impls(item.owner_id.to_def_id()) { if let Some(local_def_id) = impl_def_id.as_local() && let ItemKind::Impl(impl_ref) = @@ -454,7 +457,12 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { intravisit::walk_path(self, impl_ref.of_trait.unwrap().path); } } - + // mark assoc ty live if the trait is live + for trait_item in trait_item_refs { + if let hir::AssocItemKind::Type = trait_item.kind { + self.check_def_id(trait_item.id.owner_id.to_def_id()); + } + } intravisit::walk_item(self, item) } _ => intravisit::walk_item(self, item), @@ -471,9 +479,8 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { && let ItemKind::Impl(impl_ref) = self.tcx.hir().expect_item(local_impl_id).kind { - if !matches!(trait_item.kind, hir::TraitItemKind::Type(..)) - && !ty_ref_to_pub_struct(self.tcx, impl_ref.self_ty) - .ty_and_all_fields_are_public + if !ty_ref_to_pub_struct(self.tcx, impl_ref.self_ty) + .ty_and_all_fields_are_public { // skip impl-items of non pure pub ty, // cause we don't know the ty is constructed or not, @@ -812,9 +819,8 @@ fn check_item<'tcx>( // for trait impl blocks, // mark the method live if the self_ty is public, // or the method is public and may construct self - if of_trait && matches!(tcx.def_kind(local_def_id), DefKind::AssocTy) - || tcx.visibility(local_def_id).is_public() - && (ty_and_all_fields_are_public || may_construct_self) + if tcx.visibility(local_def_id).is_public() + && (ty_and_all_fields_are_public || may_construct_self) { // if the impl item is public, // and the ty may be constructed or can be constructed in foreign crates, @@ -851,10 +857,13 @@ fn check_trait_item( worklist: &mut Vec<(LocalDefId, ComesFromAllowExpect)>, id: hir::TraitItemId, ) { - use hir::TraitItemKind::{Const, Fn}; - if matches!(tcx.def_kind(id.owner_id), DefKind::AssocConst | DefKind::AssocFn) { + use hir::TraitItemKind::{Const, Fn, Type}; + if matches!( + tcx.def_kind(id.owner_id), + DefKind::AssocConst | DefKind::AssocTy | DefKind::AssocFn + ) { let trait_item = tcx.hir().trait_item(id); - if matches!(trait_item.kind, Const(_, Some(_)) | Fn(..)) + if matches!(trait_item.kind, Const(_, Some(_)) | Type(_, Some(_)) | Fn(..)) && let Some(comes_from_allow) = has_allow_dead_code_or_lang_attr(tcx, trait_item.owner_id.def_id) { @@ -896,7 +905,7 @@ fn create_and_seed_worklist( // checks impls, impl-items and pub structs with all public fields later match tcx.def_kind(id) { DefKind::Impl { .. } => false, - DefKind::AssocConst | DefKind::AssocFn => !matches!(tcx.associated_item(id).container, AssocItemContainer::ImplContainer), + DefKind::AssocConst | DefKind::AssocTy | DefKind::AssocFn => !matches!(tcx.associated_item(id).container, AssocItemContainer::ImplContainer), DefKind::Struct => struct_all_fields_are_public(tcx, id.to_def_id()) || has_allow_dead_code_or_lang_attr(tcx, id).is_some(), _ => true }) @@ -1183,6 +1192,7 @@ impl<'tcx> DeadVisitor<'tcx> { } match self.tcx.def_kind(def_id) { DefKind::AssocConst + | DefKind::AssocTy | DefKind::AssocFn | DefKind::Fn | DefKind::Static { .. } @@ -1224,15 +1234,14 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) { || (def_kind == DefKind::Trait && live_symbols.contains(&item.owner_id.def_id)) { for &def_id in tcx.associated_item_def_ids(item.owner_id.def_id) { - // We have diagnosed unused assoc consts and fns in traits + // We have diagnosed unused assocs in traits if matches!(def_kind, DefKind::Impl { of_trait: true }) - && matches!(tcx.def_kind(def_id), DefKind::AssocConst | DefKind::AssocFn) + && matches!(tcx.def_kind(def_id), DefKind::AssocConst | DefKind::AssocTy | DefKind::AssocFn) // skip unused public inherent methods, // cause we have diagnosed unconstructed struct || matches!(def_kind, DefKind::Impl { of_trait: false }) && tcx.visibility(def_id).is_public() && ty_ref_to_pub_struct(tcx, tcx.hir().item(item).expect_impl().self_ty).ty_is_public - || def_kind == DefKind::Trait && tcx.def_kind(def_id) == DefKind::AssocTy { continue; } diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs index 618897b3ababd..6d1f10f521176 100644 --- a/library/core/src/ffi/mod.rs +++ b/library/core/src/ffi/mod.rs @@ -484,7 +484,7 @@ mod sealed_trait { all supported platforms", issue = "44930" )] - pub trait VaArgSafe {} + pub unsafe trait VaArgSafe {} } macro_rules! impl_va_arg_safe { @@ -494,7 +494,7 @@ macro_rules! impl_va_arg_safe { reason = "the `c_variadic` feature has not been properly tested on \ all supported platforms", issue = "44930")] - impl sealed_trait::VaArgSafe for $t {} + unsafe impl sealed_trait::VaArgSafe for $t {} )+ } } @@ -509,14 +509,15 @@ impl_va_arg_safe! {f64} all supported platforms", issue = "44930" )] -impl sealed_trait::VaArgSafe for *mut T {} +unsafe impl sealed_trait::VaArgSafe for *mut T {} + #[unstable( feature = "c_variadic", reason = "the `c_variadic` feature has not been properly tested on \ all supported platforms", issue = "44930" )] -impl sealed_trait::VaArgSafe for *const T {} +unsafe impl sealed_trait::VaArgSafe for *const T {} #[unstable( feature = "c_variadic", diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 6b5054a9f0612..9ba1c6a415470 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2579,7 +2579,7 @@ extern "rust-intrinsic" { /// fn runtime() -> i32 { 1 } /// const fn compiletime() -> i32 { 2 } /// -// // ⚠ This code violates the required equivalence of `compiletime` +/// // ⚠ This code violates the required equivalence of `compiletime` /// // and `runtime`. /// const_eval_select((), compiletime, runtime) /// } diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index f6b9de26c1c4d..4a417c84a30a5 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -552,10 +552,20 @@ impl OsString { OsStr::from_inner_mut(self.inner.leak()) } - /// Part of a hack to make PathBuf::push/pop more efficient. + /// Provides plumbing to core `Vec::truncate`. + /// More well behaving alternative to allowing outer types + /// full mutable access to the core `Vec`. #[inline] - pub(crate) fn as_mut_vec_for_path_buf(&mut self) -> &mut Vec { - self.inner.as_mut_vec_for_path_buf() + pub(crate) fn truncate(&mut self, len: usize) { + self.inner.truncate(len); + } + + /// Provides plumbing to core `Vec::extend_from_slice`. + /// More well behaving alternative to allowing outer types + /// full mutable access to the core `Vec`. + #[inline] + pub(crate) fn extend_from_slice(&mut self, other: &[u8]) { + self.inner.extend_from_slice(other); } } diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 72073d1328023..caae8f924d2b1 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1163,11 +1163,6 @@ pub struct PathBuf { } impl PathBuf { - #[inline] - fn as_mut_vec(&mut self) -> &mut Vec { - self.inner.as_mut_vec_for_path_buf() - } - /// Allocates an empty `PathBuf`. /// /// # Examples @@ -1290,7 +1285,8 @@ impl PathBuf { fn _push(&mut self, path: &Path) { // in general, a separator is needed if the rightmost byte is not a separator - let mut need_sep = self.as_mut_vec().last().map(|c| !is_sep_byte(*c)).unwrap_or(false); + let buf = self.inner.as_encoded_bytes(); + let mut need_sep = buf.last().map(|c| !is_sep_byte(*c)).unwrap_or(false); // in the special case of `C:` on Windows, do *not* add a separator let comps = self.components(); @@ -1304,7 +1300,7 @@ impl PathBuf { // absolute `path` replaces `self` if path.is_absolute() || path.prefix().is_some() { - self.as_mut_vec().truncate(0); + self.inner.truncate(0); // verbatim paths need . and .. removed } else if comps.prefix_verbatim() && !path.inner.is_empty() { @@ -1349,7 +1345,7 @@ impl PathBuf { // `path` has a root but no prefix, e.g., `\windows` (Windows only) } else if path.has_root() { let prefix_len = self.components().prefix_remaining(); - self.as_mut_vec().truncate(prefix_len); + self.inner.truncate(prefix_len); // `path` is a pure relative path } else if need_sep { @@ -1382,7 +1378,7 @@ impl PathBuf { pub fn pop(&mut self) -> bool { match self.parent().map(|p| p.as_u8_slice().len()) { Some(len) => { - self.as_mut_vec().truncate(len); + self.inner.truncate(len); true } None => false, @@ -1510,15 +1506,14 @@ impl PathBuf { // truncate until right after the file stem let end_file_stem = file_stem[file_stem.len()..].as_ptr().addr(); let start = self.inner.as_encoded_bytes().as_ptr().addr(); - let v = self.as_mut_vec(); - v.truncate(end_file_stem.wrapping_sub(start)); + self.inner.truncate(end_file_stem.wrapping_sub(start)); // add the new extension, if any - let new = extension.as_encoded_bytes(); + let new = extension; if !new.is_empty() { - v.reserve_exact(new.len() + 1); - v.push(b'.'); - v.extend_from_slice(new); + self.inner.reserve_exact(new.len() + 1); + self.inner.push(OsStr::new(".")); + self.inner.push(new); } true @@ -2645,18 +2640,18 @@ impl Path { None => { // Enough capacity for the extension and the dot let capacity = self_len + extension.len() + 1; - let whole_path = self_bytes.iter(); + let whole_path = self_bytes; (capacity, whole_path) } Some(previous_extension) => { let capacity = self_len + extension.len() - previous_extension.len(); - let path_till_dot = self_bytes[..self_len - previous_extension.len()].iter(); + let path_till_dot = &self_bytes[..self_len - previous_extension.len()]; (capacity, path_till_dot) } }; let mut new_path = PathBuf::with_capacity(new_capacity); - new_path.as_mut_vec().extend(slice_to_copy); + new_path.inner.extend_from_slice(slice_to_copy); new_path.set_extension(extension); new_path } diff --git a/library/std/src/sys/os_str/bytes.rs b/library/std/src/sys/os_str/bytes.rs index f7c6b0877aa62..2a7477e3afc20 100644 --- a/library/std/src/sys/os_str/bytes.rs +++ b/library/std/src/sys/os_str/bytes.rs @@ -202,10 +202,20 @@ impl Buf { self.as_slice().into_rc() } - /// Part of a hack to make PathBuf::push/pop more efficient. + /// Provides plumbing to core `Vec::truncate`. + /// More well behaving alternative to allowing outer types + /// full mutable access to the core `Vec`. #[inline] - pub(crate) fn as_mut_vec_for_path_buf(&mut self) -> &mut Vec { - &mut self.inner + pub(crate) fn truncate(&mut self, len: usize) { + self.inner.truncate(len); + } + + /// Provides plumbing to core `Vec::extend_from_slice`. + /// More well behaving alternative to allowing outer types + /// full mutable access to the core `Vec`. + #[inline] + pub(crate) fn extend_from_slice(&mut self, other: &[u8]) { + self.inner.extend_from_slice(other); } } diff --git a/library/std/src/sys/os_str/wtf8.rs b/library/std/src/sys/os_str/wtf8.rs index 96690f8c44e9c..edb923a47501c 100644 --- a/library/std/src/sys/os_str/wtf8.rs +++ b/library/std/src/sys/os_str/wtf8.rs @@ -165,10 +165,20 @@ impl Buf { self.as_slice().into_rc() } - /// Part of a hack to make PathBuf::push/pop more efficient. + /// Provides plumbing to core `Vec::truncate`. + /// More well behaving alternative to allowing outer types + /// full mutable access to the core `Vec`. #[inline] - pub(crate) fn as_mut_vec_for_path_buf(&mut self) -> &mut Vec { - self.inner.as_mut_vec_for_path_buf() + pub(crate) fn truncate(&mut self, len: usize) { + self.inner.truncate(len); + } + + /// Provides plumbing to core `Vec::extend_from_slice`. + /// More well behaving alternative to allowing outer types + /// full mutable access to the core `Vec`. + #[inline] + pub(crate) fn extend_from_slice(&mut self, other: &[u8]) { + self.inner.extend_from_slice(other); } } diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs index 84128a4b595f7..708f62f476e73 100644 --- a/library/std/src/sys_common/wtf8.rs +++ b/library/std/src/sys_common/wtf8.rs @@ -474,13 +474,13 @@ impl Wtf8Buf { Wtf8Buf { bytes: bytes.into_vec(), is_known_utf8: false } } - /// Part of a hack to make PathBuf::push/pop more efficient. + /// Provides plumbing to core `Vec::extend_from_slice`. + /// More well behaving alternative to allowing outer types + /// full mutable access to the core `Vec`. #[inline] - pub(crate) fn as_mut_vec_for_path_buf(&mut self) -> &mut Vec { - // FIXME: this function should not even exist, as it implies violating Wtf8Buf invariants - // For now, simply assume that is about to happen. - self.is_known_utf8 = false; - &mut self.bytes + pub(crate) fn extend_from_slice(&mut self, other: &[u8]) { + self.bytes.extend_from_slice(other); + self.is_known_utf8 = self.is_known_utf8 || self.next_surrogate(0).is_none(); } } diff --git a/src/ci/docker/host-x86_64/disabled/riscv64gc-gnu/Dockerfile b/src/ci/docker/host-x86_64/disabled/riscv64gc-gnu/Dockerfile index a9ffa5918b5bc..a52c3839196f7 100644 --- a/src/ci/docker/host-x86_64/disabled/riscv64gc-gnu/Dockerfile +++ b/src/ci/docker/host-x86_64/disabled/riscv64gc-gnu/Dockerfile @@ -91,7 +91,9 @@ RUN sh /scripts/sccache.sh # Avoid "fatal: detected dubious ownership in repository at '/checkout'" error RUN git config --global --add safe.directory /checkout -ENV RUST_CONFIGURE_ARGS --qemu-riscv64-rootfs=/tmp/rootfs +ENV RUST_CONFIGURE_ARGS \ + --qemu-riscv64-rootfs=/tmp/rootfs \ + --set target.riscv64gc-unknown-linux-gnu.linker=riscv64-linux-gnu-gcc ENV SCRIPT python3 ../x.py --stage 2 test --host='' --target riscv64gc-unknown-linux-gnu ENV NO_CHANGE_USER=1 diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index d60320d828253..f451758c33507 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -6,7 +6,7 @@ use clippy_utils::{ expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, DefinedTy, ExprUseNode, }; use core::mem; -use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX}; +use rustc_ast::util::parser::{PREC_UNAMBIGUOUS, PREC_PREFIX}; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_ty, Visitor}; @@ -1013,7 +1013,7 @@ fn report<'tcx>( let (precedence, calls_field) = match cx.tcx.parent_hir_node(data.first_expr.hir_id) { Node::Expr(e) => match e.kind { ExprKind::Call(callee, _) if callee.hir_id != data.first_expr.hir_id => (0, false), - ExprKind::Call(..) => (PREC_POSTFIX, matches!(expr.kind, ExprKind::Field(..))), + ExprKind::Call(..) => (PREC_UNAMBIGUOUS, matches!(expr.kind, ExprKind::Field(..))), _ => (e.precedence().order(), false), }, _ => (0, false), @@ -1160,7 +1160,7 @@ impl<'tcx> Dereferencing<'tcx> { }, Some(parent) if !parent.span.from_expansion() => { // Double reference might be needed at this point. - if parent.precedence().order() == PREC_POSTFIX { + if parent.precedence().order() == PREC_UNAMBIGUOUS { // Parentheses would be needed here, don't lint. *outer_pat = None; } else { diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs index 183caab56c59a..be80aebed6dfb 100644 --- a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs +++ b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs @@ -7,7 +7,7 @@ use clippy_utils::{ can_move_expr_to_closure, is_else_clause, is_lint_allowed, is_res_lang_ctor, path_res, path_to_local_id, peel_blocks, peel_hir_expr_refs, peel_hir_expr_while, CaptureKind, }; -use rustc_ast::util::parser::PREC_POSTFIX; +use rustc_ast::util::parser::PREC_UNAMBIGUOUS; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::LangItem::{OptionNone, OptionSome}; @@ -117,7 +117,7 @@ where // it's being passed by value. let scrutinee = peel_hir_expr_refs(scrutinee).0; let (scrutinee_str, _) = snippet_with_context(cx, scrutinee.span, expr_ctxt, "..", &mut app); - let scrutinee_str = if scrutinee.span.eq_ctxt(expr.span) && scrutinee.precedence().order() < PREC_POSTFIX { + let scrutinee_str = if scrutinee.span.eq_ctxt(expr.span) && scrutinee.precedence().order() < PREC_UNAMBIGUOUS { format!("({scrutinee_str})") } else { scrutinee_str.into() diff --git a/src/tools/run-make-support/src/llvm.rs b/src/tools/run-make-support/src/llvm.rs index 7f42223bf7f5a..4c9e9a5323025 100644 --- a/src/tools/run-make-support/src/llvm.rs +++ b/src/tools/run-make-support/src/llvm.rs @@ -180,6 +180,13 @@ impl LlvmFilecheck { self.cmd.arg(path.as_ref()); self } + + /// `--input-file` option. + pub fn input_file>(&mut self, input_file: P) -> &mut Self { + self.cmd.arg("--input-file"); + self.cmd.arg(input_file.as_ref()); + self + } } impl LlvmObjdump { diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 07073ef5d40c7..53e2662fa9fe0 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -92,7 +92,6 @@ run-make/link-cfg/Makefile run-make/link-framework/Makefile run-make/link-path-order/Makefile run-make/linkage-attr-on-static/Makefile -run-make/llvm-ident/Makefile run-make/long-linker-command-lines-cmd-exe/Makefile run-make/long-linker-command-lines/Makefile run-make/longjmp-across-rust/Makefile diff --git a/tests/run-make/llvm-ident/Makefile b/tests/run-make/llvm-ident/Makefile deleted file mode 100644 index e583e6018e0bf..0000000000000 --- a/tests/run-make/llvm-ident/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -include ../tools.mk - -# only-linux - -all: - # `-Ccodegen-units=16 -Copt-level=2` is used here to trigger thin LTO - # across codegen units to test deduplication of the named metadata - # (see `LLVMRustPrepareThinLTOImport` for details). - echo 'fn main(){}' | $(RUSTC) - --emit=link,obj -Csave-temps -Ccodegen-units=16 -Copt-level=2 --target=$(TARGET) - - # `llvm-dis` is used here since `--emit=llvm-ir` does not emit LLVM IR - # for temporary outputs. - "$(LLVM_BIN_DIR)"/llvm-dis $(TMPDIR)/*.bc - - # Check LLVM IR files (including temporary outputs) have `!llvm.ident` - # named metadata, reusing the related codegen test. - set -e; for f in $(TMPDIR)/*.ll; do \ - $(LLVM_FILECHECK) --input-file $$f ../../codegen/llvm-ident.rs; \ - done diff --git a/tests/run-make/llvm-ident/rmake.rs b/tests/run-make/llvm-ident/rmake.rs new file mode 100644 index 0000000000000..1ca0d96778f3e --- /dev/null +++ b/tests/run-make/llvm-ident/rmake.rs @@ -0,0 +1,40 @@ +//@ only-linux + +use run_make_support::llvm::llvm_bin_dir; +use run_make_support::{cmd, env_var, llvm_filecheck, read_dir, rustc, source_root}; + +use std::ffi::OsStr; + +fn main() { + // `-Ccodegen-units=16 -Copt-level=2` is used here to trigger thin LTO + // across codegen units to test deduplication of the named metadata + // (see `LLVMRustPrepareThinLTOImport` for details). + rustc() + .emit("link,obj") + .arg("-Csave-temps") + .codegen_units(16) + .opt_level("2") + .target(&env_var("TARGET")) + .arg("-") + .stdin("fn main(){}") + .run(); + + // `llvm-dis` is used here since `--emit=llvm-ir` does not emit LLVM IR + // for temporary outputs. + let mut files = Vec::new(); + read_dir(".", |path| { + if path.is_file() && path.extension().is_some_and(|ext| ext == OsStr::new("bc")) { + files.push(path.to_path_buf()); + } + }); + cmd(llvm_bin_dir().join("llvm-dis")).args(&files).run(); + + // Check LLVM IR files (including temporary outputs) have `!llvm.ident` + // named metadata, reusing the related codegen test. + let llvm_ident_path = source_root().join("tests/codegen/llvm-ident.rs"); + read_dir(".", |path| { + if path.is_file() && path.extension().is_some_and(|ext| ext == OsStr::new("ll")) { + llvm_filecheck().input_file(path).arg(&llvm_ident_path).run(); + } + }); +} diff --git a/tests/ui/async-await/suggest-missing-await.rs b/tests/ui/async-await/suggest-missing-await.rs index 96996af0bd2d8..0bd67cec335bd 100644 --- a/tests/ui/async-await/suggest-missing-await.rs +++ b/tests/ui/async-await/suggest-missing-await.rs @@ -71,4 +71,11 @@ async fn suggest_await_in_generic_pattern() { } } +// Issue #126903 +async fn do_async() {} +fn dont_suggest_awaiting_closure_patterns() { + Some(do_async()).map(|()| {}); + //~^ ERROR mismatched types [E0308] +} + fn main() {} diff --git a/tests/ui/async-await/suggest-missing-await.stderr b/tests/ui/async-await/suggest-missing-await.stderr index f0ec34a6a5557..f9db86ea40a93 100644 --- a/tests/ui/async-await/suggest-missing-await.stderr +++ b/tests/ui/async-await/suggest-missing-await.stderr @@ -133,6 +133,18 @@ help: consider `await`ing on the `Future` LL | match dummy_result().await { | ++++++ -error: aborting due to 7 previous errors +error[E0308]: mismatched types + --> $DIR/suggest-missing-await.rs:77:27 + | +LL | Some(do_async()).map(|()| {}); + | ^^ + | | + | expected future, found `()` + | expected due to this + | + = note: expected opaque type `impl Future` + found unit type `()` + +error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/cross_crate_complex.rs b/tests/ui/const-generics/cross_crate_complex.rs index d13b69aa0cfb4..b44d889f5e99e 100644 --- a/tests/ui/const-generics/cross_crate_complex.rs +++ b/tests/ui/const-generics/cross_crate_complex.rs @@ -11,6 +11,7 @@ async fn foo() { async_in_foo(async_out_foo::<4>().await).await; } +#[allow(dead_code)] struct Faz; impl Foo for Faz {} diff --git a/tests/ui/delegation/explicit-paths.stderr b/tests/ui/delegation/explicit-paths.stderr index 30891c94c0e98..d33c5da4377b1 100644 --- a/tests/ui/delegation/explicit-paths.stderr +++ b/tests/ui/delegation/explicit-paths.stderr @@ -110,10 +110,10 @@ error[E0308]: mismatched types --> $DIR/explicit-paths.rs:78:30 | LL | reuse ::foo1; - | ---------------^^^^ - | | | - | | expected `&S2`, found `&S` - | arguments to this function are incorrect + | ^^^^ + | | + | expected `&S2`, found `&S` + | arguments to this function are incorrect | = note: expected reference `&S2` found reference `&S` diff --git a/tests/ui/generic-associated-types/missing-bounds.fixed b/tests/ui/generic-associated-types/missing-bounds.fixed index 703d3c1e0fb17..ff69016d8626d 100644 --- a/tests/ui/generic-associated-types/missing-bounds.fixed +++ b/tests/ui/generic-associated-types/missing-bounds.fixed @@ -2,6 +2,7 @@ use std::ops::Add; +#[allow(dead_code)] struct A(B); impl Add for A where B: Add { @@ -12,6 +13,7 @@ impl Add for A where B: Add { } } +#[allow(dead_code)] struct C(B); impl> Add for C { @@ -22,6 +24,7 @@ impl> Add for C { } } +#[allow(dead_code)] struct D(B); impl> Add for D { @@ -32,6 +35,7 @@ impl> Add for D { } } +#[allow(dead_code)] struct E(B); impl> Add for E where B: Add { diff --git a/tests/ui/generic-associated-types/missing-bounds.rs b/tests/ui/generic-associated-types/missing-bounds.rs index f40b422887311..1f83356c2fa6b 100644 --- a/tests/ui/generic-associated-types/missing-bounds.rs +++ b/tests/ui/generic-associated-types/missing-bounds.rs @@ -2,6 +2,7 @@ use std::ops::Add; +#[allow(dead_code)] struct A(B); impl Add for A where B: Add { @@ -12,6 +13,7 @@ impl Add for A where B: Add { } } +#[allow(dead_code)] struct C(B); impl Add for C { @@ -22,6 +24,7 @@ impl Add for C { } } +#[allow(dead_code)] struct D(B); impl Add for D { @@ -32,6 +35,7 @@ impl Add for D { } } +#[allow(dead_code)] struct E(B); impl Add for E where ::Output = B { diff --git a/tests/ui/generic-associated-types/missing-bounds.stderr b/tests/ui/generic-associated-types/missing-bounds.stderr index 1d7d80d1b0768..0f0dc24c06c0f 100644 --- a/tests/ui/generic-associated-types/missing-bounds.stderr +++ b/tests/ui/generic-associated-types/missing-bounds.stderr @@ -1,5 +1,5 @@ error: equality constraints are not yet supported in `where` clauses - --> $DIR/missing-bounds.rs:37:33 + --> $DIR/missing-bounds.rs:41:33 | LL | impl Add for E where ::Output = B { | ^^^^^^^^^^^^^^^^^^^^^^ not supported @@ -11,7 +11,7 @@ LL | impl Add for E where B: Add { | ~~~~~~~~~~~~~~~~~~ error[E0308]: mismatched types - --> $DIR/missing-bounds.rs:11:11 + --> $DIR/missing-bounds.rs:12:11 | LL | impl Add for A where B: Add { | - expected this type parameter @@ -24,14 +24,14 @@ LL | A(self.0 + rhs.0) = note: expected type parameter `B` found associated type `::Output` help: the type constructed contains `::Output` due to the type of the argument passed - --> $DIR/missing-bounds.rs:11:9 + --> $DIR/missing-bounds.rs:12:9 | LL | A(self.0 + rhs.0) | ^^--------------^ | | | this argument influences the type of `A` note: tuple struct defined here - --> $DIR/missing-bounds.rs:5:8 + --> $DIR/missing-bounds.rs:6:8 | LL | struct A(B); | ^ @@ -41,7 +41,7 @@ LL | impl Add for A where B: Add { | ++++++++++++ error[E0308]: mismatched types - --> $DIR/missing-bounds.rs:21:14 + --> $DIR/missing-bounds.rs:23:14 | LL | impl Add for C { | - expected this type parameter @@ -54,7 +54,7 @@ LL | Self(self.0 + rhs.0) = note: expected type parameter `B` found associated type `::Output` note: tuple struct defined here - --> $DIR/missing-bounds.rs:15:8 + --> $DIR/missing-bounds.rs:17:8 | LL | struct C(B); | ^ @@ -64,7 +64,7 @@ LL | impl> Add for C { | ++++++++++++ error[E0369]: cannot add `B` to `B` - --> $DIR/missing-bounds.rs:31:21 + --> $DIR/missing-bounds.rs:34:21 | LL | Self(self.0 + rhs.0) | ------ ^ ----- B @@ -77,7 +77,7 @@ LL | impl> Add for D { | +++++++++++++++++++++++++++ error[E0308]: mismatched types - --> $DIR/missing-bounds.rs:42:14 + --> $DIR/missing-bounds.rs:46:14 | LL | impl Add for E where ::Output = B { | - expected this type parameter @@ -90,7 +90,7 @@ LL | Self(self.0 + rhs.0) = note: expected type parameter `B` found associated type `::Output` note: tuple struct defined here - --> $DIR/missing-bounds.rs:35:8 + --> $DIR/missing-bounds.rs:39:8 | LL | struct E(B); | ^ diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs index 0801498578398..0028a45cbf3f2 100644 --- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs +++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs @@ -6,6 +6,7 @@ fn type_param() -> impl Sized + use<> {} trait Foo { fn bar() -> impl Sized + use<>; //~^ ERROR `impl Trait` must mention the `Self` type of the trait + //~| ERROR `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits } fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr index 93b44a0c18c27..89bd4df443106 100644 --- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr +++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr @@ -1,3 +1,11 @@ +error: `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits + --> $DIR/forgot-to-capture-type.rs:7:30 + | +LL | fn bar() -> impl Sized + use<>; + | ^^^^^ + | + = note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope + error: `impl Trait` must mention all type parameters in scope in `use<...>` --> $DIR/forgot-to-capture-type.rs:3:23 | @@ -18,5 +26,5 @@ LL | fn bar() -> impl Sized + use<>; | = note: currently, all type parameters are required to be mentioned in the precise captures list -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors diff --git a/tests/ui/impl-trait/precise-capturing/redundant.normal.stderr b/tests/ui/impl-trait/precise-capturing/redundant.normal.stderr new file mode 100644 index 0000000000000..44bc9f7daad8d --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/redundant.normal.stderr @@ -0,0 +1,20 @@ +warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant + --> $DIR/redundant.rs:7:19 + | +LL | fn hello<'a>() -> impl Sized + use<'a> {} + | ^^^^^^^^^^^^^------- + | | + | help: remove the `use<...>` syntax + | + = note: `#[warn(impl_trait_redundant_captures)]` on by default + +warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant + --> $DIR/redundant.rs:12:27 + | +LL | fn inherent(&self) -> impl Sized + use<'_> {} + | ^^^^^^^^^^^^^------- + | | + | help: remove the `use<...>` syntax + +warning: 2 warnings emitted + diff --git a/tests/ui/impl-trait/precise-capturing/redundant.rpitit.stderr b/tests/ui/impl-trait/precise-capturing/redundant.rpitit.stderr new file mode 100644 index 0000000000000..9aa73353126cd --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/redundant.rpitit.stderr @@ -0,0 +1,18 @@ +error: `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits + --> $DIR/redundant.rs:18:35 + | +LL | fn in_trait() -> impl Sized + use<'a, Self>; + | ^^^^^^^^^^^^^ + | + = note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope + +error: `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits + --> $DIR/redundant.rs:23:35 + | +LL | fn in_trait() -> impl Sized + use<'a> {} + | ^^^^^^^ + | + = note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope + +error: aborting due to 2 previous errors + diff --git a/tests/ui/impl-trait/precise-capturing/redundant.rs b/tests/ui/impl-trait/precise-capturing/redundant.rs index 99c128fdc4823..ef4f05bd7e458 100644 --- a/tests/ui/impl-trait/precise-capturing/redundant.rs +++ b/tests/ui/impl-trait/precise-capturing/redundant.rs @@ -1,24 +1,27 @@ //@ compile-flags: -Zunstable-options --edition=2024 -//@ check-pass +//@ revisions: normal rpitit +//@[normal] check-pass #![feature(precise_capturing)] fn hello<'a>() -> impl Sized + use<'a> {} -//~^ WARN all possible in-scope parameters are already captured +//[normal]~^ WARN all possible in-scope parameters are already captured struct Inherent; impl Inherent { fn inherent(&self) -> impl Sized + use<'_> {} - //~^ WARN all possible in-scope parameters are already captured + //[normal]~^ WARN all possible in-scope parameters are already captured } +#[cfg(rpitit)] trait Test<'a> { fn in_trait() -> impl Sized + use<'a, Self>; - //~^ WARN all possible in-scope parameters are already captured + //[rpitit]~^ ERROR `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits } +#[cfg(rpitit)] impl<'a> Test<'a> for () { fn in_trait() -> impl Sized + use<'a> {} - //~^ WARN all possible in-scope parameters are already captured + //[rpitit]~^ ERROR `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits } fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/redundant.stderr b/tests/ui/impl-trait/precise-capturing/redundant.stderr deleted file mode 100644 index 274d9d2375f7d..0000000000000 --- a/tests/ui/impl-trait/precise-capturing/redundant.stderr +++ /dev/null @@ -1,36 +0,0 @@ -warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant - --> $DIR/redundant.rs:6:19 - | -LL | fn hello<'a>() -> impl Sized + use<'a> {} - | ^^^^^^^^^^^^^------- - | | - | help: remove the `use<...>` syntax - | - = note: `#[warn(impl_trait_redundant_captures)]` on by default - -warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant - --> $DIR/redundant.rs:11:27 - | -LL | fn inherent(&self) -> impl Sized + use<'_> {} - | ^^^^^^^^^^^^^------- - | | - | help: remove the `use<...>` syntax - -warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant - --> $DIR/redundant.rs:16:22 - | -LL | fn in_trait() -> impl Sized + use<'a, Self>; - | ^^^^^^^^^^^^^------------- - | | - | help: remove the `use<...>` syntax - -warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant - --> $DIR/redundant.rs:20:22 - | -LL | fn in_trait() -> impl Sized + use<'a> {} - | ^^^^^^^^^^^^^------- - | | - | help: remove the `use<...>` syntax - -warning: 4 warnings emitted - diff --git a/tests/ui/impl-trait/precise-capturing/rpitit.rs b/tests/ui/impl-trait/precise-capturing/rpitit.rs new file mode 100644 index 0000000000000..4eb053573e1f2 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/rpitit.rs @@ -0,0 +1,21 @@ +//@ known-bug: unknown + +// RPITITs don't have variances in their GATs, so they always relate invariantly +// and act as if they capture all their args. +// To fix this soundly, we need to make sure that all the trait header args +// remain captured, since they affect trait selection. + +#![feature(precise_capturing)] + +trait Foo<'a> { + fn hello() -> impl PartialEq + use; +} + +fn test<'a, 'b, T: for<'r> Foo<'r>>() { + PartialEq::eq( + &>::hello(), + &>::hello(), + ); +} + +fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/rpitit.stderr b/tests/ui/impl-trait/precise-capturing/rpitit.stderr new file mode 100644 index 0000000000000..45eceef2f494b --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/rpitit.stderr @@ -0,0 +1,50 @@ +error: `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits + --> $DIR/rpitit.rs:11:36 + | +LL | fn hello() -> impl PartialEq + use; + | ^^^^^^^^^ + | + = note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope + +error: `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list + --> $DIR/rpitit.rs:11:19 + | +LL | trait Foo<'a> { + | -- this lifetime parameter is captured +LL | fn hello() -> impl PartialEq + use; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime captured due to being mentioned in the bounds of the `impl Trait` + +error: lifetime may not live long enough + --> $DIR/rpitit.rs:15:5 + | +LL | fn test<'a, 'b, T: for<'r> Foo<'r>>() { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | / PartialEq::eq( +LL | | &>::hello(), +LL | | &>::hello(), +LL | | ); + | |_____^ argument requires that `'a` must outlive `'b` + | + = help: consider adding the following bound: `'a: 'b` + +error: lifetime may not live long enough + --> $DIR/rpitit.rs:15:5 + | +LL | fn test<'a, 'b, T: for<'r> Foo<'r>>() { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | / PartialEq::eq( +LL | | &>::hello(), +LL | | &>::hello(), +LL | | ); + | |_____^ argument requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + +help: `'a` and `'b` must be the same: replace one with the other + +error: aborting due to 4 previous errors + diff --git a/tests/ui/impl-trait/precise-capturing/self-capture.rs b/tests/ui/impl-trait/precise-capturing/self-capture.rs index e0a4a8b658c5c..07bb417f9f7f1 100644 --- a/tests/ui/impl-trait/precise-capturing/self-capture.rs +++ b/tests/ui/impl-trait/precise-capturing/self-capture.rs @@ -1,9 +1,8 @@ -//@ check-pass - #![feature(precise_capturing)] trait Foo { fn bar<'a>() -> impl Sized + use; + //~^ ERROR `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits } fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/self-capture.stderr b/tests/ui/impl-trait/precise-capturing/self-capture.stderr new file mode 100644 index 0000000000000..351de86dd5fa6 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/self-capture.stderr @@ -0,0 +1,10 @@ +error: `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits + --> $DIR/self-capture.rs:4:34 + | +LL | fn bar<'a>() -> impl Sized + use; + | ^^^^^^^^^ + | + = note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope + +error: aborting due to 1 previous error + diff --git a/tests/ui/lint/dead-code/unused-trait-with-assoc-ty.rs b/tests/ui/lint/dead-code/unused-trait-with-assoc-ty.rs new file mode 100644 index 0000000000000..e8116d83ebf1c --- /dev/null +++ b/tests/ui/lint/dead-code/unused-trait-with-assoc-ty.rs @@ -0,0 +1,11 @@ +#![deny(dead_code)] + +struct T1; //~ ERROR struct `T1` is never constructed + +trait Foo { type Unused; } //~ ERROR trait `Foo` is never used +impl Foo for T1 { type Unused = Self; } + +pub trait Bar { type Used; } +impl Bar for T1 { type Used = Self; } + +fn main() {} diff --git a/tests/ui/lint/dead-code/unused-trait-with-assoc-ty.stderr b/tests/ui/lint/dead-code/unused-trait-with-assoc-ty.stderr new file mode 100644 index 0000000000000..ab73c64063431 --- /dev/null +++ b/tests/ui/lint/dead-code/unused-trait-with-assoc-ty.stderr @@ -0,0 +1,20 @@ +error: struct `T1` is never constructed + --> $DIR/unused-trait-with-assoc-ty.rs:3:8 + | +LL | struct T1; + | ^^ + | +note: the lint level is defined here + --> $DIR/unused-trait-with-assoc-ty.rs:1:9 + | +LL | #![deny(dead_code)] + | ^^^^^^^^^ + +error: trait `Foo` is never used + --> $DIR/unused-trait-with-assoc-ty.rs:5:7 + | +LL | trait Foo { type Unused; } + | ^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/pattern/issue-22546.rs b/tests/ui/pattern/issue-22546.rs index fd1d5fb6c4775..d5c5b68be78d7 100644 --- a/tests/ui/pattern/issue-22546.rs +++ b/tests/ui/pattern/issue-22546.rs @@ -15,7 +15,7 @@ impl Foo { } } -trait Tr { //~ WARN trait `Tr` is never used +trait Tr { type U; } diff --git a/tests/ui/pattern/issue-22546.stderr b/tests/ui/pattern/issue-22546.stderr deleted file mode 100644 index e067a95e4226c..0000000000000 --- a/tests/ui/pattern/issue-22546.stderr +++ /dev/null @@ -1,10 +0,0 @@ -warning: trait `Tr` is never used - --> $DIR/issue-22546.rs:18:7 - | -LL | trait Tr { - | ^^ - | - = note: `#[warn(dead_code)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/regions/account-for-lifetimes-in-closure-suggestion.rs b/tests/ui/regions/account-for-lifetimes-in-closure-suggestion.rs new file mode 100644 index 0000000000000..2de92cf62da1a --- /dev/null +++ b/tests/ui/regions/account-for-lifetimes-in-closure-suggestion.rs @@ -0,0 +1,19 @@ +// #125634 +struct Thing; + +// Invariant in 'a, Covariant in 'b +struct TwoThings<'a, 'b>(*mut &'a (), &'b mut ()); + +impl Thing { + fn enter_scope<'a>(self, _scope: impl for<'b> FnOnce(TwoThings<'a, 'b>)) {} +} + +fn foo() { + Thing.enter_scope(|ctx| { + SameLifetime(ctx); //~ ERROR lifetime may not live long enough + }); +} + +struct SameLifetime<'a>(TwoThings<'a, 'a>); + +fn main() {} diff --git a/tests/ui/regions/account-for-lifetimes-in-closure-suggestion.stderr b/tests/ui/regions/account-for-lifetimes-in-closure-suggestion.stderr new file mode 100644 index 0000000000000..5e158f59cdc6f --- /dev/null +++ b/tests/ui/regions/account-for-lifetimes-in-closure-suggestion.stderr @@ -0,0 +1,17 @@ +error: lifetime may not live long enough + --> $DIR/account-for-lifetimes-in-closure-suggestion.rs:13:22 + | +LL | Thing.enter_scope(|ctx| { + | --- + | | + | has type `TwoThings<'_, '1>` + | has type `TwoThings<'2, '_>` +LL | SameLifetime(ctx); + | ^^^ this usage requires that `'1` must outlive `'2` + | + = note: requirement occurs because of the type `TwoThings<'_, '_>`, which makes the generic argument `'_` invariant + = note: the struct `TwoThings<'a, 'b>` is invariant over the parameter `'a` + = help: see for more information about variance + +error: aborting due to 1 previous error + diff --git a/tests/crashes/124563.rs b/tests/ui/regions/lifetime-not-long-enough-suggestion-regression-test-124563.rs similarity index 72% rename from tests/crashes/124563.rs rename to tests/ui/regions/lifetime-not-long-enough-suggestion-regression-test-124563.rs index b082739af53d9..23427838ceb73 100644 --- a/tests/crashes/124563.rs +++ b/tests/ui/regions/lifetime-not-long-enough-suggestion-regression-test-124563.rs @@ -1,5 +1,4 @@ -//@ known-bug: rust-lang/rust#124563 - +// #124563 use std::marker::PhantomData; pub trait Trait {} @@ -17,11 +16,11 @@ where T: Trait, { type Trait = T; - type Bar = BarImpl<'a, 'b, T>; + type Bar = BarImpl<'a, 'b, T>; //~ ERROR lifetime bound not satisfied fn foo(&mut self) { - self.enter_scope(|ctx| { - BarImpl(ctx); + self.enter_scope(|ctx| { //~ ERROR lifetime may not live long enough + BarImpl(ctx); //~ ERROR lifetime may not live long enough }); } } @@ -44,3 +43,5 @@ where { type Foo = FooImpl<'a, 'b, T>; } + +fn main() {} diff --git a/tests/ui/regions/lifetime-not-long-enough-suggestion-regression-test-124563.stderr b/tests/ui/regions/lifetime-not-long-enough-suggestion-regression-test-124563.stderr new file mode 100644 index 0000000000000..fcd0a232a7bd3 --- /dev/null +++ b/tests/ui/regions/lifetime-not-long-enough-suggestion-regression-test-124563.stderr @@ -0,0 +1,49 @@ +error[E0478]: lifetime bound not satisfied + --> $DIR/lifetime-not-long-enough-suggestion-regression-test-124563.rs:19:16 + | +LL | type Bar = BarImpl<'a, 'b, T>; + | ^^^^^^^^^^^^^^^^^^ + | +note: lifetime parameter instantiated with the lifetime `'a` as defined here + --> $DIR/lifetime-not-long-enough-suggestion-regression-test-124563.rs:14:6 + | +LL | impl<'a, 'b, T> Foo for FooImpl<'a, 'b, T> + | ^^ +note: but lifetime parameter must outlive the lifetime `'b` as defined here + --> $DIR/lifetime-not-long-enough-suggestion-regression-test-124563.rs:14:10 + | +LL | impl<'a, 'b, T> Foo for FooImpl<'a, 'b, T> + | ^^ + +error: lifetime may not live long enough + --> $DIR/lifetime-not-long-enough-suggestion-regression-test-124563.rs:23:21 + | +LL | self.enter_scope(|ctx| { + | --- + | | + | has type `&'1 mut FooImpl<'_, '_, T>` + | has type `&mut FooImpl<'2, '_, T>` +LL | BarImpl(ctx); + | ^^^ this usage requires that `'1` must outlive `'2` + +error: lifetime may not live long enough + --> $DIR/lifetime-not-long-enough-suggestion-regression-test-124563.rs:22:9 + | +LL | impl<'a, 'b, T> Foo for FooImpl<'a, 'b, T> + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | / self.enter_scope(|ctx| { +LL | | BarImpl(ctx); +LL | | }); + | |__________^ argument requires that `'a` must outlive `'b` + | + = help: consider adding the following bound: `'a: 'b` + = note: requirement occurs because of a mutable reference to `FooImpl<'_, '_, T>` + = note: mutable references are invariant over their type parameter + = help: see for more information about variance + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0478`. diff --git a/tests/ui/regions/regions-escape-method.fixed b/tests/ui/regions/regions-escape-method.fixed new file mode 100644 index 0000000000000..f192dca1e25f0 --- /dev/null +++ b/tests/ui/regions/regions-escape-method.fixed @@ -0,0 +1,17 @@ +// Test a method call where the parameter `B` would (illegally) be +// inferred to a region bound in the method argument. If this program +// were accepted, then the closure passed to `s.f` could escape its +// argument. +//@ run-rustfix + +struct S; + +impl S { + fn f(&self, _: F) where F: FnOnce(&i32) -> B { + } +} + +fn main() { + let s = S; + s.f(|p| *p) //~ ERROR lifetime may not live long enough +} diff --git a/tests/ui/regions/regions-escape-method.rs b/tests/ui/regions/regions-escape-method.rs index 69c01ae6906cb..82bf86c79b235 100644 --- a/tests/ui/regions/regions-escape-method.rs +++ b/tests/ui/regions/regions-escape-method.rs @@ -2,6 +2,7 @@ // inferred to a region bound in the method argument. If this program // were accepted, then the closure passed to `s.f` could escape its // argument. +//@ run-rustfix struct S; diff --git a/tests/ui/regions/regions-escape-method.stderr b/tests/ui/regions/regions-escape-method.stderr index aeda923b0ba98..687b91bb7b47b 100644 --- a/tests/ui/regions/regions-escape-method.stderr +++ b/tests/ui/regions/regions-escape-method.stderr @@ -1,11 +1,16 @@ error: lifetime may not live long enough - --> $DIR/regions-escape-method.rs:15:13 + --> $DIR/regions-escape-method.rs:16:13 | LL | s.f(|p| p) | -- ^ returning this value requires that `'1` must outlive `'2` | || | |return type of closure is &'2 i32 | has type `&'1 i32` + | +help: dereference the return value + | +LL | s.f(|p| *p) + | + error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/missing-impl-trait-block-but-not-ascii.rs b/tests/ui/suggestions/missing-impl-trait-block-but-not-ascii.rs new file mode 100644 index 0000000000000..ddb6bd1e90209 --- /dev/null +++ b/tests/ui/suggestions/missing-impl-trait-block-but-not-ascii.rs @@ -0,0 +1,13 @@ +// issue#126764 + +struct S; + +trait T { + fn f(); +} +impl T for S; +//~^ ERROR: unknown start of token +//~| ERROR: expected `{}` +//~| ERROR: not all trait items implemented, missing: `f` + +fn main() {} diff --git a/tests/ui/suggestions/missing-impl-trait-block-but-not-ascii.stderr b/tests/ui/suggestions/missing-impl-trait-block-but-not-ascii.stderr new file mode 100644 index 0000000000000..56cdc11b62e6b --- /dev/null +++ b/tests/ui/suggestions/missing-impl-trait-block-but-not-ascii.stderr @@ -0,0 +1,31 @@ +error: unknown start of token: \u{ff1b} + --> $DIR/missing-impl-trait-block-but-not-ascii.rs:8:13 + | +LL | impl T for S; + | ^^ + | +help: Unicode character ';' (Fullwidth Semicolon) looks like ';' (Semicolon), but it is not + | +LL | impl T for S; + | ~ + +error: expected `{}`, found `;` + --> $DIR/missing-impl-trait-block-but-not-ascii.rs:8:13 + | +LL | impl T for S; + | ^^ + | + = help: try using `{}` instead + +error[E0046]: not all trait items implemented, missing: `f` + --> $DIR/missing-impl-trait-block-but-not-ascii.rs:8:1 + | +LL | fn f(); + | ------- `f` from trait +LL | } +LL | impl T for S; + | ^^^^^^^^^^^^ missing `f` in implementation + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0046`.