diff options
47 files changed, 688 insertions, 235 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index ab8b7f632e8..cc0fc7b8358 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2570,7 +2570,7 @@ pub enum AttrStyle { rustc_index::newtype_index! { #[custom_encodable] - #[debug_format = "AttrId({})]"] + #[debug_format = "AttrId({})"] pub struct AttrId {} } diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index 72352b138cb..c41bdc44093 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -2,7 +2,7 @@ use super::LoweringContext; use rustc_ast as ast; use rustc_ast::visit::{self, Visitor}; use rustc_ast::*; -use rustc_data_structures::fx::FxIndexSet; +use rustc_data_structures::fx::FxIndexMap; use rustc_hir as hir; use rustc_span::{ sym, @@ -238,7 +238,7 @@ fn make_count<'hir>( ctx: &mut LoweringContext<'_, 'hir>, sp: Span, count: &Option<FormatCount>, - argmap: &mut FxIndexSet<(usize, ArgumentType)>, + argmap: &mut FxIndexMap<(usize, ArgumentType), Option<Span>>, ) -> hir::Expr<'hir> { match count { Some(FormatCount::Literal(n)) => { @@ -252,7 +252,7 @@ fn make_count<'hir>( } Some(FormatCount::Argument(arg)) => { if let Ok(arg_index) = arg.index { - let (i, _) = argmap.insert_full((arg_index, ArgumentType::Usize)); + let (i, _) = argmap.insert_full((arg_index, ArgumentType::Usize), arg.span); let count_param = ctx.arena.alloc(ctx.expr_lang_item_type_relative( sp, hir::LangItem::FormatCount, @@ -291,12 +291,14 @@ fn make_format_spec<'hir>( ctx: &mut LoweringContext<'_, 'hir>, sp: Span, placeholder: &FormatPlaceholder, - argmap: &mut FxIndexSet<(usize, ArgumentType)>, + argmap: &mut FxIndexMap<(usize, ArgumentType), Option<Span>>, ) -> hir::Expr<'hir> { let position = match placeholder.argument.index { Ok(arg_index) => { - let (i, _) = - argmap.insert_full((arg_index, ArgumentType::Format(placeholder.format_trait))); + let (i, _) = argmap.insert_full( + (arg_index, ArgumentType::Format(placeholder.format_trait)), + placeholder.span, + ); ctx.expr_usize(sp, i) } Err(_) => ctx.expr( @@ -386,7 +388,7 @@ fn expand_format_args<'hir>( // Create a list of all _unique_ (argument, format trait) combinations. // E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (1, Display)] - let mut argmap = FxIndexSet::default(); + let mut argmap = FxIndexMap::default(); for piece in &fmt.template { let FormatArgsPiece::Placeholder(placeholder) = piece else { continue }; if placeholder.format_options != Default::default() { @@ -394,7 +396,10 @@ fn expand_format_args<'hir>( use_format_options = true; } if let Ok(index) = placeholder.argument.index { - if !argmap.insert((index, ArgumentType::Format(placeholder.format_trait))) { + if argmap + .insert((index, ArgumentType::Format(placeholder.format_trait)), placeholder.span) + .is_some() + { // Duplicate (argument, format trait) combination, // which we'll only put once in the args array. use_format_options = true; @@ -438,7 +443,7 @@ fn expand_format_args<'hir>( // This is an optimization, speeding up compilation about 1-2% in some cases. // See https://github.com/rust-lang/rust/pull/106770#issuecomment-1380790609 let use_simple_array = argmap.len() == arguments.len() - && argmap.iter().enumerate().all(|(i, &(j, _))| i == j) + && argmap.iter().enumerate().all(|(i, (&(j, _), _))| i == j) && arguments.iter().skip(1).all(|arg| !may_contain_yield_point(&arg.expr)); let args = if use_simple_array { @@ -452,14 +457,19 @@ fn expand_format_args<'hir>( let elements: Vec<_> = arguments .iter() .zip(argmap) - .map(|(arg, (_, ty))| { - let sp = arg.expr.span.with_ctxt(macsp.ctxt()); + .map(|(arg, ((_, ty), placeholder_span))| { + let placeholder_span = + placeholder_span.unwrap_or(arg.expr.span).with_ctxt(macsp.ctxt()); + let arg_span = match arg.kind { + FormatArgumentKind::Captured(_) => placeholder_span, + _ => arg.expr.span.with_ctxt(macsp.ctxt()), + }; let arg = ctx.lower_expr(&arg.expr); let ref_arg = ctx.arena.alloc(ctx.expr( - sp, + arg_span, hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, arg), )); - make_argument(ctx, sp, ref_arg, ty) + make_argument(ctx, placeholder_span, ref_arg, ty) }) .collect(); ctx.expr_array_ref(macsp, ctx.arena.alloc_from_iter(elements)) @@ -475,16 +485,26 @@ fn expand_format_args<'hir>( // } let args_ident = Ident::new(sym::args, macsp); let (args_pat, args_hir_id) = ctx.pat_ident(macsp, args_ident); - let args = ctx.arena.alloc_from_iter(argmap.iter().map(|&(arg_index, ty)| { - let arg = &arguments[arg_index]; - let sp = arg.expr.span.with_ctxt(macsp.ctxt()); - let args_ident_expr = ctx.expr_ident(macsp, args_ident, args_hir_id); - let arg = ctx.arena.alloc(ctx.expr( - sp, - hir::ExprKind::Field(args_ident_expr, Ident::new(sym::integer(arg_index), macsp)), - )); - make_argument(ctx, sp, arg, ty) - })); + let args = ctx.arena.alloc_from_iter(argmap.iter().map( + |(&(arg_index, ty), &placeholder_span)| { + let arg = &arguments[arg_index]; + let placeholder_span = + placeholder_span.unwrap_or(arg.expr.span).with_ctxt(macsp.ctxt()); + let arg_span = match arg.kind { + FormatArgumentKind::Captured(_) => placeholder_span, + _ => arg.expr.span.with_ctxt(macsp.ctxt()), + }; + let args_ident_expr = ctx.expr_ident(macsp, args_ident, args_hir_id); + let arg = ctx.arena.alloc(ctx.expr( + arg_span, + hir::ExprKind::Field( + args_ident_expr, + Ident::new(sym::integer(arg_index), macsp), + ), + )); + make_argument(ctx, placeholder_span, arg, ty) + }, + )); let elements: Vec<_> = arguments .iter() .map(|arg| { diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 7ce72d21727..2dda4cd1694 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -1452,8 +1452,8 @@ fn start_executing_work<B: ExtraBackendMethods>( Err(e) => { let msg = &format!("failed to acquire jobserver token: {}", e); shared_emitter.fatal(msg); - // Exit the coordinator thread - panic!("{}", msg) + codegen_done = true; + codegen_aborted = true; } } } diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index d8879bf70ed..9872b3bda1e 100644 --- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs +++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs @@ -202,7 +202,10 @@ impl AnnotateSnippetEmitterWriter { annotations: annotations .iter() .map(|annotation| SourceAnnotation { - range: (annotation.start_col, annotation.end_col), + range: ( + annotation.start_col.display, + annotation.end_col.display, + ), label: annotation.label.as_deref().unwrap_or_default(), annotation_type: annotation_type_for_level(*level), }) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 1b2e7b7e083..d6fd057c5a4 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -12,7 +12,9 @@ use Destination::*; use rustc_span::source_map::SourceMap; use rustc_span::{FileLines, SourceFile, Span}; -use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Style, StyledString}; +use crate::snippet::{ + Annotation, AnnotationColumn, AnnotationType, Line, MultilineAnnotation, Style, StyledString, +}; use crate::styled_buffer::StyledBuffer; use crate::translation::{to_fluent_args, Translate}; use crate::{ @@ -858,7 +860,7 @@ impl EmitterWriter { let mut short_start = true; for ann in &line.annotations { if let AnnotationType::MultilineStart(depth) = ann.annotation_type { - if source_string.chars().take(ann.start_col).all(|c| c.is_whitespace()) { + if source_string.chars().take(ann.start_col.display).all(|c| c.is_whitespace()) { let style = if ann.is_primary { Style::UnderlinePrimary } else { @@ -1093,15 +1095,15 @@ impl EmitterWriter { '_', line_offset + pos, width_offset + depth, - (code_offset + annotation.start_col).saturating_sub(left), + (code_offset + annotation.start_col.display).saturating_sub(left), style, ); } _ if self.teach => { buffer.set_style_range( line_offset, - (code_offset + annotation.start_col).saturating_sub(left), - (code_offset + annotation.end_col).saturating_sub(left), + (code_offset + annotation.start_col.display).saturating_sub(left), + (code_offset + annotation.end_col.display).saturating_sub(left), style, annotation.is_primary, ); @@ -1133,7 +1135,7 @@ impl EmitterWriter { for p in line_offset + 1..=line_offset + pos { buffer.putc( p, - (code_offset + annotation.start_col).saturating_sub(left), + (code_offset + annotation.start_col.display).saturating_sub(left), '|', style, ); @@ -1169,9 +1171,9 @@ impl EmitterWriter { let style = if annotation.is_primary { Style::LabelPrimary } else { Style::LabelSecondary }; let (pos, col) = if pos == 0 { - (pos + 1, (annotation.end_col + 1).saturating_sub(left)) + (pos + 1, (annotation.end_col.display + 1).saturating_sub(left)) } else { - (pos + 2, annotation.start_col.saturating_sub(left)) + (pos + 2, annotation.start_col.display.saturating_sub(left)) }; if let Some(ref label) = annotation.label { buffer.puts(line_offset + pos, code_offset + col, label, style); @@ -1208,7 +1210,7 @@ impl EmitterWriter { } else { ('-', Style::UnderlineSecondary) }; - for p in annotation.start_col..annotation.end_col { + for p in annotation.start_col.display..annotation.end_col.display { buffer.putc( line_offset + 1, (code_offset + p).saturating_sub(left), @@ -1459,7 +1461,7 @@ impl EmitterWriter { &annotated_file.file.name, line.line_index ), - annotations[0].start_col + 1, + annotations[0].start_col.file + 1, ), Style::LineAndColumn, ); @@ -1546,7 +1548,7 @@ impl EmitterWriter { buffer.prepend(buffer_msg_line_offset + 1, "::: ", Style::LineNumber); let loc = if let Some(first_line) = annotated_file.lines.first() { let col = if let Some(first_annotation) = first_line.annotations.first() { - format!(":{}", first_annotation.start_col + 1) + format!(":{}", first_annotation.start_col.file + 1) } else { String::new() }; @@ -1607,8 +1609,8 @@ impl EmitterWriter { let mut span_left_margin = usize::MAX; for line in &annotated_file.lines { for ann in &line.annotations { - span_left_margin = min(span_left_margin, ann.start_col); - span_left_margin = min(span_left_margin, ann.end_col); + span_left_margin = min(span_left_margin, ann.start_col.display); + span_left_margin = min(span_left_margin, ann.end_col.display); } } if span_left_margin == usize::MAX { @@ -1625,11 +1627,12 @@ impl EmitterWriter { annotated_file.file.get_line(line.line_index - 1).map_or(0, |s| s.len()), ); for ann in &line.annotations { - span_right_margin = max(span_right_margin, ann.start_col); - span_right_margin = max(span_right_margin, ann.end_col); + span_right_margin = max(span_right_margin, ann.start_col.display); + span_right_margin = max(span_right_margin, ann.end_col.display); // FIXME: account for labels not in the same line let label_right = ann.label.as_ref().map_or(0, |l| l.len() + 1); - label_right_margin = max(label_right_margin, ann.end_col + label_right); + label_right_margin = + max(label_right_margin, ann.end_col.display + label_right); } } @@ -2352,8 +2355,8 @@ impl FileWithAnnotatedLines { depth: 1, line_start: lo.line, line_end: hi.line, - start_col: lo.col_display, - end_col: hi.col_display, + start_col: AnnotationColumn::from_loc(&lo), + end_col: AnnotationColumn::from_loc(&hi), is_primary, label, overlaps_exactly: false, @@ -2361,8 +2364,8 @@ impl FileWithAnnotatedLines { multiline_annotations.push((lo.file, ml)); } else { let ann = Annotation { - start_col: lo.col_display, - end_col: hi.col_display, + start_col: AnnotationColumn::from_loc(&lo), + end_col: AnnotationColumn::from_loc(&hi), is_primary, label, annotation_type: AnnotationType::Singleline, @@ -2551,7 +2554,13 @@ fn num_overlap( (b_start..b_end + extra).contains(&a_start) || (a_start..a_end + extra).contains(&b_start) } fn overlaps(a1: &Annotation, a2: &Annotation, padding: usize) -> bool { - num_overlap(a1.start_col, a1.end_col + padding, a2.start_col, a2.end_col, false) + num_overlap( + a1.start_col.display, + a1.end_col.display + padding, + a2.start_col.display, + a2.end_col.display, + false, + ) } fn emit_to_destination( diff --git a/compiler/rustc_errors/src/snippet.rs b/compiler/rustc_errors/src/snippet.rs index e4cc44c41dd..98eb70b5fce 100644 --- a/compiler/rustc_errors/src/snippet.rs +++ b/compiler/rustc_errors/src/snippet.rs @@ -1,6 +1,6 @@ // Code for annotating snippets. -use crate::Level; +use crate::{Level, Loc}; #[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] pub struct Line { @@ -8,13 +8,39 @@ pub struct Line { pub annotations: Vec<Annotation>, } +#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Default)] +pub struct AnnotationColumn { + /// the (0-indexed) column for *display* purposes, counted in characters, not utf-8 bytes + pub display: usize, + /// the (0-indexed) column in the file, counted in characters, not utf-8 bytes. + /// + /// this may be different from `self.display`, + /// e.g. if the file contains hard tabs, because we convert tabs to spaces for error messages. + /// + /// for example: + /// ```text + /// (hard tab)hello + /// ^ this is display column 4, but file column 1 + /// ``` + /// + /// we want to keep around the correct file offset so that column numbers in error messages + /// are correct. (motivated by <https://github.com/rust-lang/rust/issues/109537>) + pub file: usize, +} + +impl AnnotationColumn { + pub fn from_loc(loc: &Loc) -> AnnotationColumn { + AnnotationColumn { display: loc.col_display, file: loc.col.0 } + } +} + #[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] pub struct MultilineAnnotation { pub depth: usize, pub line_start: usize, pub line_end: usize, - pub start_col: usize, - pub end_col: usize, + pub start_col: AnnotationColumn, + pub end_col: AnnotationColumn, pub is_primary: bool, pub label: Option<String>, pub overlaps_exactly: bool, @@ -36,7 +62,12 @@ impl MultilineAnnotation { pub fn as_start(&self) -> Annotation { Annotation { start_col: self.start_col, - end_col: self.start_col + 1, + end_col: AnnotationColumn { + // these might not correspond to the same place anymore, + // but that's okay for our purposes + display: self.start_col.display + 1, + file: self.start_col.file + 1, + }, is_primary: self.is_primary, label: None, annotation_type: AnnotationType::MultilineStart(self.depth), @@ -45,7 +76,12 @@ impl MultilineAnnotation { pub fn as_end(&self) -> Annotation { Annotation { - start_col: self.end_col.saturating_sub(1), + start_col: AnnotationColumn { + // these might not correspond to the same place anymore, + // but that's okay for our purposes + display: self.end_col.display.saturating_sub(1), + file: self.end_col.file.saturating_sub(1), + }, end_col: self.end_col, is_primary: self.is_primary, label: self.label.clone(), @@ -55,8 +91,8 @@ impl MultilineAnnotation { pub fn as_line(&self) -> Annotation { Annotation { - start_col: 0, - end_col: 0, + start_col: Default::default(), + end_col: Default::default(), is_primary: self.is_primary, label: None, annotation_type: AnnotationType::MultilineLine(self.depth), @@ -92,14 +128,14 @@ pub enum AnnotationType { #[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] pub struct Annotation { - /// Start column, 0-based indexing -- counting *characters*, not - /// utf-8 bytes. Note that it is important that this field goes + /// Start column. + /// Note that it is important that this field goes /// first, so that when we sort, we sort orderings by start /// column. - pub start_col: usize, + pub start_col: AnnotationColumn, /// End column within the line (exclusive) - pub end_col: usize, + pub end_col: AnnotationColumn, /// Is this annotation derived from primary span pub is_primary: bool, @@ -118,12 +154,13 @@ impl Annotation { matches!(self.annotation_type, AnnotationType::MultilineLine(_)) } + /// Length of this annotation as displayed in the stderr output pub fn len(&self) -> usize { // Account for usize underflows - if self.end_col > self.start_col { - self.end_col - self.start_col + if self.end_col.display > self.start_col.display { + self.end_col.display - self.start_col.display } else { - self.start_col - self.end_col + self.start_col.display - self.end_col.display } } diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 55f684599e7..95d1a7df698 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -245,6 +245,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None } + fn suggest_missing_writer( + &self, + rcvr_ty: Ty<'tcx>, + args: (&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>]), + ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { + let (ty_str, _ty_file) = self.tcx.short_ty_string(rcvr_ty); + let mut err = + struct_span_err!(self.tcx.sess, args.0.span, E0599, "cannot write into `{}`", ty_str); + err.span_note( + args.0.span, + "must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method", + ); + if let ExprKind::Lit(_) = args.0.kind { + err.span_help( + args.0.span.shrink_to_lo(), + "a writer is needed before this format string", + ); + }; + + err + } + pub fn report_no_match_method_error( &self, mut span: Span, @@ -323,16 +345,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - let mut err = struct_span_err!( - tcx.sess, - span, - E0599, - "no {} named `{}` found for {} `{}` in the current scope", - item_kind, - item_name, - rcvr_ty.prefix_string(self.tcx), - ty_str_reported, - ); + let is_write = sugg_span.ctxt().outer_expn_data().macro_def_id.map_or(false, |def_id| { + tcx.is_diagnostic_item(sym::write_macro, def_id) + || tcx.is_diagnostic_item(sym::writeln_macro, def_id) + }) && item_name.name == Symbol::intern("write_fmt"); + let mut err = if is_write + && let Some(args) = args + { + self.suggest_missing_writer(rcvr_ty, args) + } else { + struct_span_err!( + tcx.sess, + span, + E0599, + "no {} named `{}` found for {} `{}` in the current scope", + item_kind, + item_name, + rcvr_ty.prefix_string(self.tcx), + ty_str_reported, + ) + }; if tcx.sess.source_map().is_multiline(sugg_span) { err.span_label(sugg_span.with_hi(span.lo()), ""); } diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index e604e44a715..f2dec8fe327 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -1158,13 +1158,6 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, // Otherwise, we sometimes lose `static` values -- see #60184. computeDeadSymbolsWithConstProp(Ret->Index, Ret->GUIDPreservedSymbols, deadIsPrevailing, /* ImportEnabled = */ false); - ComputeCrossModuleImport( - Ret->Index, - Ret->ModuleToDefinedGVSummaries, - Ret->ImportLists, - Ret->ExportLists - ); - // Resolve LinkOnce/Weak symbols, this has to be computed early be cause it // impacts the caching. // @@ -1181,6 +1174,16 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, return true; return Prevailing->second == S; }; + ComputeCrossModuleImport( + Ret->Index, + Ret->ModuleToDefinedGVSummaries, +#if LLVM_VERSION_GE(17, 0) + isPrevailing, +#endif + Ret->ImportLists, + Ret->ExportLists + ); + auto recordNewLinkage = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID, GlobalValue::LinkageTypes NewLinkage) { diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs index 669d50a7fda..0a6e94248e6 100644 --- a/compiler/rustc_middle/src/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -1,6 +1,6 @@ use crate::mir::Mutability; use crate::ty::subst::GenericArgKind; -use crate::ty::{self, Ty, TyCtxt, TypeVisitableExt}; +use crate::ty::{self, SubstsRef, Ty, TyCtxt, TypeVisitableExt}; use rustc_hir::def_id::DefId; use std::fmt::Debug; use std::hash::Hash; @@ -188,22 +188,24 @@ pub struct DeepRejectCtxt { } impl DeepRejectCtxt { - pub fn generic_args_may_unify<'tcx>( + pub fn substs_refs_may_unify<'tcx>( self, - obligation_arg: ty::GenericArg<'tcx>, - impl_arg: ty::GenericArg<'tcx>, + obligation_substs: SubstsRef<'tcx>, + impl_substs: SubstsRef<'tcx>, ) -> bool { - match (obligation_arg.unpack(), impl_arg.unpack()) { - // We don't fast reject based on regions for now. - (GenericArgKind::Lifetime(_), GenericArgKind::Lifetime(_)) => true, - (GenericArgKind::Type(obl), GenericArgKind::Type(imp)) => { - self.types_may_unify(obl, imp) - } - (GenericArgKind::Const(obl), GenericArgKind::Const(imp)) => { - self.consts_may_unify(obl, imp) + iter::zip(obligation_substs, impl_substs).all(|(obl, imp)| { + match (obl.unpack(), imp.unpack()) { + // We don't fast reject based on regions for now. + (GenericArgKind::Lifetime(_), GenericArgKind::Lifetime(_)) => true, + (GenericArgKind::Type(obl), GenericArgKind::Type(imp)) => { + self.types_may_unify(obl, imp) + } + (GenericArgKind::Const(obl), GenericArgKind::Const(imp)) => { + self.consts_may_unify(obl, imp) + } + _ => bug!("kind mismatch: {obl} {imp}"), } - _ => bug!("kind mismatch: {obligation_arg} {impl_arg}"), - } + }) } pub fn types_may_unify<'tcx>(self, obligation_ty: Ty<'tcx>, impl_ty: Ty<'tcx>) -> bool { @@ -258,9 +260,7 @@ impl DeepRejectCtxt { }, ty::Adt(obl_def, obl_substs) => match k { &ty::Adt(impl_def, impl_substs) => { - obl_def == impl_def - && iter::zip(obl_substs, impl_substs) - .all(|(obl, imp)| self.generic_args_may_unify(obl, imp)) + obl_def == impl_def && self.substs_refs_may_unify(obl_substs, impl_substs) } _ => false, }, diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs index 4fb77d79518..0f7a0eb337b 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -1,5 +1,6 @@ //! Code shared by trait and projection goals for candidate assembly. +use super::search_graph::OverflowHandler; #[cfg(doc)] use super::trait_goals::structural_traits::*; use super::{EvalCtxt, SolverMode}; @@ -279,25 +280,38 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { return }; - self.probe(|ecx| { - let normalized_ty = ecx.next_ty_infer(); - let normalizes_to_goal = goal.with( - tcx, - ty::Binder::dummy(ty::ProjectionPredicate { - projection_ty, - term: normalized_ty.into(), - }), - ); - ecx.add_goal(normalizes_to_goal); - if let Ok(_) = ecx.try_evaluate_added_goals() { - let normalized_ty = ecx.resolve_vars_if_possible(normalized_ty); - - // NOTE: Alternatively we could call `evaluate_goal` here and only have a `Normalized` candidate. - // This doesn't work as long as we use `CandidateSource` in winnowing. - let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty)); - candidates.extend(ecx.assemble_and_evaluate_candidates(goal)); - } + let normalized_self_candidates: Result<_, NoSolution> = self.probe(|ecx| { + ecx.with_incremented_depth( + |ecx| { + let result = ecx.evaluate_added_goals_and_make_canonical_response( + Certainty::Maybe(MaybeCause::Overflow), + )?; + Ok(vec![Candidate { source: CandidateSource::BuiltinImpl, result }]) + }, + |ecx| { + let normalized_ty = ecx.next_ty_infer(); + let normalizes_to_goal = goal.with( + tcx, + ty::Binder::dummy(ty::ProjectionPredicate { + projection_ty, + term: normalized_ty.into(), + }), + ); + ecx.add_goal(normalizes_to_goal); + let _ = ecx.try_evaluate_added_goals()?; + let normalized_ty = ecx.resolve_vars_if_possible(normalized_ty); + // NOTE: Alternatively we could call `evaluate_goal` here and only + // have a `Normalized` candidate. This doesn't work as long as we + // use `CandidateSource` in winnowing. + let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty)); + Ok(ecx.assemble_and_evaluate_candidates(goal)) + }, + ) }); + + if let Ok(normalized_self_candidates) = normalized_self_candidates { + candidates.extend(normalized_self_candidates); + } } fn assemble_impl_candidates<G: GoalKind<'tcx>>( diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 2b104703aab..91b56fe3522 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -17,7 +17,6 @@ use rustc_middle::ty::ProjectionPredicate; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{ToPredicate, TypeVisitableExt}; use rustc_span::{sym, DUMMY_SP}; -use std::iter; impl<'tcx> EvalCtxt<'_, 'tcx> { #[instrument(level = "debug", skip(self), ret)] @@ -144,9 +143,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { let goal_trait_ref = goal.predicate.projection_ty.trait_ref(tcx); let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup }; - if iter::zip(goal_trait_ref.substs, impl_trait_ref.skip_binder().substs) - .any(|(goal, imp)| !drcx.generic_args_may_unify(goal, imp)) - { + if !drcx.substs_refs_may_unify(goal_trait_ref.substs, impl_trait_ref.skip_binder().substs) { return Err(NoSolution); } diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs index 717905e55e5..aeb67666035 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs @@ -47,6 +47,22 @@ impl<'tcx> SearchGraph<'tcx> { self.mode } + /// We do not use the global cache during coherence. + /// + /// The trait solver behavior is different for coherence + /// so we would have to add the solver mode to the cache key. + /// This is probably not worth it as trait solving during + /// coherence tends to already be incredibly fast. + /// + /// We could add another global cache for coherence instead, + /// but that's effort so let's only do it if necessary. + pub(super) fn should_use_global_cache(&self) -> bool { + match self.mode { + SolverMode::Normal => true, + SolverMode::Coherence => false, + } + } + pub(super) fn is_empty(&self) -> bool { self.stack.is_empty() && self.provisional_cache.is_empty() } @@ -191,8 +207,10 @@ impl<'tcx> SearchGraph<'tcx> { canonical_goal: CanonicalGoal<'tcx>, mut loop_body: impl FnMut(&mut Self) -> QueryResult<'tcx>, ) -> QueryResult<'tcx> { - if let Some(result) = tcx.new_solver_evaluation_cache.get(&canonical_goal, tcx) { - return result; + if self.should_use_global_cache() { + if let Some(result) = tcx.new_solver_evaluation_cache.get(&canonical_goal, tcx) { + return result; + } } match self.try_push_stack(tcx, canonical_goal) { @@ -252,9 +270,8 @@ impl<'tcx> SearchGraph<'tcx> { // dependencies, our non-root goal may no longer appear as child of the root goal. // // See https://github.com/rust-lang/rust/pull/108071 for some additional context. - let should_cache_globally = matches!(self.solver_mode(), SolverMode::Normal) - && (!self.overflow_data.did_overflow() || self.stack.is_empty()); - if should_cache_globally { + let can_cache = !self.overflow_data.did_overflow() || self.stack.is_empty(); + if self.should_use_global_cache() && can_cache { tcx.new_solver_evaluation_cache.insert( current_goal.goal, dep_node, diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/overflow.rs b/compiler/rustc_trait_selection/src/solve/search_graph/overflow.rs index 7c9e63f529b..574f3e9a577 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph/overflow.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph/overflow.rs @@ -73,6 +73,27 @@ pub(in crate::solve) trait OverflowHandler<'tcx> { self.search_graph().overflow_data.deal_with_overflow(); on_overflow(self) } + + // Increment the `additional_depth` by one and evaluate `body`, or `on_overflow` + // if the depth is overflown. + fn with_incremented_depth<T>( + &mut self, + on_overflow: impl FnOnce(&mut Self) -> T, + body: impl FnOnce(&mut Self) -> T, + ) -> T { + let depth = self.search_graph().stack.len(); + self.search_graph().overflow_data.additional_depth += 1; + + let result = if self.search_graph().overflow_data.has_overflow(depth) { + self.search_graph().overflow_data.deal_with_overflow(); + on_overflow(self) + } else { + body(self) + }; + + self.search_graph().overflow_data.additional_depth -= 1; + result + } } impl<'tcx> OverflowHandler<'tcx> for EvalCtxt<'_, 'tcx> { diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 718c82c8f1f..f522a8f7e65 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -1,7 +1,5 @@ //! Dealing with trait goals, i.e. `T: Trait<'a, U>`. -use std::iter; - use super::{assembly, EvalCtxt, SolverMode}; use rustc_hir::def_id::DefId; use rustc_hir::LangItem; @@ -41,9 +39,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup }; - if iter::zip(goal.predicate.trait_ref.substs, impl_trait_ref.skip_binder().substs) - .any(|(goal, imp)| !drcx.generic_args_may_unify(goal, imp)) - { + if !drcx.substs_refs_may_unify( + goal.predicate.trait_ref.substs, + impl_trait_ref.skip_binder().substs, + ) { return Err(NoSolution); } diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 4e5e756dc4a..d360158fdf8 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -79,8 +79,9 @@ pub fn overlapping_impls( let impl1_ref = tcx.impl_trait_ref(impl1_def_id); let impl2_ref = tcx.impl_trait_ref(impl2_def_id); let may_overlap = match (impl1_ref, impl2_ref) { - (Some(a), Some(b)) => iter::zip(a.skip_binder().substs, b.skip_binder().substs) - .all(|(arg1, arg2)| drcx.generic_args_may_unify(arg1, arg2)), + (Some(a), Some(b)) => { + drcx.substs_refs_may_unify(a.skip_binder().substs, b.skip_binder().substs) + } (None, None) => { let self_ty1 = tcx.type_of(impl1_def_id).skip_binder(); let self_ty2 = tcx.type_of(impl2_def_id).skip_binder(); diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 234d773d64d..47a351590b1 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -11,7 +11,7 @@ use hir::LangItem; use rustc_hir as hir; use rustc_infer::traits::ObligationCause; use rustc_infer::traits::{Obligation, SelectionError, TraitObligation}; -use rustc_middle::ty::fast_reject::TreatProjections; +use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, TreatProjections}; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use crate::traits; @@ -344,6 +344,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return; } + let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup }; + let obligation_substs = obligation.predicate.skip_binder().trait_ref.substs; self.tcx().for_each_relevant_impl( obligation.predicate.def_id(), obligation.predicate.skip_binder().trait_ref.self_ty(), @@ -352,7 +354,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // consider a "quick reject". This avoids creating more types // and so forth that we need to. let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap(); - if self.fast_reject_trait_refs(obligation, &impl_trait_ref.0) { + if !drcx.substs_refs_may_unify(obligation_substs, impl_trait_ref.0.substs) { return; } if self.reject_fn_ptr_impls( diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 98c3e7c13ac..3ed3dd2d20d 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -45,7 +45,6 @@ use rustc_infer::traits::TraitEngineExt; use rustc_middle::dep_graph::{DepKind, DepNodeIndex}; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::abstract_const::NotConstEvaluatable; -use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::SubstsRef; @@ -2533,19 +2532,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> { Ok(Normalized { value: impl_substs, obligations: nested_obligations }) } - fn fast_reject_trait_refs( - &mut self, - obligation: &TraitObligation<'tcx>, - impl_trait_ref: &ty::TraitRef<'tcx>, - ) -> bool { - // We can avoid creating type variables and doing the full - // substitution if we find that any of the input types, when - // simplified, do not match. - let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup }; - iter::zip(obligation.predicate.skip_binder().trait_ref.substs, impl_trait_ref.substs) - .any(|(obl, imp)| !drcx.generic_args_may_unify(obl, imp)) - } - /// Normalize `where_clause_trait_ref` and try to match it against /// `obligation`. If successful, return any predicates that /// result from the normalization. diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 5f5521caf68..2d247bd537b 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -31,7 +31,6 @@ use rustc_span::hygiene::{AstPass, MacroKind}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{self, ExpnKind}; -use std::assert_matches::assert_matches; use std::borrow::Cow; use std::collections::hash_map::Entry; use std::collections::BTreeMap; @@ -270,15 +269,7 @@ fn clean_where_predicate<'tcx>( let bound_params = wbp .bound_generic_params .iter() - .map(|param| { - // Higher-ranked params must be lifetimes. - // Higher-ranked lifetimes can't have bounds. - assert_matches!( - param, - hir::GenericParam { kind: hir::GenericParamKind::Lifetime { .. }, .. } - ); - Lifetime(param.name.ident().name) - }) + .map(|param| clean_generic_param(cx, None, param)) .collect(); WherePredicate::BoundPredicate { ty: clean_ty(wbp.bounded_ty, cx), @@ -410,7 +401,7 @@ fn clean_projection_predicate<'tcx>( .collect_referenced_late_bound_regions(&pred) .into_iter() .filter_map(|br| match br { - ty::BrNamed(_, name) if br.is_named() => Some(Lifetime(name)), + ty::BrNamed(_, name) if br.is_named() => Some(GenericParamDef::lifetime(name)), _ => None, }) .collect(); @@ -508,7 +499,6 @@ fn clean_generic_param_def<'tcx>( ty::GenericParamDefKind::Const { has_default } => ( def.name, GenericParamDefKind::Const { - did: def.def_id, ty: Box::new(clean_middle_ty( ty::Binder::dummy( cx.tcx @@ -578,7 +568,6 @@ fn clean_generic_param<'tcx>( hir::GenericParamKind::Const { ty, default } => ( param.name.ident().name, GenericParamDefKind::Const { - did: param.def_id.to_def_id(), ty: Box::new(clean_ty(ty, cx)), default: default .map(|ct| Box::new(ty::Const::from_anon_const(cx.tcx, ct.def_id).to_string())), @@ -831,7 +820,7 @@ fn clean_ty_generics<'tcx>( p.get_bound_params() .into_iter() .flatten() - .map(|param| GenericParamDef::lifetime(param.0)) + .cloned() .collect(), )); } diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index dbbc25739aa..3c72b0bf9f2 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -49,11 +49,7 @@ pub(crate) fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> ThinVec<WP equalities.retain(|(lhs, rhs, bound_params)| { let Some((ty, trait_did, name)) = lhs.projection() else { return true; }; let Some((bounds, _)) = tybounds.get_mut(ty) else { return true }; - let bound_params = bound_params - .into_iter() - .map(|param| clean::GenericParamDef::lifetime(param.0)) - .collect(); - merge_bounds(cx, bounds, bound_params, trait_did, name, rhs) + merge_bounds(cx, bounds, bound_params.clone(), trait_did, name, rhs) }); // And finally, let's reassemble everything diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 9019a6c49ec..909e0a07e4c 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -232,14 +232,6 @@ impl ExternalCrate { hir::ItemKind::Mod(_) => { as_keyword(Res::Def(DefKind::Mod, id.owner_id.to_def_id())) } - hir::ItemKind::Use(path, hir::UseKind::Single) - if tcx.visibility(id.owner_id).is_public() => - { - path.res - .iter() - .find_map(|res| as_keyword(res.expect_non_local())) - .map(|(_, prim)| (id.owner_id.to_def_id(), prim)) - } _ => None, } }) @@ -302,15 +294,6 @@ impl ExternalCrate { hir::ItemKind::Mod(_) => { as_primitive(Res::Def(DefKind::Mod, id.owner_id.to_def_id())) } - hir::ItemKind::Use(path, hir::UseKind::Single) - if tcx.visibility(id.owner_id).is_public() => - { - path.res - .iter() - .find_map(|res| as_primitive(res.expect_non_local())) - // Pretend the primitive is local. - .map(|(_, prim)| (id.owner_id.to_def_id(), prim)) - } _ => None, } }) @@ -1236,9 +1219,9 @@ impl Lifetime { #[derive(Clone, Debug)] pub(crate) enum WherePredicate { - BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<Lifetime> }, + BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<GenericParamDef> }, RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> }, - EqPredicate { lhs: Box<Type>, rhs: Box<Term>, bound_params: Vec<Lifetime> }, + EqPredicate { lhs: Box<Type>, rhs: Box<Term>, bound_params: Vec<GenericParamDef> }, } impl WherePredicate { @@ -1250,7 +1233,7 @@ impl WherePredicate { } } - pub(crate) fn get_bound_params(&self) -> Option<&[Lifetime]> { + pub(crate) fn get_bound_params(&self) -> Option<&[GenericParamDef]> { match self { Self::BoundPredicate { bound_params, .. } | Self::EqPredicate { bound_params, .. } => { Some(bound_params) @@ -1264,7 +1247,7 @@ impl WherePredicate { pub(crate) enum GenericParamDefKind { Lifetime { outlives: Vec<Lifetime> }, Type { did: DefId, bounds: Vec<GenericBound>, default: Option<Box<Type>>, synthetic: bool }, - Const { did: DefId, ty: Box<Type>, default: Option<Box<String>> }, + Const { ty: Box<Type>, default: Option<Box<String>> }, } impl GenericParamDefKind { diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index f2b9c0bcf3e..0895bb510d4 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -307,13 +307,13 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>( write!( f, "for<{:#}> {ty_cx:#}: {generic_bounds:#}", - comma_sep(bound_params.iter().map(|lt| lt.print()), true) + comma_sep(bound_params.iter().map(|lt| lt.print(cx)), true) ) } else { write!( f, "for<{}> {ty_cx}: {generic_bounds}", - comma_sep(bound_params.iter().map(|lt| lt.print()), true) + comma_sep(bound_params.iter().map(|lt| lt.print(cx)), true) ) } } diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 18c45fd6991..59d67f27b30 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -456,7 +456,7 @@ impl FromWithTcx<clean::GenericParamDefKind> for GenericParamDefKind { default: default.map(|x| (*x).into_tcx(tcx)), synthetic, }, - Const { did: _, ty, default } => GenericParamDefKind::Const { + Const { ty, default } => GenericParamDefKind::Const { type_: (*ty).into_tcx(tcx), default: default.map(|x| *x), }, @@ -473,9 +473,35 @@ impl FromWithTcx<clean::WherePredicate> for WherePredicate { bounds: bounds.into_tcx(tcx), generic_params: bound_params .into_iter() - .map(|x| GenericParamDef { - name: x.0.to_string(), - kind: GenericParamDefKind::Lifetime { outlives: vec![] }, + .map(|x| { + let name = x.name.to_string(); + let kind = match x.kind { + clean::GenericParamDefKind::Lifetime { outlives } => { + GenericParamDefKind::Lifetime { + outlives: outlives.iter().map(|lt| lt.0.to_string()).collect(), + } + } + clean::GenericParamDefKind::Type { + did: _, + bounds, + default, + synthetic, + } => GenericParamDefKind::Type { + bounds: bounds + .into_iter() + .map(|bound| bound.into_tcx(tcx)) + .collect(), + default: default.map(|ty| (*ty).into_tcx(tcx)), + synthetic, + }, + clean::GenericParamDefKind::Const { ty, default } => { + GenericParamDefKind::Const { + type_: (*ty).into_tcx(tcx), + default: default.map(|d| *d), + } + } + }; + GenericParamDef { name, kind } }) .collect(), }, diff --git a/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff index 225f80ed41b..f6f2344e82f 100644 --- a/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff +++ b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff @@ -19,12 +19,12 @@ let mut _17: &[core::fmt::ArgumentV1<'_>; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL let _18: &[core::fmt::ArgumentV1<'_>; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL let _19: [core::fmt::ArgumentV1<'_>; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _20: core::fmt::ArgumentV1<'_>; // in scope 0 at $DIR/lifetimes.rs:+10:21: +10:22 - let mut _21: &std::boxed::Box<dyn std::fmt::Display>; // in scope 0 at $DIR/lifetimes.rs:+10:21: +10:22 - let _22: &std::boxed::Box<dyn std::fmt::Display>; // in scope 0 at $DIR/lifetimes.rs:+10:21: +10:22 - let mut _23: core::fmt::ArgumentV1<'_>; // in scope 0 at $DIR/lifetimes.rs:+10:25: +10:26 - let mut _24: &u32; // in scope 0 at $DIR/lifetimes.rs:+10:25: +10:26 - let _25: &u32; // in scope 0 at $DIR/lifetimes.rs:+10:25: +10:26 + let mut _20: core::fmt::ArgumentV1<'_>; // in scope 0 at $DIR/lifetimes.rs:+10:20: +10:23 + let mut _21: &std::boxed::Box<dyn std::fmt::Display>; // in scope 0 at $DIR/lifetimes.rs:+10:20: +10:23 + let _22: &std::boxed::Box<dyn std::fmt::Display>; // in scope 0 at $DIR/lifetimes.rs:+10:20: +10:23 + let mut _23: core::fmt::ArgumentV1<'_>; // in scope 0 at $DIR/lifetimes.rs:+10:24: +10:27 + let mut _24: &u32; // in scope 0 at $DIR/lifetimes.rs:+10:24: +10:27 + let _25: &u32; // in scope 0 at $DIR/lifetimes.rs:+10:24: +10:27 let mut _27: bool; // in scope 0 at $DIR/lifetimes.rs:+12:1: +12:2 let mut _28: isize; // in scope 0 at $DIR/lifetimes.rs:+12:1: +12:2 let mut _29: isize; // in scope 0 at $DIR/lifetimes.rs:+12:1: +12:2 @@ -108,34 +108,34 @@ StorageLive(_17); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL StorageLive(_18); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL StorageLive(_19); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageLive(_20); // scope 4 at $DIR/lifetimes.rs:+10:21: +10:22 - StorageLive(_21); // scope 4 at $DIR/lifetimes.rs:+10:21: +10:22 - StorageLive(_22); // scope 4 at $DIR/lifetimes.rs:+10:21: +10:22 - _22 = &_8; // scope 4 at $DIR/lifetimes.rs:+10:21: +10:22 - _21 = &(*_22); // scope 4 at $DIR/lifetimes.rs:+10:21: +10:22 - _20 = core::fmt::ArgumentV1::<'_>::new_display::<Box<dyn std::fmt::Display>>(move _21) -> bb3; // scope 4 at $DIR/lifetimes.rs:+10:21: +10:22 + StorageLive(_20); // scope 4 at $DIR/lifetimes.rs:+10:20: +10:23 + StorageLive(_21); // scope 4 at $DIR/lifetimes.rs:+10:20: +10:23 + StorageLive(_22); // scope 4 at $DIR/lifetimes.rs:+10:20: +10:23 + _22 = &_8; // scope 4 at $DIR/lifetimes.rs:+10:20: +10:23 + _21 = &(*_22); // scope 4 at $DIR/lifetimes.rs:+10:20: +10:23 + _20 = core::fmt::ArgumentV1::<'_>::new_display::<Box<dyn std::fmt::Display>>(move _21) -> bb3; // scope 4 at $DIR/lifetimes.rs:+10:20: +10:23 // mir::Constant - // + span: $DIR/lifetimes.rs:27:21: 27:22 + // + span: $DIR/lifetimes.rs:27:20: 27:23 // + user_ty: UserType(4) // + literal: Const { ty: for<'b> fn(&'b Box<dyn std::fmt::Display>) -> core::fmt::ArgumentV1<'b> {core::fmt::ArgumentV1::<'_>::new_display::<Box<dyn std::fmt::Display>>}, val: Value(<ZST>) } } bb3: { - StorageDead(_21); // scope 4 at $DIR/lifetimes.rs:+10:21: +10:22 - StorageLive(_23); // scope 4 at $DIR/lifetimes.rs:+10:25: +10:26 - StorageLive(_24); // scope 4 at $DIR/lifetimes.rs:+10:25: +10:26 - StorageLive(_25); // scope 4 at $DIR/lifetimes.rs:+10:25: +10:26 - _25 = &_6; // scope 4 at $DIR/lifetimes.rs:+10:25: +10:26 - _24 = &(*_25); // scope 4 at $DIR/lifetimes.rs:+10:25: +10:26 - _23 = core::fmt::ArgumentV1::<'_>::new_display::<u32>(move _24) -> bb4; // scope 4 at $DIR/lifetimes.rs:+10:25: +10:26 + StorageDead(_21); // scope 4 at $DIR/lifetimes.rs:+10:22: +10:23 + StorageLive(_23); // scope 4 at $DIR/lifetimes.rs:+10:24: +10:27 + StorageLive(_24); // scope 4 at $DIR/lifetimes.rs:+10:24: +10:27 + StorageLive(_25); // scope 4 at $DIR/lifetimes.rs:+10:24: +10:27 + _25 = &_6; // scope 4 at $DIR/lifetimes.rs:+10:24: +10:27 + _24 = &(*_25); // scope 4 at $DIR/lifetimes.rs:+10:24: +10:27 + _23 = core::fmt::ArgumentV1::<'_>::new_display::<u32>(move _24) -> bb4; // scope 4 at $DIR/lifetimes.rs:+10:24: +10:27 // mir::Constant - // + span: $DIR/lifetimes.rs:27:25: 27:26 + // + span: $DIR/lifetimes.rs:27:24: 27:27 // + user_ty: UserType(5) // + literal: Const { ty: for<'b> fn(&'b u32) -> core::fmt::ArgumentV1<'b> {core::fmt::ArgumentV1::<'_>::new_display::<u32>}, val: Value(<ZST>) } } bb4: { - StorageDead(_24); // scope 4 at $DIR/lifetimes.rs:+10:25: +10:26 + StorageDead(_24); // scope 4 at $DIR/lifetimes.rs:+10:26: +10:27 _19 = [move _20, move _23]; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL StorageDead(_23); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL StorageDead(_20); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL diff --git a/tests/run-make/jobserver-error/Makefile b/tests/run-make/jobserver-error/Makefile new file mode 100644 index 00000000000..3b9104fc354 --- /dev/null +++ b/tests/run-make/jobserver-error/Makefile @@ -0,0 +1,8 @@ +include ../../run-make-fulldeps/tools.mk + +# only-linux + +# Test compiler behavior in case: `jobserver-auth` points to correct pipe which is not jobserver. + +all: + bash -c 'echo "fn main() {}" | MAKEFLAGS="--jobserver-auth=3,3" $(RUSTC) - 3</dev/null' 2>&1 | diff jobserver.stderr - diff --git a/tests/run-make/jobserver-error/jobserver.stderr b/tests/run-make/jobserver-error/jobserver.stderr new file mode 100644 index 00000000000..d18e15a2628 --- /dev/null +++ b/tests/run-make/jobserver-error/jobserver.stderr @@ -0,0 +1,4 @@ +error: failed to acquire jobserver token: early EOF on jobserver pipe + +error: aborting due to previous error + diff --git a/tests/rustdoc-json/non_lifetime_binders.rs b/tests/rustdoc-json/non_lifetime_binders.rs new file mode 100644 index 00000000000..ca5a008344a --- /dev/null +++ b/tests/rustdoc-json/non_lifetime_binders.rs @@ -0,0 +1,24 @@ +// ignore-tidy-linelength + +#![feature(non_lifetime_binders)] +#![allow(incomplete_features)] + +#![no_core] +#![feature(lang_items, no_core)] + +#[lang = "sized"] +pub trait Sized {} + +pub trait Trait {} + +#[lang = "phantom_data"] +struct PhantomData<T_>; + +pub struct Wrapper<T_>(PhantomData<T_>); + +// @count "$.index[*][?(@.name=='foo')].inner.generics.where_predicates[0].bound_predicate.generic_params[*]" 2 +// @is "$.index[*][?(@.name=='foo')].inner.generics.where_predicates[0].bound_predicate.generic_params[0].name" \"\'a\" +// @is "$.index[*][?(@.name=='foo')].inner.generics.where_predicates[0].bound_predicate.generic_params[0].kind" '{ "lifetime": { "outlives": [] } }' +// @is "$.index[*][?(@.name=='foo')].inner.generics.where_predicates[0].bound_predicate.generic_params[1].name" \"T\" +// @is "$.index[*][?(@.name=='foo')].inner.generics.where_predicates[0].bound_predicate.generic_params[1].kind" '{ "type": { "bounds": [], "default": null, "synthetic": false } }' +pub fn foo() where for<'a, T> &'a Wrapper<T>: Trait {} diff --git a/tests/rustdoc/issue-15318-2.rs b/tests/rustdoc/issue-15318-2.rs index f7f5052a36d..614f2c1c08e 100644 --- a/tests/rustdoc/issue-15318-2.rs +++ b/tests/rustdoc/issue-15318-2.rs @@ -6,7 +6,7 @@ extern crate issue_15318; pub use issue_15318::ptr; -// @has issue_15318_2/fn.bar.html \ +// @!has issue_15318_2/fn.bar.html \ // '//*[@href="primitive.pointer.html"]' \ // '*mut T' pub fn bar<T>(ptr: *mut T) {} diff --git a/tests/rustdoc/non_lifetime_binders.rs b/tests/rustdoc/non_lifetime_binders.rs new file mode 100644 index 00000000000..da9a4e6a84d --- /dev/null +++ b/tests/rustdoc/non_lifetime_binders.rs @@ -0,0 +1,9 @@ +#![feature(non_lifetime_binders)] +#![allow(incomplete_features)] + +pub trait Trait {} + +pub struct Wrapper<T: ?Sized>(Box<T>); + +// @has non_lifetime_binders/fn.foo.html '//pre' "fn foo()where for<'a, T> &'a Wrapper<T>: Trait" +pub fn foo() where for<'a, T> &'a Wrapper<T>: Trait {} diff --git a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.current.stderr index f71fd9980a2..1e67cdca248 100644 --- a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr +++ b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.current.stderr @@ -1,5 +1,5 @@ warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/dont-project-to-specializable-projection.rs:4:12 + --> $DIR/dont-project-to-specializable-projection.rs:6:12 | LL | #![feature(async_fn_in_trait)] | ^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | #![feature(async_fn_in_trait)] = note: `#[warn(incomplete_features)]` on by default error: async associated function in trait cannot be specialized - --> $DIR/dont-project-to-specializable-projection.rs:14:5 + --> $DIR/dont-project-to-specializable-projection.rs:16:5 | LL | default async fn foo(_: T) -> &'static str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.next.stderr b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.next.stderr new file mode 100644 index 00000000000..fa89c6b77e0 --- /dev/null +++ b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.next.stderr @@ -0,0 +1,34 @@ +warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/dont-project-to-specializable-projection.rs:6:12 + | +LL | #![feature(async_fn_in_trait)] + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0053]: method `foo` has an incompatible type for trait + --> $DIR/dont-project-to-specializable-projection.rs:16:35 + | +LL | default async fn foo(_: T) -> &'static str { + | ^^^^^^^^^^^^ expected associated type, found future + | +note: type in trait + --> $DIR/dont-project-to-specializable-projection.rs:12:27 + | +LL | async fn foo(_: T) -> &'static str; + | ^^^^^^^^^^^^ + = note: expected signature `fn(_) -> impl Future<Output = &'static str>` + found signature `fn(_) -> impl Future<Output = &'static str>` + +error: async associated function in trait cannot be specialized + --> $DIR/dont-project-to-specializable-projection.rs:16:5 + | +LL | default async fn foo(_: T) -> &'static str { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: specialization behaves in inconsistent and surprising ways with `#![feature(async_fn_in_trait)]`, and for now is disallowed + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs index afd3db5e052..7183eaccc93 100644 --- a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs +++ b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs @@ -1,5 +1,7 @@ // edition: 2021 // known-bug: #108309 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(async_fn_in_trait)] #![feature(min_specialization)] diff --git a/tests/ui/consts/const-eval/format.stderr b/tests/ui/consts/const-eval/format.stderr index c39920d444d..70a1abb0a95 100644 --- a/tests/ui/consts/const-eval/format.stderr +++ b/tests/ui/consts/const-eval/format.stderr @@ -1,8 +1,8 @@ error[E0015]: cannot call non-const formatting macro in constant functions - --> $DIR/format.rs:2:20 + --> $DIR/format.rs:2:13 | LL | panic!("{:?}", 0); - | ^ + | ^^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = note: this error originates in the macro `$crate::const_format_args` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -17,10 +17,10 @@ LL | panic!("{:?}", 0); = note: this error originates in the macro `$crate::const_format_args` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0015]: cannot call non-const formatting macro in constant functions - --> $DIR/format.rs:8:22 + --> $DIR/format.rs:8:15 | LL | println!("{:?}", 0); - | ^ + | ^^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/diagnostic-width/auxiliary/tab_column_numbers.rs b/tests/ui/diagnostic-width/auxiliary/tab_column_numbers.rs new file mode 100644 index 00000000000..93418b7651c --- /dev/null +++ b/tests/ui/diagnostic-width/auxiliary/tab_column_numbers.rs @@ -0,0 +1,6 @@ +// ignore-tidy-tab + +pub struct S; +impl S { + fn method(&self) {} +} diff --git a/tests/ui/diagnostic-width/tab-column-numbers.rs b/tests/ui/diagnostic-width/tab-column-numbers.rs new file mode 100644 index 00000000000..2abb0bcde95 --- /dev/null +++ b/tests/ui/diagnostic-width/tab-column-numbers.rs @@ -0,0 +1,12 @@ +// Test for #109537: ensure that column numbers are correctly generated when using hard tabs. +// aux-build:tab_column_numbers.rs + +// ignore-tidy-tab + +extern crate tab_column_numbers; + +fn main() { + let s = tab_column_numbers::S; + s.method(); + //~^ ERROR method `method` is private +} diff --git a/tests/ui/diagnostic-width/tab-column-numbers.stderr b/tests/ui/diagnostic-width/tab-column-numbers.stderr new file mode 100644 index 00000000000..ea4e1ff52a9 --- /dev/null +++ b/tests/ui/diagnostic-width/tab-column-numbers.stderr @@ -0,0 +1,14 @@ +error[E0624]: method `method` is private + --> $DIR/tab-column-numbers.rs:10:4 + | +LL | s.method(); + | ^^^^^^ private method + | + ::: $DIR/auxiliary/tab_column_numbers.rs:5:3 + | +LL | fn method(&self) {} + | ---------------- private method defined here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0624`. diff --git a/tests/ui/fmt/format-args-argument-span.rs b/tests/ui/fmt/format-args-argument-span.rs new file mode 100644 index 00000000000..c7acb08f84b --- /dev/null +++ b/tests/ui/fmt/format-args-argument-span.rs @@ -0,0 +1,22 @@ +// check-compile + +struct DisplayOnly; + +impl std::fmt::Display for DisplayOnly { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + unimplemented!() + } +} + +fn main() { + let x = Some(1); + println!("{x:?} {x} {x:?}"); + //~^ ERROR: `Option<{integer}>` doesn't implement `std::fmt::Display` + println!("{x:?} {x} {x:?}", x = Some(1)); + //~^ ERROR: `Option<{integer}>` doesn't implement `std::fmt::Display` + let x = DisplayOnly; + println!("{x} {x:?} {x}"); + //~^ ERROR: `DisplayOnly` doesn't implement `Debug` + println!("{x} {x:?} {x}", x = DisplayOnly); + //~^ ERROR: `DisplayOnly` doesn't implement `Debug` +} diff --git a/tests/ui/fmt/format-args-argument-span.stderr b/tests/ui/fmt/format-args-argument-span.stderr new file mode 100644 index 00000000000..b060b2cd339 --- /dev/null +++ b/tests/ui/fmt/format-args-argument-span.stderr @@ -0,0 +1,51 @@ +error[E0277]: `Option<{integer}>` doesn't implement `std::fmt::Display` + --> $DIR/format-args-argument-span.rs:13:21 + | +LL | println!("{x:?} {x} {x:?}"); + | ^^^ `Option<{integer}>` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `Option<{integer}>` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: `Option<{integer}>` doesn't implement `std::fmt::Display` + --> $DIR/format-args-argument-span.rs:15:37 + | +LL | println!("{x:?} {x} {x:?}", x = Some(1)); + | ^^^^^^^ `Option<{integer}>` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `Option<{integer}>` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: `DisplayOnly` doesn't implement `Debug` + --> $DIR/format-args-argument-span.rs:18:19 + | +LL | println!("{x} {x:?} {x}"); + | ^^^^^ `DisplayOnly` cannot be formatted using `{:?}` + | + = help: the trait `Debug` is not implemented for `DisplayOnly` + = note: add `#[derive(Debug)]` to `DisplayOnly` or manually `impl Debug for DisplayOnly` + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider annotating `DisplayOnly` with `#[derive(Debug)]` + | +LL | #[derive(Debug)] + | + +error[E0277]: `DisplayOnly` doesn't implement `Debug` + --> $DIR/format-args-argument-span.rs:20:35 + | +LL | println!("{x} {x:?} {x}", x = DisplayOnly); + | ^^^^^^^^^^^ `DisplayOnly` cannot be formatted using `{:?}` + | + = help: the trait `Debug` is not implemented for `DisplayOnly` + = note: add `#[derive(Debug)]` to `DisplayOnly` or manually `impl Debug for DisplayOnly` + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider annotating `DisplayOnly` with `#[derive(Debug)]` + | +LL | #[derive(Debug)] + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/fmt/ifmt-bad-arg.stderr b/tests/ui/fmt/ifmt-bad-arg.stderr index d716bbe51af..bf18fb315c9 100644 --- a/tests/ui/fmt/ifmt-bad-arg.stderr +++ b/tests/ui/fmt/ifmt-bad-arg.stderr @@ -300,10 +300,9 @@ error[E0308]: mismatched types --> $DIR/ifmt-bad-arg.rs:78:32 | LL | println!("{} {:.*} {}", 1, 3.2, 4); - | ^^^ - | | - | expected `&usize`, found `&{float}` - | arguments to this function are incorrect + | -- ^^^ expected `&usize`, found `&{float}` + | | + | arguments to this function are incorrect | = note: expected reference `&usize` found reference `&{float}` @@ -315,10 +314,9 @@ error[E0308]: mismatched types --> $DIR/ifmt-bad-arg.rs:81:35 | LL | println!("{} {:07$.*} {}", 1, 3.2, 4); - | ^^^ - | | - | expected `&usize`, found `&{float}` - | arguments to this function are incorrect + | -- ^^^ expected `&usize`, found `&{float}` + | | + | arguments to this function are incorrect | = note: expected reference `&usize` found reference `&{float}` diff --git a/tests/ui/fmt/ifmt-unimpl.stderr b/tests/ui/fmt/ifmt-unimpl.stderr index 3480a2ec815..dc2dee3f341 100644 --- a/tests/ui/fmt/ifmt-unimpl.stderr +++ b/tests/ui/fmt/ifmt-unimpl.stderr @@ -2,7 +2,9 @@ error[E0277]: the trait bound `str: UpperHex` is not satisfied --> $DIR/ifmt-unimpl.rs:2:21 | LL | format!("{:X}", "3"); - | ^^^ the trait `UpperHex` is not implemented for `str` + | ---- ^^^ the trait `UpperHex` is not implemented for `str` + | | + | required by a bound introduced by this call | = help: the following other types implement trait `UpperHex`: &T diff --git a/tests/ui/macros/missing-writer.rs b/tests/ui/macros/missing-writer.rs new file mode 100644 index 00000000000..7df965c3684 --- /dev/null +++ b/tests/ui/macros/missing-writer.rs @@ -0,0 +1,17 @@ +// Check error for missing writer in writeln! and write! macro +fn main() { + let x = 1; + let y = 2; + write!("{}_{}", x, y); + //~^ ERROR format argument must be a string literal + //~| HELP you might be missing a string literal to format with + //~| ERROR cannot write into `&'static str` + //~| NOTE must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method + //~| HELP a writer is needed before this format string + writeln!("{}_{}", x, y); + //~^ ERROR format argument must be a string literal + //~| HELP you might be missing a string literal to format with + //~| ERROR cannot write into `&'static str` + //~| NOTE must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method + //~| HELP a writer is needed before this format string +} diff --git a/tests/ui/macros/missing-writer.stderr b/tests/ui/macros/missing-writer.stderr new file mode 100644 index 00000000000..86dfe7d65ea --- /dev/null +++ b/tests/ui/macros/missing-writer.stderr @@ -0,0 +1,59 @@ +error: format argument must be a string literal + --> $DIR/missing-writer.rs:5:21 + | +LL | write!("{}_{}", x, y); + | ^ + | +help: you might be missing a string literal to format with + | +LL | write!("{}_{}", "{} {}", x, y); + | ++++++++ + +error: format argument must be a string literal + --> $DIR/missing-writer.rs:11:23 + | +LL | writeln!("{}_{}", x, y); + | ^ + | +help: you might be missing a string literal to format with + | +LL | writeln!("{}_{}", "{} {}", x, y); + | ++++++++ + +error[E0599]: cannot write into `&'static str` + --> $DIR/missing-writer.rs:5:12 + | +LL | write!("{}_{}", x, y); + | -------^^^^^^^------- method not found in `&str` + | +note: must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method + --> $DIR/missing-writer.rs:5:12 + | +LL | write!("{}_{}", x, y); + | ^^^^^^^ +help: a writer is needed before this format string + --> $DIR/missing-writer.rs:5:12 + | +LL | write!("{}_{}", x, y); + | ^ + +error[E0599]: cannot write into `&'static str` + --> $DIR/missing-writer.rs:11:14 + | +LL | writeln!("{}_{}", x, y); + | ---------^^^^^^^------- method not found in `&str` + | +note: must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method + --> $DIR/missing-writer.rs:11:14 + | +LL | writeln!("{}_{}", x, y); + | ^^^^^^^ +help: a writer is needed before this format string + --> $DIR/missing-writer.rs:11:14 + | +LL | writeln!("{}_{}", x, y); + | ^ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/suggestions/issue-97760.stderr b/tests/ui/suggestions/issue-97760.stderr index bbcc3693fff..5415c247c8f 100644 --- a/tests/ui/suggestions/issue-97760.stderr +++ b/tests/ui/suggestions/issue-97760.stderr @@ -1,8 +1,8 @@ error[E0277]: `<impl IntoIterator as IntoIterator>::Item` doesn't implement `std::fmt::Display` - --> $DIR/issue-97760.rs:4:20 + --> $DIR/issue-97760.rs:4:19 | LL | println!("{x}"); - | ^ `<impl IntoIterator as IntoIterator>::Item` cannot be formatted with the default formatter + | ^^^ `<impl IntoIterator as IntoIterator>::Item` cannot be formatted with the default formatter | = help: the trait `std::fmt::Display` is not implemented for `<impl IntoIterator as IntoIterator>::Item` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead diff --git a/tests/ui/suggestions/mut-borrow-needed-by-trait.stderr b/tests/ui/suggestions/mut-borrow-needed-by-trait.stderr index 6910b77d9bc..94710f4503f 100644 --- a/tests/ui/suggestions/mut-borrow-needed-by-trait.stderr +++ b/tests/ui/suggestions/mut-borrow-needed-by-trait.stderr @@ -21,18 +21,22 @@ note: required by a bound in `BufWriter` --> $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL error[E0599]: the method `write_fmt` exists for struct `BufWriter<&dyn Write>`, but its trait bounds were not satisfied - --> $DIR/mut-borrow-needed-by-trait.rs:21:5 + --> $DIR/mut-borrow-needed-by-trait.rs:21:14 | LL | writeln!(fp, "hello world").unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ method cannot be called on `BufWriter<&dyn Write>` due to unsatisfied trait bounds + | ---------^^---------------- method cannot be called on `BufWriter<&dyn Write>` due to unsatisfied trait bounds --> $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL | = note: doesn't satisfy `BufWriter<&dyn std::io::Write>: std::io::Write` | +note: must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method + --> $DIR/mut-borrow-needed-by-trait.rs:21:14 + | +LL | writeln!(fp, "hello world").unwrap(); + | ^^ = note: the following trait bounds were not satisfied: `&dyn std::io::Write: std::io::Write` which is required by `BufWriter<&dyn std::io::Write>: std::io::Write` - = note: this error originates in the macro `writeln` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 3 previous errors diff --git a/tests/ui/traits/new-solver/recursive-self-normalization-2.rs b/tests/ui/traits/new-solver/recursive-self-normalization-2.rs new file mode 100644 index 00000000000..7417d6018a1 --- /dev/null +++ b/tests/ui/traits/new-solver/recursive-self-normalization-2.rs @@ -0,0 +1,19 @@ +// compile-flags: -Ztrait-solver=next + +trait Foo1 { + type Assoc1; +} + +trait Foo2 { + type Assoc2; +} + +trait Bar {} +fn needs_bar<S: Bar>() {} + +fn test<T: Foo1<Assoc1 = <T as Foo2>::Assoc2> + Foo2<Assoc2 = <T as Foo1>::Assoc1>>() { + needs_bar::<T::Assoc1>(); + //~^ ERROR type annotations needed +} + +fn main() {} diff --git a/tests/ui/traits/new-solver/recursive-self-normalization-2.stderr b/tests/ui/traits/new-solver/recursive-self-normalization-2.stderr new file mode 100644 index 00000000000..29cfa47a105 --- /dev/null +++ b/tests/ui/traits/new-solver/recursive-self-normalization-2.stderr @@ -0,0 +1,9 @@ +error[E0282]: type annotations needed + --> $DIR/recursive-self-normalization-2.rs:15:5 + | +LL | needs_bar::<T::Assoc1>(); + | ^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `S` declared on the function `needs_bar` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/traits/new-solver/recursive-self-normalization.rs b/tests/ui/traits/new-solver/recursive-self-normalization.rs new file mode 100644 index 00000000000..f3e3d71d813 --- /dev/null +++ b/tests/ui/traits/new-solver/recursive-self-normalization.rs @@ -0,0 +1,15 @@ +// compile-flags: -Ztrait-solver=next + +trait Foo { + type Assoc; +} + +trait Bar {} +fn needs_bar<S: Bar>() {} + +fn test<T: Foo<Assoc = <T as Foo>::Assoc>>() { + needs_bar::<T::Assoc>(); + //~^ ERROR type annotations needed +} + +fn main() {} diff --git a/tests/ui/traits/new-solver/recursive-self-normalization.stderr b/tests/ui/traits/new-solver/recursive-self-normalization.stderr new file mode 100644 index 00000000000..ba39981893d --- /dev/null +++ b/tests/ui/traits/new-solver/recursive-self-normalization.stderr @@ -0,0 +1,9 @@ +error[E0282]: type annotations needed + --> $DIR/recursive-self-normalization.rs:11:5 + | +LL | needs_bar::<T::Assoc>(); + | ^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `S` declared on the function `needs_bar` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. |
