summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast/src/ast.rs2
-rw-r--r--compiler/rustc_ast_lowering/src/format.rs66
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs4
-rw-r--r--compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs5
-rw-r--r--compiler/rustc_errors/src/emitter.rs51
-rw-r--r--compiler/rustc_errors/src/snippet.rs65
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs52
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp17
-rw-r--r--compiler/rustc_middle/src/ty/fast_reject.rs34
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly.rs50
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals.rs5
-rw-r--r--compiler/rustc_trait_selection/src/solve/search_graph/mod.rs27
-rw-r--r--compiler/rustc_trait_selection/src/solve/search_graph/overflow.rs21
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs14
-rw-r--r--src/librustdoc/clean/mod.rs17
-rw-r--r--src/librustdoc/clean/simplify.rs6
-rw-r--r--src/librustdoc/clean/types.rs25
-rw-r--r--src/librustdoc/html/format.rs4
-rw-r--r--src/librustdoc/json/conversions.rs34
-rw-r--r--tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff44
-rw-r--r--tests/run-make/jobserver-error/Makefile8
-rw-r--r--tests/run-make/jobserver-error/jobserver.stderr4
-rw-r--r--tests/rustdoc-json/non_lifetime_binders.rs24
-rw-r--r--tests/rustdoc/issue-15318-2.rs2
-rw-r--r--tests/rustdoc/non_lifetime_binders.rs9
-rw-r--r--tests/ui/async-await/in-trait/dont-project-to-specializable-projection.current.stderr (renamed from tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr)4
-rw-r--r--tests/ui/async-await/in-trait/dont-project-to-specializable-projection.next.stderr34
-rw-r--r--tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs2
-rw-r--r--tests/ui/consts/const-eval/format.stderr8
-rw-r--r--tests/ui/diagnostic-width/auxiliary/tab_column_numbers.rs6
-rw-r--r--tests/ui/diagnostic-width/tab-column-numbers.rs12
-rw-r--r--tests/ui/diagnostic-width/tab-column-numbers.stderr14
-rw-r--r--tests/ui/fmt/format-args-argument-span.rs22
-rw-r--r--tests/ui/fmt/format-args-argument-span.stderr51
-rw-r--r--tests/ui/fmt/ifmt-bad-arg.stderr14
-rw-r--r--tests/ui/fmt/ifmt-unimpl.stderr4
-rw-r--r--tests/ui/macros/missing-writer.rs17
-rw-r--r--tests/ui/macros/missing-writer.stderr59
-rw-r--r--tests/ui/suggestions/issue-97760.stderr4
-rw-r--r--tests/ui/suggestions/mut-borrow-needed-by-trait.stderr10
-rw-r--r--tests/ui/traits/new-solver/recursive-self-normalization-2.rs19
-rw-r--r--tests/ui/traits/new-solver/recursive-self-normalization-2.stderr9
-rw-r--r--tests/ui/traits/new-solver/recursive-self-normalization.rs15
-rw-r--r--tests/ui/traits/new-solver/recursive-self-normalization.stderr9
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&lt;{}&gt; {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`.