diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 2100487107517..b15e2d084ef7f 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -1,271 +1,42 @@ -use ArgumentType::*; -use Position::*; - -use rustc_ast as ast; use rustc_ast::ptr::P; +use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; -use rustc_ast::visit::{self, Visitor}; -use rustc_ast::{token, BlockCheckMode, UnsafeSource}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_ast::Expr; +use rustc_data_structures::fx::FxHashSet; use rustc_errors::{pluralize, Applicability, MultiSpan, PResult}; use rustc_expand::base::{self, *}; use rustc_parse_format as parse; -use rustc_span::symbol::{sym, Ident, Symbol}; +use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{BytePos, InnerSpan, Span}; -use smallvec::SmallVec; use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY; use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics, LintId}; -use rustc_parse_format::Count; -use std::borrow::Cow; -use std::collections::hash_map::Entry; - -#[derive(PartialEq)] -enum ArgumentType { - Placeholder(&'static str), - Count, -} - -enum Position { - Exact(usize), - Capture(usize), - Named(Symbol, InnerSpan), -} - -/// Indicates how positional named argument (i.e. an named argument which is used by position -/// instead of by name) is used in format string -/// * `Arg` is the actual argument to print -/// * `Width` is width format argument -/// * `Precision` is precion format argument -/// Example: `{Arg:Width$.Precision$} -#[derive(Debug, Eq, PartialEq)] -enum PositionalNamedArgType { - Arg, - Width, - Precision, -} - -/// Contains information necessary to create a lint for a positional named argument -#[derive(Debug)] -struct PositionalNamedArg { - ty: PositionalNamedArgType, - /// The piece of the using this argument (multiple pieces can use the same argument) - cur_piece: usize, - /// The InnerSpan for in the string to be replaced with the named argument - /// This will be None when the position is implicit - inner_span_to_replace: Option, - /// The name to use instead of the position - replacement: Symbol, - /// The span for the positional named argument (so the lint can point a message to it) - positional_named_arg_span: Span, - has_formatting: bool, -} - -impl PositionalNamedArg { - /// Determines: - /// 1) span to be replaced with the name of the named argument and - /// 2) span to be underlined for error messages - fn get_positional_arg_spans(&self, cx: &Context<'_, '_>) -> (Option, Option) { - if let Some(inner_span) = &self.inner_span_to_replace { - let span = - cx.fmtsp.from_inner(InnerSpan { start: inner_span.start, end: inner_span.end }); - (Some(span), Some(span)) - } else if self.ty == PositionalNamedArgType::Arg { - // In the case of a named argument whose position is implicit, if the argument *has* - // formatting, there will not be a span to replace. Instead, we insert the name after - // the `{`, which will be the first character of arg_span. If the argument does *not* - // have formatting, there may or may not be a span to replace. This is because - // whitespace is allowed in arguments without formatting (such as `format!("{ }", 1);`) - // but is not allowed in arguments with formatting (an error will be generated in cases - // like `format!("{ :1.1}", 1.0f32);`. - // For the message span, if there is formatting, we want to use the opening `{` and the - // next character, which will the `:` indicating the start of formatting. If there is - // not any formatting, we want to underline the entire span. - cx.arg_spans.get(self.cur_piece).map_or((None, None), |arg_span| { - if self.has_formatting { - ( - Some(arg_span.with_lo(arg_span.lo() + BytePos(1)).shrink_to_lo()), - Some(arg_span.with_hi(arg_span.lo() + BytePos(2))), - ) - } else { - let replace_start = arg_span.lo() + BytePos(1); - let replace_end = arg_span.hi() - BytePos(1); - let to_replace = arg_span.with_lo(replace_start).with_hi(replace_end); - (Some(to_replace), Some(*arg_span)) - } - }) - } else { - (None, None) - } - } -} - -/// Encapsulates all the named arguments that have been used positionally -#[derive(Debug)] -struct PositionalNamedArgsLint { - positional_named_args: Vec, -} - -impl PositionalNamedArgsLint { - /// For a given positional argument, check if the index is for a named argument. - /// - /// Since positional arguments are required to come before named arguments, if the positional - /// index is greater than or equal to the start of named arguments, we know it's a named - /// argument used positionally. - /// - /// Example: - /// println!("{} {} {2}", 0, a=1, b=2); - /// - /// In this case, the first piece (`{}`) would be ArgumentImplicitlyIs with an index of 0. The - /// total number of arguments is 3 and the number of named arguments is 2, so the start of named - /// arguments is index 1. Therefore, the index of 0 is okay. - /// - /// The second piece (`{}`) would be ArgumentImplicitlyIs with an index of 1, which is the start - /// of named arguments, and so we should add a lint to use the named argument `a`. - /// - /// The third piece (`{2}`) would be ArgumentIs with an index of 2, which is greater than the - /// start of named arguments, and so we should add a lint to use the named argument `b`. - /// - /// This same check also works for width and precision formatting when either or both are - /// CountIsParam, which contains an index into the arguments. - fn maybe_add_positional_named_arg( - &mut self, - arg: Option<&FormatArg>, - ty: PositionalNamedArgType, - cur_piece: usize, - inner_span_to_replace: Option, - has_formatting: bool, - ) { - if let Some(arg) = arg { - if let Some(name) = arg.name { - self.push(name, ty, cur_piece, inner_span_to_replace, has_formatting) - } - } - } - /// Construct a PositionalNamedArg struct and push it into the vec of positional - /// named arguments. - fn push( - &mut self, - arg_name: Ident, - ty: PositionalNamedArgType, - cur_piece: usize, - inner_span_to_replace: Option, - has_formatting: bool, - ) { - // In FormatSpec, `precision_span` starts at the leading `.`, which we want to keep in - // the lint suggestion, so increment `start` by 1 when `PositionalArgumentType` is - // `Precision`. - let inner_span_to_replace = if ty == PositionalNamedArgType::Precision { - inner_span_to_replace - .map(|is| rustc_parse_format::InnerSpan { start: is.start + 1, end: is.end }) - } else { - inner_span_to_replace - }; - self.positional_named_args.push(PositionalNamedArg { - ty, - cur_piece, - inner_span_to_replace, - replacement: arg_name.name, - positional_named_arg_span: arg_name.span, - has_formatting, - }); - } -} - -struct Context<'a, 'b> { - ecx: &'a mut ExtCtxt<'b>, - /// The macro's call site. References to unstable formatting internals must - /// use this span to pass the stability checker. - macsp: Span, - /// The span of the format string literal. - fmtsp: Span, - - /// List of parsed argument expressions. - /// Named expressions are resolved early, and are appended to the end of - /// argument expressions. - /// - /// Example showing the various data structures in motion: - /// - /// * Original: `"{foo:o} {:o} {foo:x} {0:x} {1:o} {:x} {1:x} {0:o}"` - /// * Implicit argument resolution: `"{foo:o} {0:o} {foo:x} {0:x} {1:o} {1:x} {1:x} {0:o}"` - /// * Name resolution: `"{2:o} {0:o} {2:x} {0:x} {1:o} {1:x} {1:x} {0:o}"` - /// * `arg_types` (in JSON): `[[0, 1, 0], [0, 1, 1], [0, 1]]` - /// * `arg_unique_types` (in simplified JSON): `[["o", "x"], ["o", "x"], ["o", "x"]]` - /// * `names` (in JSON): `{"foo": 2}` - args: Vec, - /// The number of arguments that were added by implicit capturing. - num_captured_args: usize, - /// Placeholder slot numbers indexed by argument. - arg_types: Vec>, - /// Unique format specs seen for each argument. - arg_unique_types: Vec>, - /// Map from named arguments to their resolved indices. - names: FxHashMap, - - /// The latest consecutive literal strings, or empty if there weren't any. - literal: String, +mod ast; +use ast::*; - /// Collection of the compiled `rt::Argument` structures - pieces: Vec>, - /// Collection of string literals - str_pieces: Vec>, - /// Stays `true` if all formatting parameters are default (as in "{}{}"). - all_pieces_simple: bool, +mod expand; +use expand::expand_parsed_format_args; - /// Mapping between positional argument references and indices into the - /// final generated static argument array. We record the starting indices - /// corresponding to each positional argument, and number of references - /// consumed so far for each argument, to facilitate correct `Position` - /// mapping in `build_piece`. In effect this can be seen as a "flattened" - /// version of `arg_unique_types`. - /// - /// Again with the example described above in docstring for `args`: - /// - /// * `arg_index_map` (in JSON): `[[0, 1, 0], [2, 3, 3], [4, 5]]` - arg_index_map: Vec>, +// The format_args!() macro is expanded in three steps: +// 1. First, `parse_args` will parse the `(literal, arg, arg, name=arg, name=arg)` syntax, +// but doesn't parse the template (the literal) itself. +// 2. Second, `make_format_args` will parse the template, the format options, resolve argument references, +// produce diagnostics, and turn the whole thing into a `FormatArgs` structure. +// 3. Finally, `expand_parsed_format_args` will turn that `FormatArgs` structure +// into the expression that the macro expands to. - /// Starting offset of count argument slots. - count_args_index_offset: usize, +// See format/ast.rs for the FormatArgs structure and glossary. - /// Count argument slots and tracking data structures. - /// Count arguments are separately tracked for de-duplication in case - /// multiple references are made to one argument. For example, in this - /// format string: - /// - /// * Original: `"{:.*} {:.foo$} {1:.*} {:.0$}"` - /// * Implicit argument resolution: `"{1:.0$} {2:.foo$} {1:.3$} {4:.0$}"` - /// * Name resolution: `"{1:.0$} {2:.5$} {1:.3$} {4:.0$}"` - /// * `count_positions` (in JSON): `{0: 0, 5: 1, 3: 2}` - /// * `count_args`: `vec![0, 5, 3]` - count_args: Vec, - /// Relative slot numbers for count arguments. - count_positions: FxHashMap, - /// Number of count slots assigned. - count_positions_count: usize, - - /// Current position of the implicit positional arg pointer, as if it - /// still existed in this phase of processing. - /// Used only for `all_pieces_simple` tracking in `build_piece`. - curarg: usize, - /// Current piece being evaluated, used for error reporting. - curpiece: usize, - /// Keep track of invalid references to positional arguments. - invalid_refs: Vec<(usize, usize)>, - /// Spans of all the formatting arguments, in order. - arg_spans: Vec, - /// All the formatting arguments that have formatting flags set, in order for diagnostics. - arg_with_formatting: Vec>, - - /// Whether this format string came from a string literal, as opposed to a macro. - is_literal: bool, - unused_names_lint: PositionalNamedArgsLint, -} - -pub struct FormatArg { - expr: P, - name: Option, +// Only used in parse_args and report_invalid_references, +// to indicate how a referred argument was used. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum PositionUsedAs { + Placeholder(Option), + Precision, + Width, } +use PositionUsedAs::*; /// Parses the arguments from the given list of tokens, returning the diagnostic /// if there's a parse error so we can continue parsing other format! @@ -274,15 +45,14 @@ pub struct FormatArg { /// If parsing succeeds, the return value is: /// /// ```text -/// Some((fmtstr, parsed arguments, index map for named arguments)) +/// Ok((fmtstr, parsed arguments)) /// ``` fn parse_args<'a>( ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream, -) -> PResult<'a, (P, Vec, FxHashMap)> { - let mut args = Vec::::new(); - let mut names = FxHashMap::::default(); +) -> PResult<'a, (P, FormatArguments)> { + let mut args = FormatArguments::new(); let mut p = ecx.new_parser_from_tts(tts); @@ -311,7 +81,6 @@ fn parse_args<'a>( }; let mut first = true; - let mut named = false; while p.token != token::Eof { if !p.eat(&token::Comma) { @@ -343,879 +112,54 @@ fn parse_args<'a>( } // accept trailing commas match p.token.ident() { Some((ident, _)) if p.look_ahead(1, |t| *t == token::Eq) => { - named = true; p.bump(); p.expect(&token::Eq)?; - let e = p.parse_expr()?; - if let Some(&prev) = names.get(&ident.name) { - ecx.struct_span_err(e.span, &format!("duplicate argument named `{}`", ident)) - .span_label(args[prev].expr.span, "previously here") - .span_label(e.span, "duplicate argument") - .emit(); + let expr = p.parse_expr()?; + if let Some((_, prev)) = args.by_name(ident.name) { + ecx.struct_span_err( + ident.span, + &format!("duplicate argument named `{}`", ident), + ) + .span_label(prev.kind.ident().unwrap().span, "previously here") + .span_label(ident.span, "duplicate argument") + .emit(); continue; } - - // Resolve names into slots early. - // Since all the positional args are already seen at this point - // if the input is valid, we can simply append to the positional - // args. And remember the names. - let slot = args.len(); - names.insert(ident.name, slot); - args.push(FormatArg { expr: e, name: Some(ident) }); + args.add(FormatArgument { kind: FormatArgumentKind::Named(ident), expr }); } _ => { - let e = p.parse_expr()?; - if named { + let expr = p.parse_expr()?; + if !args.named_args().is_empty() { let mut err = ecx.struct_span_err( - e.span, + expr.span, "positional arguments cannot follow named arguments", ); - err.span_label(e.span, "positional arguments must be before named arguments"); - for &pos in names.values() { - err.span_label(args[pos].expr.span, "named argument"); + err.span_label( + expr.span, + "positional arguments must be before named arguments", + ); + for arg in args.named_args() { + if let Some(name) = arg.kind.ident() { + err.span_label(name.span.to(arg.expr.span), "named argument"); + } } err.emit(); } - args.push(FormatArg { expr: e, name: None }); + args.add(FormatArgument { kind: FormatArgumentKind::Normal, expr }); } } } - Ok((fmtstr, args, names)) + Ok((fmtstr, args)) } -impl<'a, 'b> Context<'a, 'b> { - /// The number of arguments that were explicitly given. - fn num_args(&self) -> usize { - self.args.len() - self.num_captured_args - } - - fn resolve_name_inplace(&mut self, p: &mut parse::Piece<'_>) { - // NOTE: the `unwrap_or` branch is needed in case of invalid format - // arguments, e.g., `format_args!("{foo}")`. - let lookup = |s: &str| self.names.get(&Symbol::intern(s)).copied().unwrap_or(0); - - match *p { - parse::String(_) => {} - parse::NextArgument(ref mut arg) => { - if let parse::ArgumentNamed(s) = arg.position { - arg.position = parse::ArgumentIs(lookup(s)); - } - if let parse::CountIsName(s, _) = arg.format.width { - arg.format.width = parse::CountIsParam(lookup(s)); - } - if let parse::CountIsName(s, _) = arg.format.precision { - arg.format.precision = parse::CountIsParam(lookup(s)); - } - } - } - } - - /// Verifies one piece of a parse string, and remembers it if valid. - /// All errors are not emitted as fatal so we can continue giving errors - /// about this and possibly other format strings. - fn verify_piece(&mut self, p: &parse::Piece<'a>) { - match *p { - parse::String(..) => {} - parse::NextArgument(ref arg) => { - // width/precision first, if they have implicit positional - // parameters it makes more sense to consume them first. - self.verify_count( - arg.format.width, - &arg.format.width_span, - PositionalNamedArgType::Width, - ); - self.verify_count( - arg.format.precision, - &arg.format.precision_span, - PositionalNamedArgType::Precision, - ); - - let has_precision = arg.format.precision != Count::CountImplied; - let has_width = arg.format.width != Count::CountImplied; - - if has_precision || has_width { - // push before named params are resolved to aid diagnostics - self.arg_with_formatting.push(arg.format); - } - - // argument second, if it's an implicit positional parameter - // it's written second, so it should come after width/precision. - let pos = match arg.position { - parse::ArgumentIs(i) => { - self.unused_names_lint.maybe_add_positional_named_arg( - self.args.get(i), - PositionalNamedArgType::Arg, - self.curpiece, - Some(arg.position_span), - has_precision || has_width, - ); - - Exact(i) - } - parse::ArgumentImplicitlyIs(i) => { - self.unused_names_lint.maybe_add_positional_named_arg( - self.args.get(i), - PositionalNamedArgType::Arg, - self.curpiece, - None, - has_precision || has_width, - ); - Exact(i) - } - parse::ArgumentNamed(s) => { - let symbol = Symbol::intern(s); - let span = arg.position_span; - Named(symbol, InnerSpan::new(span.start, span.end)) - } - }; - - let ty = Placeholder(match arg.format.ty { - "" => "Display", - "?" => "Debug", - "e" => "LowerExp", - "E" => "UpperExp", - "o" => "Octal", - "p" => "Pointer", - "b" => "Binary", - "x" => "LowerHex", - "X" => "UpperHex", - _ => { - let fmtsp = self.fmtsp; - let sp = arg - .format - .ty_span - .map(|sp| fmtsp.from_inner(InnerSpan::new(sp.start, sp.end))); - let mut err = self.ecx.struct_span_err( - sp.unwrap_or(fmtsp), - &format!("unknown format trait `{}`", arg.format.ty), - ); - err.note( - "the only appropriate formatting traits are:\n\ - - ``, which uses the `Display` trait\n\ - - `?`, which uses the `Debug` trait\n\ - - `e`, which uses the `LowerExp` trait\n\ - - `E`, which uses the `UpperExp` trait\n\ - - `o`, which uses the `Octal` trait\n\ - - `p`, which uses the `Pointer` trait\n\ - - `b`, which uses the `Binary` trait\n\ - - `x`, which uses the `LowerHex` trait\n\ - - `X`, which uses the `UpperHex` trait", - ); - if let Some(sp) = sp { - for (fmt, name) in &[ - ("", "Display"), - ("?", "Debug"), - ("e", "LowerExp"), - ("E", "UpperExp"), - ("o", "Octal"), - ("p", "Pointer"), - ("b", "Binary"), - ("x", "LowerHex"), - ("X", "UpperHex"), - ] { - // FIXME: rustfix (`run-rustfix`) fails to apply suggestions. - // > "Cannot replace slice of data that was already replaced" - err.tool_only_span_suggestion( - sp, - &format!("use the `{}` trait", name), - *fmt, - Applicability::MaybeIncorrect, - ); - } - } - err.emit(); - "" - } - }); - self.verify_arg_type(pos, ty); - self.curpiece += 1; - } - } - } - - fn verify_count( - &mut self, - c: parse::Count<'_>, - inner_span: &Option, - named_arg_type: PositionalNamedArgType, - ) { - match c { - parse::CountImplied | parse::CountIs(..) => {} - parse::CountIsParam(i) | parse::CountIsStar(i) => { - self.unused_names_lint.maybe_add_positional_named_arg( - self.args.get(i), - named_arg_type, - self.curpiece, - *inner_span, - true, - ); - self.verify_arg_type(Exact(i), Count); - } - parse::CountIsName(s, span) => { - self.verify_arg_type( - Named(Symbol::intern(s), InnerSpan::new(span.start, span.end)), - Count, - ); - } - } - } - - fn describe_num_args(&self) -> Cow<'_, str> { - match self.num_args() { - 0 => "no arguments were given".into(), - 1 => "there is 1 argument".into(), - x => format!("there are {} arguments", x).into(), - } - } - - /// Handle invalid references to positional arguments. Output different - /// errors for the case where all arguments are positional and for when - /// there are named arguments or numbered positional arguments in the - /// format string. - fn report_invalid_references(&self, numbered_position_args: bool) { - let mut e; - let sp = if !self.arg_spans.is_empty() { - // Point at the formatting arguments. - MultiSpan::from_spans(self.arg_spans.clone()) - } else { - MultiSpan::from_span(self.fmtsp) - }; - let refs = - self.invalid_refs.iter().map(|(r, pos)| (r.to_string(), self.arg_spans.get(*pos))); - - let mut zero_based_note = false; - - let count = self.pieces.len() - + self - .arg_with_formatting - .iter() - .filter(|fmt| matches!(fmt.precision, parse::CountIsStar(_))) - .count(); - if self.names.is_empty() && !numbered_position_args && count != self.num_args() { - e = self.ecx.struct_span_err( - sp, - &format!( - "{} positional argument{} in format string, but {}", - count, - pluralize!(count), - self.describe_num_args(), - ), - ); - for arg in &self.args { - // Point at the arguments that will be formatted. - e.span_label(arg.expr.span, ""); - } - } else { - let (mut refs, spans): (Vec<_>, Vec<_>) = refs.unzip(); - // Avoid `invalid reference to positional arguments 7 and 7 (there is 1 argument)` - // for `println!("{7:7$}", 1);` - refs.sort(); - refs.dedup(); - let spans: Vec<_> = spans.into_iter().filter_map(|sp| sp.copied()).collect(); - let sp = if self.arg_spans.is_empty() || spans.is_empty() { - MultiSpan::from_span(self.fmtsp) - } else { - MultiSpan::from_spans(spans) - }; - let arg_list = if refs.len() == 1 { - format!("argument {}", refs[0]) - } else { - let reg = refs.pop().unwrap(); - format!("arguments {head} and {tail}", head = refs.join(", "), tail = reg) - }; - - e = self.ecx.struct_span_err( - sp, - &format!( - "invalid reference to positional {} ({})", - arg_list, - self.describe_num_args() - ), - ); - zero_based_note = true; - }; - - for fmt in &self.arg_with_formatting { - if let Some(span) = fmt.precision_span { - let span = self.fmtsp.from_inner(InnerSpan::new(span.start, span.end)); - match fmt.precision { - parse::CountIsParam(pos) if pos >= self.num_args() => { - e.span_label( - span, - &format!( - "this precision flag expects an `usize` argument at position {}, \ - but {}", - pos, - self.describe_num_args(), - ), - ); - zero_based_note = true; - } - parse::CountIsStar(pos) => { - let count = self.pieces.len() - + self - .arg_with_formatting - .iter() - .filter(|fmt| matches!(fmt.precision, parse::CountIsStar(_))) - .count(); - e.span_label( - span, - &format!( - "this precision flag adds an extra required argument at position {}, \ - which is why there {} expected", - pos, - if count == 1 { - "is 1 argument".to_string() - } else { - format!("are {} arguments", count) - }, - ), - ); - if let Some(arg) = self.args.get(pos) { - e.span_label( - arg.expr.span, - "this parameter corresponds to the precision flag", - ); - } - zero_based_note = true; - } - _ => {} - } - } - if let Some(span) = fmt.width_span { - let span = self.fmtsp.from_inner(InnerSpan::new(span.start, span.end)); - match fmt.width { - parse::CountIsParam(pos) if pos >= self.num_args() => { - e.span_label( - span, - &format!( - "this width flag expects an `usize` argument at position {}, \ - but {}", - pos, - self.describe_num_args(), - ), - ); - zero_based_note = true; - } - _ => {} - } - } - } - if zero_based_note { - e.note("positional arguments are zero-based"); - } - if !self.arg_with_formatting.is_empty() { - e.note( - "for information about formatting flags, visit \ - https://doc.rust-lang.org/std/fmt/index.html", - ); - } - - e.emit(); - } - - /// Actually verifies and tracks a given format placeholder - /// (a.k.a. argument). - fn verify_arg_type(&mut self, arg: Position, ty: ArgumentType) { - if let Exact(arg) = arg { - if arg >= self.num_args() { - self.invalid_refs.push((arg, self.curpiece)); - return; - } - } - - match arg { - Exact(arg) | Capture(arg) => { - match ty { - Placeholder(_) => { - // record every (position, type) combination only once - let seen_ty = &mut self.arg_unique_types[arg]; - let i = seen_ty.iter().position(|x| *x == ty).unwrap_or_else(|| { - let i = seen_ty.len(); - seen_ty.push(ty); - i - }); - self.arg_types[arg].push(i); - } - Count => { - if let Entry::Vacant(e) = self.count_positions.entry(arg) { - let i = self.count_positions_count; - e.insert(i); - self.count_args.push(arg); - self.count_positions_count += 1; - } - } - } - } - - Named(name, span) => { - match self.names.get(&name) { - Some(&idx) => { - // Treat as positional arg. - self.verify_arg_type(Capture(idx), ty) - } - None => { - // For the moment capturing variables from format strings expanded from macros is - // disabled (see RFC #2795) - if self.is_literal { - // Treat this name as a variable to capture from the surrounding scope - let idx = self.args.len(); - self.arg_types.push(Vec::new()); - self.arg_unique_types.push(Vec::new()); - let span = if self.is_literal { - self.fmtsp.from_inner(span) - } else { - self.fmtsp - }; - self.num_captured_args += 1; - self.args.push(FormatArg { - expr: self.ecx.expr_ident(span, Ident::new(name, span)), - name: Some(Ident::new(name, span)), - }); - self.names.insert(name, idx); - self.verify_arg_type(Capture(idx), ty) - } else { - let msg = format!("there is no argument named `{}`", name); - let sp = if self.is_literal { - self.fmtsp.from_inner(span) - } else { - self.fmtsp - }; - let mut err = self.ecx.struct_span_err(sp, &msg); - - err.note(&format!( - "did you intend to capture a variable `{}` from \ - the surrounding scope?", - name - )); - err.note( - "to avoid ambiguity, `format_args!` cannot capture variables \ - when the format string is expanded from a macro", - ); - - err.emit(); - } - } - } - } - } - } - - /// Builds the mapping between format placeholders and argument objects. - fn build_index_map(&mut self) { - // NOTE: Keep the ordering the same as `into_expr`'s expansion would do! - let args_len = self.args.len(); - self.arg_index_map.reserve(args_len); - - let mut sofar = 0usize; - - // Map the arguments - for i in 0..args_len { - let arg_types = &self.arg_types[i]; - let arg_offsets = arg_types.iter().map(|offset| sofar + *offset).collect::>(); - self.arg_index_map.push(arg_offsets); - sofar += self.arg_unique_types[i].len(); - } - - // Record starting index for counts, which appear just after arguments - self.count_args_index_offset = sofar; - } - - fn rtpath(ecx: &ExtCtxt<'_>, s: Symbol) -> Vec { - ecx.std_path(&[sym::fmt, sym::rt, sym::v1, s]) - } - - fn build_count(&self, c: parse::Count<'_>) -> P { - let sp = self.macsp; - let count = |c, arg| { - let mut path = Context::rtpath(self.ecx, sym::Count); - path.push(Ident::new(c, sp)); - match arg { - Some(arg) => self.ecx.expr_call_global(sp, path, vec![arg]), - None => self.ecx.expr_path(self.ecx.path_global(sp, path)), - } - }; - match c { - parse::CountIs(i) => count(sym::Is, Some(self.ecx.expr_usize(sp, i))), - parse::CountIsParam(i) | parse::CountIsStar(i) => { - // This needs mapping too, as `i` is referring to a macro - // argument. If `i` is not found in `count_positions` then - // the error had already been emitted elsewhere. - let i = self.count_positions.get(&i).cloned().unwrap_or(0) - + self.count_args_index_offset; - count(sym::Param, Some(self.ecx.expr_usize(sp, i))) - } - parse::CountImplied => count(sym::Implied, None), - // should never be the case, names are already resolved - parse::CountIsName(..) => panic!("should never happen"), - } - } - - /// Build a literal expression from the accumulated string literals - fn build_literal_string(&mut self) -> P { - let sp = self.fmtsp; - let s = Symbol::intern(&self.literal); - self.literal.clear(); - self.ecx.expr_str(sp, s) - } - - /// Builds a static `rt::Argument` from a `parse::Piece` or append - /// to the `literal` string. - fn build_piece( - &mut self, - piece: &parse::Piece<'a>, - arg_index_consumed: &mut Vec, - ) -> Option> { - let sp = self.macsp; - match *piece { - parse::String(s) => { - self.literal.push_str(s); - None - } - parse::NextArgument(ref arg) => { - // Build the position - let pos = { - match arg.position { - parse::ArgumentIs(i, ..) | parse::ArgumentImplicitlyIs(i) => { - // Map to index in final generated argument array - // in case of multiple types specified - let arg_idx = match arg_index_consumed.get_mut(i) { - None => 0, // error already emitted elsewhere - Some(offset) => { - let idx_map = &self.arg_index_map[i]; - // unwrap_or branch: error already emitted elsewhere - let arg_idx = *idx_map.get(*offset).unwrap_or(&0); - *offset += 1; - arg_idx - } - }; - self.ecx.expr_usize(sp, arg_idx) - } - - // should never be the case, because names are already - // resolved. - parse::ArgumentNamed(..) => panic!("should never happen"), - } - }; - - let simple_arg = parse::Argument { - position: { - // We don't have ArgumentNext any more, so we have to - // track the current argument ourselves. - let i = self.curarg; - self.curarg += 1; - parse::ArgumentIs(i) - }, - position_span: arg.position_span, - format: parse::FormatSpec { - fill: None, - align: parse::AlignUnknown, - flags: 0, - precision: parse::CountImplied, - precision_span: arg.format.precision_span, - width: parse::CountImplied, - width_span: arg.format.width_span, - ty: arg.format.ty, - ty_span: arg.format.ty_span, - }, - }; - - let fill = arg.format.fill.unwrap_or(' '); - let pos_simple = arg.position.index() == simple_arg.position.index(); - - if !pos_simple || arg.format != simple_arg.format { - self.all_pieces_simple = false; - } - - // Build the format - let fill = self.ecx.expr_char(sp, fill); - let align = |name| { - let mut p = Context::rtpath(self.ecx, sym::Alignment); - p.push(Ident::new(name, sp)); - self.ecx.path_global(sp, p) - }; - let align = match arg.format.align { - parse::AlignLeft => align(sym::Left), - parse::AlignRight => align(sym::Right), - parse::AlignCenter => align(sym::Center), - parse::AlignUnknown => align(sym::Unknown), - }; - let align = self.ecx.expr_path(align); - let flags = self.ecx.expr_u32(sp, arg.format.flags); - let prec = self.build_count(arg.format.precision); - let width = self.build_count(arg.format.width); - let path = self.ecx.path_global(sp, Context::rtpath(self.ecx, sym::FormatSpec)); - let fmt = self.ecx.expr_struct( - sp, - path, - vec![ - self.ecx.field_imm(sp, Ident::new(sym::fill, sp), fill), - self.ecx.field_imm(sp, Ident::new(sym::align, sp), align), - self.ecx.field_imm(sp, Ident::new(sym::flags, sp), flags), - self.ecx.field_imm(sp, Ident::new(sym::precision, sp), prec), - self.ecx.field_imm(sp, Ident::new(sym::width, sp), width), - ], - ); - - let path = self.ecx.path_global(sp, Context::rtpath(self.ecx, sym::Argument)); - Some(self.ecx.expr_struct( - sp, - path, - vec![ - self.ecx.field_imm(sp, Ident::new(sym::position, sp), pos), - self.ecx.field_imm(sp, Ident::new(sym::format, sp), fmt), - ], - )) - } - } - } - - /// Actually builds the expression which the format_args! block will be - /// expanded to. - fn into_expr(self) -> P { - let mut original_args = self.args; - let mut fmt_args = Vec::with_capacity( - self.arg_unique_types.iter().map(|v| v.len()).sum::() + self.count_args.len(), - ); - - // First, build up the static array which will become our precompiled - // format "string" - let pieces = self.ecx.expr_array_ref(self.fmtsp, self.str_pieces); - - // We need to construct a &[ArgumentV1] to pass into the fmt::Arguments - // constructor. In general the expressions in this slice might be - // permuted from their order in original_args (such as in the case of - // "{1} {0}"), or may have multiple entries referring to the same - // element of original_args ("{0} {0}"). - // - // The following vector has one item per element of our output slice, - // identifying the index of which element of original_args it's passing, - // and that argument's type. - let mut fmt_arg_index_and_ty = SmallVec::<[(usize, &ArgumentType); 8]>::new(); - for (i, unique_types) in self.arg_unique_types.iter().enumerate() { - fmt_arg_index_and_ty.extend(unique_types.iter().map(|ty| (i, ty))); - } - fmt_arg_index_and_ty.extend(self.count_args.iter().map(|&i| (i, &Count))); - - // Figure out whether there are permuted or repeated elements. If not, - // we can generate simpler code. - // - // The sequence has no indices out of order or repeated if: for every - // adjacent pair of elements, the first one's index is less than the - // second one's index. - let nicely_ordered = - fmt_arg_index_and_ty.array_windows().all(|[(i, _i_ty), (j, _j_ty)]| i < j); - - // We want to emit: - // - // [ArgumentV1::new(&$arg0, …), ArgumentV1::new(&$arg1, …), …] - // - // However, it's only legal to do so if $arg0, $arg1, … were written in - // exactly that order by the programmer. When arguments are permuted, we - // want them evaluated in the order written by the programmer, not in - // the order provided to fmt::Arguments. When arguments are repeated, we - // want the expression evaluated only once. - // - // Further, if any arg _after the first one_ contains a yield point such - // as `await` or `yield`, the above short form is inconvenient for the - // caller because it would keep a temporary of type ArgumentV1 alive - // across the yield point. ArgumentV1 can't implement Send since it - // holds a type-erased arbitrary type. - // - // Thus in the not nicely ordered case, and in the yielding case, we - // emit the following instead: - // - // match (&$arg0, &$arg1, …) { - // args => [ArgumentV1::new(args.$i, …), ArgumentV1::new(args.$j, …), …] - // } - // - // for the sequence of indices $i, $j, … governed by fmt_arg_index_and_ty. - // This more verbose representation ensures that all arguments are - // evaluated a single time each, in the order written by the programmer, - // and that the surrounding future/generator (if any) is Send whenever - // possible. - let no_need_for_match = nicely_ordered - && !original_args.iter().skip(1).any(|arg| may_contain_yield_point(&arg.expr)); - - for (arg_index, arg_ty) in fmt_arg_index_and_ty { - let e = &mut original_args[arg_index].expr; - let span = e.span; - let arg = if no_need_for_match { - let expansion_span = e.span.with_ctxt(self.macsp.ctxt()); - // The indices are strictly ordered so e has not been taken yet. - self.ecx.expr_addr_of(expansion_span, P(e.take())) - } else { - let def_site = self.ecx.with_def_site_ctxt(span); - let args_tuple = self.ecx.expr_ident(def_site, Ident::new(sym::args, def_site)); - let member = Ident::new(sym::integer(arg_index), def_site); - self.ecx.expr(def_site, ast::ExprKind::Field(args_tuple, member)) - }; - fmt_args.push(Context::format_arg(self.ecx, self.macsp, span, arg_ty, arg)); - } - - let args_array = self.ecx.expr_array(self.macsp, fmt_args); - let args_slice = self.ecx.expr_addr_of( - self.macsp, - if no_need_for_match { - args_array - } else { - // In the !no_need_for_match case, none of the exprs were moved - // away in the previous loop. - // - // This uses the arg span for `&arg` so that borrowck errors - // point to the specific expression passed to the macro (the - // span is otherwise unavailable in the MIR used by borrowck). - let heads = original_args - .into_iter() - .map(|arg| { - self.ecx.expr_addr_of(arg.expr.span.with_ctxt(self.macsp.ctxt()), arg.expr) - }) - .collect(); - - let pat = self.ecx.pat_ident(self.macsp, Ident::new(sym::args, self.macsp)); - let arm = self.ecx.arm(self.macsp, pat, args_array); - let head = self.ecx.expr(self.macsp, ast::ExprKind::Tup(heads)); - self.ecx.expr_match(self.macsp, head, vec![arm]) - }, - ); - - // Now create the fmt::Arguments struct with all our locals we created. - let (fn_name, fn_args) = if self.all_pieces_simple { - ("new_v1", vec![pieces, args_slice]) - } else { - // Build up the static array which will store our precompiled - // nonstandard placeholders, if there are any. - let fmt = self.ecx.expr_array_ref(self.macsp, self.pieces); - - let path = self.ecx.std_path(&[sym::fmt, sym::UnsafeArg, sym::new]); - let unsafe_arg = self.ecx.expr_call_global(self.macsp, path, Vec::new()); - let unsafe_expr = self.ecx.expr_block(P(ast::Block { - stmts: vec![self.ecx.stmt_expr(unsafe_arg)], - id: ast::DUMMY_NODE_ID, - rules: BlockCheckMode::Unsafe(UnsafeSource::CompilerGenerated), - span: self.macsp, - tokens: None, - could_be_bare_literal: false, - })); - - ("new_v1_formatted", vec![pieces, args_slice, fmt, unsafe_expr]) - }; - - let path = self.ecx.std_path(&[sym::fmt, sym::Arguments, Symbol::intern(fn_name)]); - self.ecx.expr_call_global(self.macsp, path, fn_args) - } - - fn format_arg( - ecx: &ExtCtxt<'_>, - macsp: Span, - mut sp: Span, - ty: &ArgumentType, - arg: P, - ) -> P { - sp = ecx.with_def_site_ctxt(sp); - let trait_ = match *ty { - Placeholder(trait_) if trait_ == "" => return DummyResult::raw_expr(sp, true), - Placeholder(trait_) => trait_, - Count => { - let path = ecx.std_path(&[sym::fmt, sym::ArgumentV1, sym::from_usize]); - return ecx.expr_call_global(macsp, path, vec![arg]); - } - }; - let new_fn_name = match trait_ { - "Display" => "new_display", - "Debug" => "new_debug", - "LowerExp" => "new_lower_exp", - "UpperExp" => "new_upper_exp", - "Octal" => "new_octal", - "Pointer" => "new_pointer", - "Binary" => "new_binary", - "LowerHex" => "new_lower_hex", - "UpperHex" => "new_upper_hex", - _ => unreachable!(), - }; - - let path = ecx.std_path(&[sym::fmt, sym::ArgumentV1, Symbol::intern(new_fn_name)]); - ecx.expr_call_global(sp, path, vec![arg]) - } -} - -fn expand_format_args_impl<'cx>( - ecx: &'cx mut ExtCtxt<'_>, - mut sp: Span, - tts: TokenStream, - nl: bool, -) -> Box { - sp = ecx.with_def_site_ctxt(sp); - match parse_args(ecx, sp, tts) { - Ok((efmt, args, names)) => { - MacEager::expr(expand_preparsed_format_args(ecx, sp, efmt, args, names, nl)) - } - Err(mut err) => { - err.emit(); - DummyResult::any(sp) - } - } -} - -pub fn expand_format_args<'cx>( - ecx: &'cx mut ExtCtxt<'_>, - sp: Span, - tts: TokenStream, -) -> Box { - expand_format_args_impl(ecx, sp, tts, false) -} - -pub fn expand_format_args_nl<'cx>( - ecx: &'cx mut ExtCtxt<'_>, - sp: Span, - tts: TokenStream, -) -> Box { - expand_format_args_impl(ecx, sp, tts, true) -} - -fn create_lints_for_named_arguments_used_positionally(cx: &mut Context<'_, '_>) { - for named_arg in &cx.unused_names_lint.positional_named_args { - let (position_sp_to_replace, position_sp_for_msg) = named_arg.get_positional_arg_spans(cx); - - let msg = format!("named argument `{}` is not used by name", named_arg.replacement); - - cx.ecx.buffered_early_lint.push(BufferedEarlyLint { - span: MultiSpan::from_span(named_arg.positional_named_arg_span), - msg: msg.into(), - node_id: ast::CRATE_NODE_ID, - lint_id: LintId::of(&NAMED_ARGUMENTS_USED_POSITIONALLY), - diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally { - position_sp_to_replace, - position_sp_for_msg, - named_arg_sp: named_arg.positional_named_arg_span, - named_arg_name: named_arg.replacement.to_string(), - is_formatting_arg: named_arg.ty != PositionalNamedArgType::Arg, - }, - }); - } -} - -/// Take the various parts of `format_args!(efmt, args..., name=names...)` -/// and construct the appropriate formatting expression. -pub fn expand_preparsed_format_args( +pub fn make_format_args( ecx: &mut ExtCtxt<'_>, - sp: Span, - efmt: P, - args: Vec, - names: FxHashMap, + efmt: P, + mut args: FormatArguments, append_newline: bool, -) -> P { - // NOTE: this verbose way of initializing `Vec>` is because - // `ArgumentType` does not derive `Clone`. - let arg_types: Vec<_> = (0..args.len()).map(|_| Vec::new()).collect(); - let arg_unique_types: Vec<_> = (0..args.len()).map(|_| Vec::new()).collect(); - - let mut macsp = ecx.call_site(); - macsp = ecx.with_def_site_ctxt(macsp); - +) -> Result { let msg = "format argument must be a string literal"; - let fmt_sp = efmt.span; - let efmt_kind_is_lit: bool = matches!(efmt.kind, ast::ExprKind::Lit(_)); + let fmt_span = efmt.span; let (fmt_str, fmt_style, fmt_span) = match expr_to_spanned_string(ecx, efmt, msg) { Ok(mut fmt) if append_newline => { fmt.0 = Symbol::intern(&format!("{}\n", fmt.0)); @@ -1224,13 +168,13 @@ pub fn expand_preparsed_format_args( Ok(fmt) => fmt, Err(err) => { if let Some((mut err, suggested)) = err { - let sugg_fmt = match args.len() { + let sugg_fmt = match args.explicit_args().len() { 0 => "{}".to_string(), - _ => format!("{}{{}}", "{} ".repeat(args.len())), + _ => format!("{}{{}}", "{} ".repeat(args.explicit_args().len())), }; if !suggested { err.span_suggestion( - fmt_sp.shrink_to_lo(), + fmt_span.shrink_to_lo(), "you might be missing a string literal to format with", format!("\"{}\", ", sugg_fmt), Applicability::MaybeIncorrect, @@ -1238,17 +182,17 @@ pub fn expand_preparsed_format_args( } err.emit(); } - return DummyResult::raw_expr(sp, true); + return Err(()); } }; let str_style = match fmt_style { - ast::StrStyle::Cooked => None, - ast::StrStyle::Raw(raw) => Some(raw as usize), + rustc_ast::StrStyle::Cooked => None, + rustc_ast::StrStyle::Raw(raw) => Some(raw as usize), }; let fmt_str = fmt_str.as_str(); // for the suggestions below - let fmt_snippet = ecx.source_map().span_to_snippet(fmt_sp).ok(); + let fmt_snippet = ecx.source_map().span_to_snippet(fmt_span).ok(); let mut parser = parse::Parser::new( fmt_str, str_style, @@ -1257,18 +201,20 @@ pub fn expand_preparsed_format_args( parse::ParseMode::Format, ); - let mut unverified_pieces = Vec::new(); + let mut pieces = Vec::new(); while let Some(piece) = parser.next() { if !parser.errors.is_empty() { break; } else { - unverified_pieces.push(piece); + pieces.push(piece); } } + let is_literal = parser.is_literal; + if !parser.errors.is_empty() { let err = parser.errors.remove(0); - let sp = if efmt_kind_is_lit { + let sp = if is_literal { fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end)) } else { // The format string could be another macro invocation, e.g.: @@ -1286,25 +232,21 @@ pub fn expand_preparsed_format_args( if let Some(note) = err.note { e.note(¬e); } - if let Some((label, span)) = err.secondary_label { - if efmt_kind_is_lit { - e.span_label(fmt_span.from_inner(InnerSpan::new(span.start, span.end)), label); - } + if let Some((label, span)) = err.secondary_label && is_literal { + e.span_label(fmt_span.from_inner(InnerSpan::new(span.start, span.end)), label); } if err.should_be_replaced_with_positional_argument { let captured_arg_span = fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end)); - let n_positional_args = - args.iter().rposition(|arg| arg.name.is_none()).map_or(0, |i| i + 1); if let Ok(arg) = ecx.source_map().span_to_snippet(captured_arg_span) { - let span = match args[..n_positional_args].last() { + let span = match args.unnamed_args().last() { Some(arg) => arg.expr.span, - None => fmt_sp, + None => fmt_span, }; e.multipart_suggestion_verbose( "consider using a positional formatting argument instead", vec![ - (captured_arg_span, n_positional_args.to_string()), + (captured_arg_span, args.unnamed_args().len().to_string()), (span.shrink_to_hi(), format!(", {}", arg)), ], Applicability::MachineApplicable, @@ -1312,241 +254,626 @@ pub fn expand_preparsed_format_args( } } e.emit(); - return DummyResult::raw_expr(sp, true); + return Err(()); } - let arg_spans = parser - .arg_places - .iter() - .map(|span| fmt_span.from_inner(InnerSpan::new(span.start, span.end))) - .collect(); + let to_span = |inner_span: rustc_parse_format::InnerSpan| { + is_literal.then(|| { + fmt_span.from_inner(InnerSpan { start: inner_span.start, end: inner_span.end }) + }) + }; + + let mut used = vec![false; args.explicit_args().len()]; + let mut invalid_refs = Vec::new(); + let mut numeric_refences_to_named_arg = Vec::new(); - let mut cx = Context { - ecx, - args, - num_captured_args: 0, - arg_types, - arg_unique_types, - names, - curarg: 0, - curpiece: 0, - arg_index_map: Vec::new(), - count_args: Vec::new(), - count_positions: FxHashMap::default(), - count_positions_count: 0, - count_args_index_offset: 0, - literal: String::new(), - pieces: Vec::with_capacity(unverified_pieces.len()), - str_pieces: Vec::with_capacity(unverified_pieces.len()), - all_pieces_simple: true, - macsp, - fmtsp: fmt_span, - invalid_refs: Vec::new(), - arg_spans, - arg_with_formatting: Vec::new(), - is_literal: parser.is_literal, - unused_names_lint: PositionalNamedArgsLint { positional_named_args: vec![] }, + enum ArgRef<'a> { + Index(usize), + Name(&'a str, Option), + } + use ArgRef::*; + + let mut lookup_arg = |arg: ArgRef<'_>, + span: Option, + used_as: PositionUsedAs, + kind: FormatArgPositionKind| + -> FormatArgPosition { + let index = match arg { + Index(index) => { + if let Some(arg) = args.by_index(index) { + used[index] = true; + if arg.kind.ident().is_some() { + // This was a named argument, but it was used as a positional argument. + numeric_refences_to_named_arg.push((index, span, used_as)); + } + Ok(index) + } else { + // Doesn't exist as an explicit argument. + invalid_refs.push((index, span, used_as, kind)); + Err(index) + } + } + Name(name, span) => { + let name = Symbol::intern(name); + if let Some((index, _)) = args.by_name(name) { + // Name found in `args`, so we resolve it to its index. + if index < args.explicit_args().len() { + // Mark it as used, if it was an explicit argument. + used[index] = true; + } + Ok(index) + } else { + // Name not found in `args`, so we add it as an implicitly captured argument. + let span = span.unwrap_or(fmt_span); + let ident = Ident::new(name, span); + let expr = if is_literal { + ecx.expr_ident(span, ident) + } else { + // For the moment capturing variables from format strings expanded from macros is + // disabled (see RFC #2795) + ecx.struct_span_err(span, &format!("there is no argument named `{name}`")) + .note(format!("did you intend to capture a variable `{name}` from the surrounding scope?")) + .note("to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro") + .emit(); + DummyResult::raw_expr(span, true) + }; + Ok(args.add(FormatArgument { kind: FormatArgumentKind::Captured(ident), expr })) + } + } + }; + FormatArgPosition { index, kind, span } }; - // This needs to happen *after* the Parser has consumed all pieces to create all the spans - let pieces = unverified_pieces - .into_iter() - .map(|mut piece| { - cx.verify_piece(&piece); - cx.resolve_name_inplace(&mut piece); - piece - }) - .collect::>(); + let mut template = Vec::new(); + let mut unfinished_literal = String::new(); + let mut placeholder_index = 0; - let numbered_position_args = pieces.iter().any(|arg: &parse::Piece<'_>| match *arg { - parse::String(_) => false, - parse::NextArgument(arg) => matches!(arg.position, parse::Position::ArgumentIs(..)), - }); + for piece in pieces { + match piece { + parse::Piece::String(s) => { + unfinished_literal.push_str(s); + } + parse::Piece::NextArgument(parse::Argument { position, position_span, format }) => { + if !unfinished_literal.is_empty() { + template.push(FormatArgsPiece::Literal(Symbol::intern(&unfinished_literal))); + unfinished_literal.clear(); + } - cx.build_index_map(); + let span = parser.arg_places.get(placeholder_index).and_then(|&s| to_span(s)); + placeholder_index += 1; + + let position_span = to_span(position_span); + let argument = match position { + parse::ArgumentImplicitlyIs(i) => lookup_arg( + Index(i), + position_span, + Placeholder(span), + FormatArgPositionKind::Implicit, + ), + parse::ArgumentIs(i) => lookup_arg( + Index(i), + position_span, + Placeholder(span), + FormatArgPositionKind::Number, + ), + parse::ArgumentNamed(name) => lookup_arg( + Name(name, position_span), + position_span, + Placeholder(span), + FormatArgPositionKind::Named, + ), + }; - let mut arg_index_consumed = vec![0usize; cx.arg_index_map.len()]; + let alignment = match format.align { + parse::AlignUnknown => None, + parse::AlignLeft => Some(FormatAlignment::Left), + parse::AlignRight => Some(FormatAlignment::Right), + parse::AlignCenter => Some(FormatAlignment::Center), + }; - for piece in pieces { - if let Some(piece) = cx.build_piece(&piece, &mut arg_index_consumed) { - let s = cx.build_literal_string(); - cx.str_pieces.push(s); - cx.pieces.push(piece); + let format_trait = match format.ty { + "" => FormatTrait::Display, + "?" => FormatTrait::Debug, + "e" => FormatTrait::LowerExp, + "E" => FormatTrait::UpperExp, + "o" => FormatTrait::Octal, + "p" => FormatTrait::Pointer, + "b" => FormatTrait::Binary, + "x" => FormatTrait::LowerHex, + "X" => FormatTrait::UpperHex, + _ => { + invalid_placeholder_type_error(ecx, format.ty, format.ty_span, fmt_span); + FormatTrait::Display + } + }; + + let precision_span = format.precision_span.and_then(to_span); + let precision = match format.precision { + parse::CountIs(n) => Some(FormatCount::Literal(n)), + parse::CountIsName(name, name_span) => Some(FormatCount::Argument(lookup_arg( + Name(name, to_span(name_span)), + precision_span, + Precision, + FormatArgPositionKind::Named, + ))), + parse::CountIsParam(i) => Some(FormatCount::Argument(lookup_arg( + Index(i), + precision_span, + Precision, + FormatArgPositionKind::Number, + ))), + parse::CountIsStar(i) => Some(FormatCount::Argument(lookup_arg( + Index(i), + precision_span, + Precision, + FormatArgPositionKind::Implicit, + ))), + parse::CountImplied => None, + }; + + let width_span = format.width_span.and_then(to_span); + let width = match format.width { + parse::CountIs(n) => Some(FormatCount::Literal(n)), + parse::CountIsName(name, name_span) => Some(FormatCount::Argument(lookup_arg( + Name(name, to_span(name_span)), + width_span, + Width, + FormatArgPositionKind::Named, + ))), + parse::CountIsParam(i) => Some(FormatCount::Argument(lookup_arg( + Index(i), + width_span, + Width, + FormatArgPositionKind::Number, + ))), + parse::CountIsStar(_) => unreachable!(), + parse::CountImplied => None, + }; + + template.push(FormatArgsPiece::Placeholder(FormatPlaceholder { + argument, + span, + format_trait, + format_options: FormatOptions { + fill: format.fill, + alignment, + flags: format.flags, + precision, + width, + }, + })); + } } } - if !cx.literal.is_empty() { - let s = cx.build_literal_string(); - cx.str_pieces.push(s); + if !unfinished_literal.is_empty() { + template.push(FormatArgsPiece::Literal(Symbol::intern(&unfinished_literal))); } - if !cx.invalid_refs.is_empty() { - cx.report_invalid_references(numbered_position_args); + if !invalid_refs.is_empty() { + report_invalid_references(ecx, &invalid_refs, &template, fmt_span, &args, parser); } - // Make sure that all arguments were used and all arguments have types. - let errs = cx - .arg_types + let unused = used .iter() .enumerate() - .filter(|(i, ty)| ty.is_empty() && !cx.count_positions.contains_key(&i)) + .filter(|&(_, used)| !used) .map(|(i, _)| { - let msg = if cx.args[i].name.is_some() { + let msg = if let FormatArgumentKind::Named(_) = args.explicit_args()[i].kind { "named argument never used" } else { "argument never used" }; - (cx.args[i].expr.span, msg) + (args.explicit_args()[i].expr.span, msg) }) .collect::>(); - let errs_len = errs.len(); - if !errs.is_empty() { - let args_used = cx.arg_types.len() - errs_len; - let args_unused = errs_len; + if !unused.is_empty() { + // If there's a lot of unused arguments, + // let's check if this format arguments looks like another syntax (printf / shell). + let detect_foreign_fmt = unused.len() > args.explicit_args().len() / 2; + report_missing_placeholders(ecx, unused, detect_foreign_fmt, str_style, fmt_str, fmt_span); + } - let mut diag = { - if let [(sp, msg)] = &errs[..] { - let mut diag = cx.ecx.struct_span_err(*sp, *msg); - diag.span_label(*sp, *msg); - diag - } else { - let mut diag = cx.ecx.struct_span_err( - errs.iter().map(|&(sp, _)| sp).collect::>(), - "multiple unused formatting arguments", - ); - diag.span_label(cx.fmtsp, "multiple missing formatting specifiers"); - for (sp, msg) in errs { - diag.span_label(sp, msg); + // Only check for unused named argument names if there are no other errors to avoid causing + // too much noise in output errors, such as when a named argument is entirely unused. + if invalid_refs.is_empty() && ecx.sess.err_count() == 0 { + for &(index, span, used_as) in &numeric_refences_to_named_arg { + let (position_sp_to_replace, position_sp_for_msg) = match used_as { + Placeholder(pspan) => (span, pspan), + Precision => { + // Strip the leading `.` for precision. + let span = span.map(|span| span.with_lo(span.lo() + BytePos(1))); + (span, span) } - diag - } - }; + Width => (span, span), + }; + let arg_name = args.explicit_args()[index].kind.ident().unwrap(); + ecx.buffered_early_lint.push(BufferedEarlyLint { + span: arg_name.span.into(), + msg: format!("named argument `{}` is not used by name", arg_name.name).into(), + node_id: rustc_ast::CRATE_NODE_ID, + lint_id: LintId::of(&NAMED_ARGUMENTS_USED_POSITIONALLY), + diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally { + position_sp_to_replace, + position_sp_for_msg, + named_arg_sp: arg_name.span, + named_arg_name: arg_name.name.to_string(), + is_formatting_arg: matches!(used_as, Width | Precision), + }, + }); + } + } - // Used to ensure we only report translations for *one* kind of foreign format. - let mut found_foreign = false; - // Decide if we want to look for foreign formatting directives. - if args_used < args_unused { - use super::format_foreign as foreign; + Ok(FormatArgs { span: fmt_span, template, arguments: args }) +} - // The set of foreign substitutions we've explained. This prevents spamming the user - // with `%d should be written as {}` over and over again. - let mut explained = FxHashSet::default(); +fn invalid_placeholder_type_error( + ecx: &ExtCtxt<'_>, + ty: &str, + ty_span: Option, + fmt_span: Span, +) { + let sp = ty_span.map(|sp| fmt_span.from_inner(InnerSpan::new(sp.start, sp.end))); + let mut err = + ecx.struct_span_err(sp.unwrap_or(fmt_span), &format!("unknown format trait `{}`", ty)); + err.note( + "the only appropriate formatting traits are:\n\ + - ``, which uses the `Display` trait\n\ + - `?`, which uses the `Debug` trait\n\ + - `e`, which uses the `LowerExp` trait\n\ + - `E`, which uses the `UpperExp` trait\n\ + - `o`, which uses the `Octal` trait\n\ + - `p`, which uses the `Pointer` trait\n\ + - `b`, which uses the `Binary` trait\n\ + - `x`, which uses the `LowerHex` trait\n\ + - `X`, which uses the `UpperHex` trait", + ); + if let Some(sp) = sp { + for (fmt, name) in &[ + ("", "Display"), + ("?", "Debug"), + ("e", "LowerExp"), + ("E", "UpperExp"), + ("o", "Octal"), + ("p", "Pointer"), + ("b", "Binary"), + ("x", "LowerHex"), + ("X", "UpperHex"), + ] { + err.tool_only_span_suggestion( + sp, + &format!("use the `{}` trait", name), + *fmt, + Applicability::MaybeIncorrect, + ); + } + } + err.emit(); +} - macro_rules! check_foreign { - ($kind:ident) => {{ - let mut show_doc_note = false; +fn report_missing_placeholders( + ecx: &mut ExtCtxt<'_>, + unused: Vec<(Span, &str)>, + detect_foreign_fmt: bool, + str_style: Option, + fmt_str: &str, + fmt_span: Span, +) { + let mut diag = if let &[(span, msg)] = &unused[..] { + let mut diag = ecx.struct_span_err(span, msg); + diag.span_label(span, msg); + diag + } else { + let mut diag = ecx.struct_span_err( + unused.iter().map(|&(sp, _)| sp).collect::>(), + "multiple unused formatting arguments", + ); + diag.span_label(fmt_span, "multiple missing formatting specifiers"); + for &(span, msg) in &unused { + diag.span_label(span, msg); + } + diag + }; - let mut suggestions = vec![]; - // account for `"` and account for raw strings `r#` - let padding = str_style.map(|i| i + 2).unwrap_or(1); - for sub in foreign::$kind::iter_subs(fmt_str, padding) { - let (trn, success) = match sub.translate() { - Ok(trn) => (trn, true), - Err(Some(msg)) => (msg, false), + // Used to ensure we only report translations for *one* kind of foreign format. + let mut found_foreign = false; + + // Decide if we want to look for foreign formatting directives. + if detect_foreign_fmt { + use super::format_foreign as foreign; + + // The set of foreign substitutions we've explained. This prevents spamming the user + // with `%d should be written as {}` over and over again. + let mut explained = FxHashSet::default(); + + macro_rules! check_foreign { + ($kind:ident) => {{ + let mut show_doc_note = false; + + let mut suggestions = vec![]; + // account for `"` and account for raw strings `r#` + let padding = str_style.map(|i| i + 2).unwrap_or(1); + for sub in foreign::$kind::iter_subs(fmt_str, padding) { + let (trn, success) = match sub.translate() { + Ok(trn) => (trn, true), + Err(Some(msg)) => (msg, false), + + // If it has no translation, don't call it out specifically. + _ => continue, + }; + + let pos = sub.position(); + let sub = String::from(sub.as_str()); + if explained.contains(&sub) { + continue; + } + explained.insert(sub.clone()); - // If it has no translation, don't call it out specifically. - _ => continue, - }; + if !found_foreign { + found_foreign = true; + show_doc_note = true; + } - let pos = sub.position(); - let sub = String::from(sub.as_str()); - if explained.contains(&sub) { - continue; - } - explained.insert(sub.clone()); + if let Some(inner_sp) = pos { + let sp = fmt_span.from_inner(inner_sp); - if !found_foreign { - found_foreign = true; - show_doc_note = true; + if success { + suggestions.push((sp, trn)); + } else { + diag.span_note( + sp, + &format!("format specifiers use curly braces, and {}", trn), + ); } - - if let Some(inner_sp) = pos { - let sp = fmt_sp.from_inner(inner_sp); - - if success { - suggestions.push((sp, trn)); - } else { - diag.span_note( - sp, - &format!("format specifiers use curly braces, and {}", trn), - ); - } + } else { + if success { + diag.help(&format!("`{}` should be written as `{}`", sub, trn)); } else { - if success { - diag.help(&format!("`{}` should be written as `{}`", sub, trn)); - } else { - diag.note(&format!( - "`{}` should use curly braces, and {}", - sub, trn - )); - } + diag.note(&format!("`{}` should use curly braces, and {}", sub, trn)); } } + } - if show_doc_note { - diag.note(concat!( - stringify!($kind), - " formatting not supported; see the documentation for `std::fmt`", - )); - } - if suggestions.len() > 0 { - diag.multipart_suggestion( - "format specifiers use curly braces", - suggestions, - Applicability::MachineApplicable, - ); - } - }}; - } - - check_foreign!(printf); - if !found_foreign { - check_foreign!(shell); - } - } - if !found_foreign && errs_len == 1 { - diag.span_label(cx.fmtsp, "formatting specifier missing"); + if show_doc_note { + diag.note(concat!( + stringify!($kind), + " formatting not supported; see the documentation for `std::fmt`", + )); + } + if suggestions.len() > 0 { + diag.multipart_suggestion( + "format specifiers use curly braces", + suggestions, + Applicability::MachineApplicable, + ); + } + }}; } - diag.emit(); - } else if cx.invalid_refs.is_empty() && cx.ecx.sess.err_count() == 0 { - // Only check for unused named argument names if there are no other errors to avoid causing - // too much noise in output errors, such as when a named argument is entirely unused. - create_lints_for_named_arguments_used_positionally(&mut cx); + check_foreign!(printf); + if !found_foreign { + check_foreign!(shell); + } + } + if !found_foreign && unused.len() == 1 { + diag.span_label(fmt_span, "formatting specifier missing"); } - cx.into_expr() + diag.emit(); } -fn may_contain_yield_point(e: &ast::Expr) -> bool { - struct MayContainYieldPoint(bool); +/// Handle invalid references to positional arguments. Output different +/// errors for the case where all arguments are positional and for when +/// there are named arguments or numbered positional arguments in the +/// format string. +fn report_invalid_references( + ecx: &mut ExtCtxt<'_>, + invalid_refs: &[(usize, Option, PositionUsedAs, FormatArgPositionKind)], + template: &[FormatArgsPiece], + fmt_span: Span, + args: &FormatArguments, + parser: parse::Parser<'_>, +) { + let num_args_desc = match args.explicit_args().len() { + 0 => "no arguments were given".to_string(), + 1 => "there is 1 argument".to_string(), + n => format!("there are {} arguments", n), + }; + + let mut e; - impl Visitor<'_> for MayContainYieldPoint { - fn visit_expr(&mut self, e: &ast::Expr) { - if let ast::ExprKind::Await(_) | ast::ExprKind::Yield(_) = e.kind { - self.0 = true; - } else { - visit::walk_expr(self, e); + if template.iter().all(|piece| match piece { + FormatArgsPiece::Placeholder(FormatPlaceholder { + argument: FormatArgPosition { kind: FormatArgPositionKind::Number, .. }, + .. + }) => false, + FormatArgsPiece::Placeholder(FormatPlaceholder { + format_options: + FormatOptions { + precision: + Some(FormatCount::Argument(FormatArgPosition { + kind: FormatArgPositionKind::Number, + .. + })), + .. + } + | FormatOptions { + width: + Some(FormatCount::Argument(FormatArgPosition { + kind: FormatArgPositionKind::Number, + .. + })), + .. + }, + .. + }) => false, + _ => true, + }) { + // There are no numeric positions. + // Collect all the implicit positions: + let mut spans = Vec::new(); + let mut num_placeholders = 0; + for piece in template { + let mut placeholder = None; + // `{arg:.*}` + if let FormatArgsPiece::Placeholder(FormatPlaceholder { + format_options: + FormatOptions { + precision: + Some(FormatCount::Argument(FormatArgPosition { + span, + kind: FormatArgPositionKind::Implicit, + .. + })), + .. + }, + .. + }) = piece + { + placeholder = *span; + num_placeholders += 1; } + // `{}` + if let FormatArgsPiece::Placeholder(FormatPlaceholder { + argument: FormatArgPosition { kind: FormatArgPositionKind::Implicit, .. }, + span, + .. + }) = piece + { + placeholder = *span; + num_placeholders += 1; + } + // For `{:.*}`, we only push one span. + spans.extend(placeholder); } - - fn visit_mac_call(&mut self, _: &ast::MacCall) { - self.0 = true; + let span = if spans.is_empty() { + MultiSpan::from_span(fmt_span) + } else { + MultiSpan::from_spans(spans) + }; + e = ecx.struct_span_err( + span, + &format!( + "{} positional argument{} in format string, but {}", + num_placeholders, + pluralize!(num_placeholders), + num_args_desc, + ), + ); + for arg in args.explicit_args() { + e.span_label(arg.expr.span, ""); + } + // Point out `{:.*}` placeholders: those take an extra argument. + let mut has_precision_star = false; + for piece in template { + if let FormatArgsPiece::Placeholder(FormatPlaceholder { + format_options: + FormatOptions { + precision: + Some(FormatCount::Argument(FormatArgPosition { + index, + span: Some(span), + kind: FormatArgPositionKind::Implicit, + .. + })), + .. + }, + .. + }) = piece + { + let (Ok(index) | Err(index)) = index; + has_precision_star = true; + e.span_label( + *span, + &format!( + "this precision flag adds an extra required argument at position {}, which is why there {} expected", + index, + if num_placeholders == 1 { + "is 1 argument".to_string() + } else { + format!("are {} arguments", num_placeholders) + }, + ), + ); + } + } + if has_precision_star { + e.note("positional arguments are zero-based"); } + } else { + let mut indexes: Vec<_> = invalid_refs.iter().map(|&(index, _, _, _)| index).collect(); + // Avoid `invalid reference to positional arguments 7 and 7 (there is 1 argument)` + // for `println!("{7:7$}", 1);` + indexes.sort(); + indexes.dedup(); + let span: MultiSpan = if !parser.is_literal || parser.arg_places.is_empty() { + MultiSpan::from_span(fmt_span) + } else { + MultiSpan::from_spans(invalid_refs.iter().filter_map(|&(_, span, _, _)| span).collect()) + }; + let arg_list = if let &[index] = &indexes[..] { + format!("argument {index}") + } else { + let tail = indexes.pop().unwrap(); + format!( + "arguments {head} and {tail}", + head = indexes.into_iter().map(|i| i.to_string()).collect::>().join(", ") + ) + }; + e = ecx.struct_span_err( + span, + &format!("invalid reference to positional {} ({})", arg_list, num_args_desc), + ); + e.note("positional arguments are zero-based"); + } - fn visit_attribute(&mut self, _: &ast::Attribute) { - // Conservatively assume this may be a proc macro attribute in - // expression position. - self.0 = true; + if template.iter().any(|piece| match piece { + FormatArgsPiece::Placeholder(FormatPlaceholder { format_options: f, .. }) => { + *f != FormatOptions::default() } + _ => false, + }) { + e.note("for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html"); + } + + e.emit(); +} - fn visit_item(&mut self, _: &ast::Item) { - // Do not recurse into nested items. +fn expand_format_args_impl<'cx>( + ecx: &'cx mut ExtCtxt<'_>, + mut sp: Span, + tts: TokenStream, + nl: bool, +) -> Box { + sp = ecx.with_def_site_ctxt(sp); + match parse_args(ecx, sp, tts) { + Ok((efmt, args)) => { + if let Ok(format_args) = make_format_args(ecx, efmt, args, nl) { + MacEager::expr(expand_parsed_format_args(ecx, format_args)) + } else { + MacEager::expr(DummyResult::raw_expr(sp, true)) + } + } + Err(mut err) => { + err.emit(); + DummyResult::any(sp) } } +} + +pub fn expand_format_args<'cx>( + ecx: &'cx mut ExtCtxt<'_>, + sp: Span, + tts: TokenStream, +) -> Box { + expand_format_args_impl(ecx, sp, tts, false) +} - let mut visitor = MayContainYieldPoint(false); - visitor.visit_expr(e); - visitor.0 +pub fn expand_format_args_nl<'cx>( + ecx: &'cx mut ExtCtxt<'_>, + sp: Span, + tts: TokenStream, +) -> Box { + expand_format_args_impl(ecx, sp, tts, true) } diff --git a/compiler/rustc_builtin_macros/src/format/ast.rs b/compiler/rustc_builtin_macros/src/format/ast.rs new file mode 100644 index 0000000000000..01dbffa21b8aa --- /dev/null +++ b/compiler/rustc_builtin_macros/src/format/ast.rs @@ -0,0 +1,240 @@ +use rustc_ast::ptr::P; +use rustc_ast::Expr; +use rustc_data_structures::fx::FxHashMap; +use rustc_span::symbol::{Ident, Symbol}; +use rustc_span::Span; + +// Definitions: +// +// format_args!("hello {abc:.xyz$}!!", abc="world"); +// └──────────────────────────────────────────────┘ +// FormatArgs +// +// format_args!("hello {abc:.xyz$}!!", abc="world"); +// └─────────┘ +// argument +// +// format_args!("hello {abc:.xyz$}!!", abc="world"); +// └───────────────────┘ +// template +// +// format_args!("hello {abc:.xyz$}!!", abc="world"); +// └────┘└─────────┘└┘ +// pieces +// +// format_args!("hello {abc:.xyz$}!!", abc="world"); +// └────┘ └┘ +// literal pieces +// +// format_args!("hello {abc:.xyz$}!!", abc="world"); +// └─────────┘ +// placeholder +// +// format_args!("hello {abc:.xyz$}!!", abc="world"); +// └─┘ └─┘ +// positions (could be names, numbers, empty, or `*`) + +/// (Parsed) format args. +/// +/// Basically the "AST" for a complete `format_args!()`. +/// +/// E.g., `format_args!("hello {name}");`. +#[derive(Clone, Debug)] +pub struct FormatArgs { + pub span: Span, + pub template: Vec, + pub arguments: FormatArguments, +} + +/// A piece of a format template string. +/// +/// E.g. "hello" or "{name}". +#[derive(Clone, Debug)] +pub enum FormatArgsPiece { + Literal(Symbol), + Placeholder(FormatPlaceholder), +} + +/// The arguments to format_args!(). +/// +/// E.g. `1, 2, name="ferris", n=3`, +/// but also implicit captured arguments like `x` in `format_args!("{x}")`. +#[derive(Clone, Debug)] +pub struct FormatArguments { + arguments: Vec, + num_unnamed_args: usize, + num_explicit_args: usize, + names: FxHashMap, +} + +impl FormatArguments { + pub fn new() -> Self { + Self { + arguments: Vec::new(), + names: FxHashMap::default(), + num_unnamed_args: 0, + num_explicit_args: 0, + } + } + + pub fn add(&mut self, arg: FormatArgument) -> usize { + let index = self.arguments.len(); + if let Some(name) = arg.kind.ident() { + self.names.insert(name.name, index); + } else if self.names.is_empty() { + // Only count the unnamed args before the first named arg. + // (Any later ones are errors.) + self.num_unnamed_args += 1; + } + if !matches!(arg.kind, FormatArgumentKind::Captured(..)) { + // This is an explicit argument. + // Make sure that all arguments so far are explcit. + assert_eq!( + self.num_explicit_args, + self.arguments.len(), + "captured arguments must be added last" + ); + self.num_explicit_args += 1; + } + self.arguments.push(arg); + index + } + + pub fn by_name(&self, name: Symbol) -> Option<(usize, &FormatArgument)> { + let i = *self.names.get(&name)?; + Some((i, &self.arguments[i])) + } + + pub fn by_index(&self, i: usize) -> Option<&FormatArgument> { + (i < self.num_explicit_args).then(|| &self.arguments[i]) + } + + pub fn unnamed_args(&self) -> &[FormatArgument] { + &self.arguments[..self.num_unnamed_args] + } + + pub fn named_args(&self) -> &[FormatArgument] { + &self.arguments[self.num_unnamed_args..self.num_explicit_args] + } + + pub fn explicit_args(&self) -> &[FormatArgument] { + &self.arguments[..self.num_explicit_args] + } + + pub fn into_vec(self) -> Vec { + self.arguments + } +} + +#[derive(Clone, Debug)] +pub struct FormatArgument { + pub kind: FormatArgumentKind, + pub expr: P, +} + +#[derive(Clone, Debug)] +pub enum FormatArgumentKind { + /// `format_args(…, arg)` + Normal, + /// `format_args(…, arg = 1)` + Named(Ident), + /// `format_args("… {arg} …")` + Captured(Ident), +} + +impl FormatArgumentKind { + pub fn ident(&self) -> Option { + match self { + &Self::Normal => None, + &Self::Named(id) => Some(id), + &Self::Captured(id) => Some(id), + } + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct FormatPlaceholder { + /// Index into [`FormatArgs::arguments`]. + pub argument: FormatArgPosition, + /// The span inside the format string for the full `{…}` placeholder. + pub span: Option, + /// `{}`, `{:?}`, or `{:x}`, etc. + pub format_trait: FormatTrait, + /// `{}` or `{:.5}` or `{:-^20}`, etc. + pub format_options: FormatOptions, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct FormatArgPosition { + /// Which argument this position refers to (Ok), + /// or would've referred to if it existed (Err). + pub index: Result, + /// What kind of position this is. See [`FormatArgPositionKind`]. + pub kind: FormatArgPositionKind, + /// The span of the name or number. + pub span: Option, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum FormatArgPositionKind { + /// `{}` or `{:.*}` + Implicit, + /// `{1}` or `{:1$}` or `{:.1$}` + Number, + /// `{a}` or `{:a$}` or `{:.a$}` + Named, +} + +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub enum FormatTrait { + /// `{}` + Display, + /// `{:?}` + Debug, + /// `{:e}` + LowerExp, + /// `{:E}` + UpperExp, + /// `{:o}` + Octal, + /// `{:p}` + Pointer, + /// `{:b}` + Binary, + /// `{:x}` + LowerHex, + /// `{:X}` + UpperHex, +} + +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct FormatOptions { + /// The width. E.g. `{:5}` or `{:width$}`. + pub width: Option, + /// The precision. E.g. `{:.5}` or `{:.precision$}`. + pub precision: Option, + /// The alignment. E.g. `{:>}` or `{:<}` or `{:^}`. + pub alignment: Option, + /// The fill character. E.g. the `.` in `{:.>10}`. + pub fill: Option, + /// The `+`, `-`, `0`, `#`, `x?` and `X?` flags. + pub flags: u32, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum FormatAlignment { + /// `{:<}` + Left, + /// `{:>}` + Right, + /// `{:^}` + Center, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum FormatCount { + /// `{:5}` or `{:.5}` + Literal(usize), + /// `{:.*}`, `{:.5$}`, or `{:a$}`, etc. + Argument(FormatArgPosition), +} diff --git a/compiler/rustc_builtin_macros/src/format/expand.rs b/compiler/rustc_builtin_macros/src/format/expand.rs new file mode 100644 index 0000000000000..37ff9c7549b3d --- /dev/null +++ b/compiler/rustc_builtin_macros/src/format/expand.rs @@ -0,0 +1,256 @@ +use super::*; +use rustc_ast as ast; +use rustc_span::symbol::{kw, sym, Ident}; + +pub fn expand_parsed_format_args(ecx: &mut ExtCtxt<'_>, fmt: FormatArgs) -> P { + let macsp = ecx.with_def_site_ctxt(ecx.call_site()); + + if fmt.template.is_empty() { + return ecx.expr_call_global( + macsp, + ecx.std_path(&[sym::fmt, sym::Arguments, sym::from_static_str]), + vec![ecx.expr_str(macsp, kw::Empty)], + ); + } + + if let &[FormatArgsPiece::Literal(s)] = &fmt.template[..] { + return ecx.expr_call_global( + macsp, + ecx.std_path(&[sym::fmt, sym::Arguments, sym::from_static_str]), + vec![ecx.expr_str(macsp, s)], + ); + } + + let args = Ident::new(sym::_args, macsp); + let w = Ident::new(sym::w, macsp); + + let arguments = fmt.arguments.into_vec(); + + let mut statements = Vec::new(); + + for piece in fmt.template { + match piece { + FormatArgsPiece::Literal(s) => { + // Generate: + // w.write_str("…")?; + statements.push(ecx.stmt_expr(ecx.expr( + macsp, + ast::ExprKind::Try(ecx.expr( + macsp, + ast::ExprKind::MethodCall( + ast::PathSegment::from_ident(Ident::new(sym::write_str, macsp)), + ecx.expr_ident(macsp, w), + vec![ecx.expr_str(macsp, s)], + macsp, + ), + )), + ))); + } + FormatArgsPiece::Placeholder(p) => { + // Don't set options if they're still set to defaults + // and this placeholder also uses default options. + + // Generate: + // ::core::fmt::Formatter::new(w) + let mut formatter = ecx.expr_call_global( + macsp, + ecx.std_path(&[sym::fmt, sym::Formatter, sym::new]), + vec![ecx.expr_ident(macsp, w)], + ); + + if p.format_options != FormatOptions::default() { + // Add: + // .with_options(…) + formatter = ecx.expr( + macsp, + ast::ExprKind::MethodCall( + ast::PathSegment::from_ident(Ident::new(sym::with_options, macsp)), + formatter, + vec![ + ecx.expr_u32(macsp, p.format_options.flags), + ecx.expr_char(macsp, p.format_options.fill.unwrap_or(' ')), + ecx.expr_path(ecx.path_global( + macsp, + ecx.std_path(&[ + sym::fmt, + sym::rt, + sym::v1, + sym::Alignment, + match p.format_options.alignment { + Some(FormatAlignment::Left) => sym::Left, + Some(FormatAlignment::Right) => sym::Right, + Some(FormatAlignment::Center) => sym::Center, + None => sym::Unknown, + }, + ]), + )), + make_count(ecx, macsp, &arguments, args, p.format_options.width), + make_count( + ecx, + macsp, + &arguments, + args, + p.format_options.precision, + ), + ], + macsp, + ), + ); + } + + // Generate: + // ::core::fmt::Display::fmt(arg.0, &mut formatter)?; + + let arg = if let Ok(i) = p.argument.index { + ecx.expr_field( + arguments[i].expr.span.with_ctxt(macsp.ctxt()), + ecx.expr_ident(macsp, args), + Ident::new(sym::integer(i), macsp), + ) + } else { + DummyResult::raw_expr(macsp, true) + }; + let fmt_trait = match p.format_trait { + FormatTrait::Display => sym::Display, + FormatTrait::Debug => sym::Debug, + FormatTrait::LowerExp => sym::LowerExp, + FormatTrait::UpperExp => sym::UpperExp, + FormatTrait::Octal => sym::Octal, + FormatTrait::Pointer => sym::Pointer, + FormatTrait::Binary => sym::Binary, + FormatTrait::LowerHex => sym::LowerHex, + FormatTrait::UpperHex => sym::UpperHex, + }; + statements.push(ecx.stmt_expr(ecx.expr( + macsp, + ast::ExprKind::Try(ecx.expr_call_global( + arg.span, + ecx.std_path(&[sym::fmt, fmt_trait, sym::fmt]), + vec![ + arg, + ecx.expr( + macsp, + ast::ExprKind::AddrOf( + ast::BorrowKind::Ref, + ast::Mutability::Mut, + formatter, + ), + ), + ], + )), + ))); + } + } + } + + // Generate: + // Ok(()) + statements.push(ecx.stmt_expr(ecx.expr_ok(macsp, ecx.expr_tuple(macsp, Vec::new())))); + + // Generate: + // |w: &mut dyn ::core::fmt::Write| -> ::core::fmt::Result { + // … // statements + // } + let closure = ecx.expr( + macsp, + ast::ExprKind::Closure( + ast::ClosureBinder::NotPresent, + ast::CaptureBy::Ref, + ast::Async::No, + ast::Movability::Movable, + ecx.fn_decl( + vec![ecx.param( + macsp, + w, + ecx.ty_rptr( + macsp, + ecx.ty( + macsp, + ast::TyKind::TraitObject( + vec![ast::GenericBound::Trait( + ast::PolyTraitRef::new( + vec![], + ecx.path_global( + macsp, + ecx.std_path(&[sym::fmt, sym::Write]), + ), + macsp, + ), + ast::TraitBoundModifier::None, + )], + ast::TraitObjectSyntax::Dyn, + ), + ), + None, + ast::Mutability::Mut, + ), + )], + ast::FnRetTy::Ty( + ecx.ty_path(ecx.path_global(macsp, ecx.std_path(&[sym::fmt, sym::Result]))), + ), + ), + ecx.expr_block(ecx.block(macsp, statements)), + macsp, + ), + ); + + // Generate: + // ::core::fmt::Arguments::new( + // &match (&arg0, &arg1, …) { + // args => closure, + // } + // ) + ecx.expr_call_global( + macsp, + ecx.std_path(&[sym::fmt, sym::Arguments, sym::new]), + vec![ + ecx.expr_addr_of( + macsp, + ecx.expr_match( + macsp, + ecx.expr_tuple( + macsp, + arguments + .into_iter() + .map(|arg| { + ecx.expr_addr_of(arg.expr.span.with_ctxt(macsp.ctxt()), arg.expr) + }) + .collect(), + ), + vec![ecx.arm(macsp, ecx.pat_ident(macsp, args), closure)], + ), + ), + ], + ) +} + +pub fn make_count( + ecx: &ExtCtxt<'_>, + macsp: Span, + arguments: &[FormatArgument], + args: Ident, + count: Option, +) -> P { + match count { + Some(FormatCount::Literal(n)) => ecx.expr_some(macsp, ecx.expr_usize(macsp, n)), + Some(FormatCount::Argument(arg)) => { + if let Ok(i) = arg.index { + let sp = arguments[i].expr.span.with_ctxt(macsp.ctxt()); + ecx.expr_some( + sp, + ecx.expr_deref( + sp, + ecx.expr_field( + sp, + ecx.expr_ident(macsp, args), + Ident::new(sym::integer(i), macsp), + ), + ), + ) + } else { + DummyResult::raw_expr(macsp, true) + } + } + None => ecx.expr_none(macsp), + } +} diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 280fa70451141..d76369a34a865 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -7,6 +7,7 @@ #![feature(box_patterns)] #![feature(decl_macro)] #![feature(if_let_guard)] +#![feature(is_some_with)] #![feature(is_sorted)] #![feature(let_chains)] #![feature(let_else)] diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index cf2c023c2f89f..36910fc36ec66 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -252,6 +252,10 @@ impl<'a> ExtCtxt<'a> { self.expr_ident(span, Ident::with_dummy_span(kw::SelfLower)) } + pub fn expr_field(&self, span: Span, expr: P, field: Ident) -> P { + self.expr(span, ast::ExprKind::Field(expr, field)) + } + pub fn expr_binary( &self, sp: Span, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 81b0ebfb42c54..a02789e4d8f3a 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -155,6 +155,7 @@ symbols! { BTreeEntry, BTreeMap, BTreeSet, + Binary, BinaryHeap, Borrow, BorrowMut, @@ -223,6 +224,8 @@ symbols! { Left, LinkedList, LintPass, + LowerExp, + LowerHex, Mutex, MutexGuard, N, @@ -237,6 +240,7 @@ symbols! { NonZeroU64, NonZeroU8, None, + Octal, Ok, Option, Ord, @@ -299,9 +303,12 @@ symbols! { TyKind, Unknown, UnsafeArg, + UpperExp, + UpperHex, Vec, VecDeque, Wrapper, + Write, Yield, _DECLS, _Self, @@ -310,6 +317,7 @@ symbols! { __S, __awaitee, __try_var, + _args, _d, _e, _task_context, @@ -754,6 +762,7 @@ symbols! { from_output, from_residual, from_size_align_unchecked, + from_static_str, from_usize, from_yeet, fsub_fast, @@ -989,7 +998,18 @@ symbols! { never_type, never_type_fallback, new, + new_binary, + new_debug, + new_display, + new_lower_exp, + new_lower_hex, + new_octal, + new_pointer, new_unchecked, + new_upper_exp, + new_upper_hex, + new_v1, + new_v1_formatted, next, nll, no, @@ -1600,6 +1620,7 @@ symbols! { vreg_low16, vtable_align, vtable_size, + w, warn, wasm_abi, wasm_import_module, @@ -1609,6 +1630,7 @@ symbols! { windows, windows_subsystem, with_negative_coherence, + with_options, wrapping_add, wrapping_mul, wrapping_sub, diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs index ed398b56612ce..6a0178274d36e 100644 --- a/library/alloc/src/fmt.rs +++ b/library/alloc/src/fmt.rs @@ -558,7 +558,7 @@ pub use core::fmt::Alignment; #[stable(feature = "rust1", since = "1.0.0")] pub use core::fmt::Error; #[stable(feature = "rust1", since = "1.0.0")] -pub use core::fmt::{write, ArgumentV1, Arguments}; +pub use core::fmt::{write, Arguments}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::fmt::{Binary, Octal}; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 905212eb372b1..b97573b3afb24 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -6,6 +6,7 @@ use crate::cell::{Cell, Ref, RefCell, RefMut, SyncUnsafeCell, UnsafeCell}; use crate::char::EscapeDebugExtArgs; use crate::iter; use crate::marker::PhantomData; +#[cfg(bootstrap)] use crate::mem; use crate::num::fmt as numfmt; use crate::ops::Deref; @@ -165,6 +166,7 @@ pub trait Write { /// assert_eq!(&buf, "ab"); /// ``` #[stable(feature = "fmt_write_char", since = "1.1.0")] + #[inline] fn write_char(&mut self, c: char) -> Result { self.write_str(c.encode_utf8(&mut [0; 4])) } @@ -188,6 +190,7 @@ pub trait Write { /// assert_eq!(&buf, "world"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[inline] fn write_fmt(mut self: &mut Self, args: Arguments<'_>) -> Result { write(&mut self, args) } @@ -195,14 +198,17 @@ pub trait Write { #[stable(feature = "fmt_write_blanket_impl", since = "1.4.0")] impl Write for &mut W { + #[inline] fn write_str(&mut self, s: &str) -> Result { (**self).write_str(s) } + #[inline] fn write_char(&mut self, c: char) -> Result { (**self).write_char(c) } + #[inline] fn write_fmt(&mut self, args: Arguments<'_>) -> Result { (**self).write_fmt(args) } @@ -239,6 +245,7 @@ impl<'a> Formatter<'a> { /// Currently not intended for use outside of the standard library. #[unstable(feature = "fmt_internals", reason = "internal to standard library", issue = "none")] #[doc(hidden)] + #[inline] pub fn new(buf: &'a mut (dyn Write + 'a)) -> Formatter<'a> { Formatter { flags: 0, @@ -249,11 +256,32 @@ impl<'a> Formatter<'a> { buf, } } + + /// Set all the formatting options. + #[unstable(feature = "fmt_internals", issue = "none")] + #[doc(hidden)] + #[inline] + pub fn with_options( + mut self, + flags: u32, + fill: char, + align: rt::v1::Alignment, + width: Option, + precision: Option, + ) -> Self { + self.flags = flags; + self.fill = fill; + self.align = align; + self.width = width; + self.precision = precision; + self + } } // NB. Argument is essentially an optimized partially applied formatting function, // equivalent to `exists T.(&T, fn(&T, &mut Formatter<'_>) -> Result`. +#[cfg(bootstrap)] extern "C" { type Opaque; } @@ -266,6 +294,7 @@ extern "C" { #[allow(missing_debug_implementations)] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] #[doc(hidden)] +#[cfg(bootstrap)] pub struct ArgumentV1<'a> { value: &'a Opaque, formatter: fn(&Opaque, &mut Formatter<'_>) -> Result, @@ -277,10 +306,12 @@ pub struct ArgumentV1<'a> { #[allow(missing_debug_implementations)] #[doc(hidden)] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] +#[cfg(bootstrap)] pub struct UnsafeArg { _private: (), } +#[cfg(bootstrap)] impl UnsafeArg { /// See documentation where `UnsafeArg` is required to know when it is safe to /// create and use `UnsafeArg`. @@ -307,6 +338,7 @@ impl UnsafeArg { // first argument. The read_volatile here ensures that we can safely ready out a // usize from the passed reference and that this address does not point at a // non-usize taking function. +#[cfg(bootstrap)] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] static USIZE_MARKER: fn(&usize, &mut Formatter<'_>) -> Result = |ptr, _| { // SAFETY: ptr is a reference @@ -314,6 +346,7 @@ static USIZE_MARKER: fn(&usize, &mut Formatter<'_>) -> Result = |ptr, _| { loop {} }; +#[cfg(bootstrap)] macro_rules! arg_new { ($f: ident, $t: ident) => { #[doc(hidden)] @@ -325,6 +358,7 @@ macro_rules! arg_new { }; } +#[cfg(bootstrap)] #[rustc_diagnostic_item = "ArgumentV1Methods"] impl<'a> ArgumentV1<'a> { #[doc(hidden)] @@ -391,6 +425,7 @@ impl<'a> Arguments<'a> { #[inline] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] #[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")] + #[cfg(bootstrap)] pub const fn new_v1(pieces: &'a [&'static str], args: &'a [ArgumentV1<'a>]) -> Arguments<'a> { if pieces.len() < args.len() || pieces.len() > args.len() + 1 { panic!("invalid args"); @@ -411,6 +446,7 @@ impl<'a> Arguments<'a> { #[inline] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] #[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")] + #[cfg(bootstrap)] pub const fn new_v1_formatted( pieces: &'a [&'static str], args: &'a [ArgumentV1<'a>], @@ -420,6 +456,24 @@ impl<'a> Arguments<'a> { Arguments { pieces, fmt: Some(fmt), args } } + #[doc(hidden)] + #[inline] + #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] + #[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")] + #[cfg(not(bootstrap))] + pub const fn new(f: &'a dyn Fn(&mut dyn Write) -> Result) -> Arguments<'a> { + Arguments { inner: Inner::Fn(f) } + } + + #[doc(hidden)] + #[inline] + #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] + #[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")] + #[cfg(not(bootstrap))] + pub const fn from_static_str(s: &'static str) -> Arguments<'a> { + Arguments { inner: Inner::StaticStr(s) } + } + /// Estimates the length of the formatted text. /// /// This is intended to be used for setting initial `String` capacity @@ -427,6 +481,19 @@ impl<'a> Arguments<'a> { #[doc(hidden)] #[inline] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] + #[cfg(not(bootstrap))] + pub fn estimated_capacity(&self) -> usize { + match self.inner { + Inner::Fn(_) => 0, // FIXME + Inner::StaticStr(s) => s.len(), + } + } + + /// Old estimated_capacity(). + #[doc(hidden)] + #[inline] + #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] + #[cfg(bootstrap)] pub fn estimated_capacity(&self) -> usize { let pieces_length: usize = self.pieces.iter().map(|x| x.len()).sum(); @@ -471,6 +538,23 @@ impl<'a> Arguments<'a> { #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "Arguments")] #[derive(Copy, Clone)] +#[cfg(not(bootstrap))] +pub struct Arguments<'a> { + inner: Inner<'a>, +} + +#[cfg(not(bootstrap))] +#[derive(Copy, Clone)] +enum Inner<'a> { + Fn(&'a dyn Fn(&mut dyn Write) -> Result), + StaticStr(&'static str), +} + +/// Old fmt::Arguments. +#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "Arguments")] +#[derive(Copy, Clone)] +#[cfg(bootstrap)] pub struct Arguments<'a> { // Format string pieces to print. pieces: &'a [&'static str], @@ -513,6 +597,20 @@ impl<'a> Arguments<'a> { #[rustc_const_unstable(feature = "const_arguments_as_str", issue = "none")] #[must_use] #[inline] + #[cfg(not(bootstrap))] + pub const fn as_str(&self) -> Option<&'static str> { + match self.inner { + Inner::Fn(_) => None, + Inner::StaticStr(s) => Some(s), + } + } + + /// Old as_str(). + #[stable(feature = "fmt_as_str", since = "1.52.0")] + #[rustc_const_unstable(feature = "const_arguments_as_str", issue = "none")] + #[must_use] + #[inline] + #[cfg(bootstrap)] pub const fn as_str(&self) -> Option<&'static str> { match (self.pieces, self.args) { ([], []) => Some(""), @@ -1185,6 +1283,18 @@ pub trait UpperExp { /// /// [`write!`]: crate::write! #[stable(feature = "rust1", since = "1.0.0")] +#[cfg(not(bootstrap))] +#[inline] +pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result { + match args.inner { + Inner::Fn(f) => f(output), + Inner::StaticStr(s) => output.write_str(s), + } +} + +/// Old write(). +#[stable(feature = "rust1", since = "1.0.0")] +#[cfg(bootstrap)] pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result { let mut formatter = Formatter::new(output); let mut idx = 0; @@ -1229,6 +1339,7 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result { Ok(()) } +#[cfg(bootstrap)] unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::v1::Argument, args: &[ArgumentV1<'_>]) -> Result { fmt.fill = arg.format.fill; fmt.align = arg.format.align; @@ -1250,6 +1361,7 @@ unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::v1::Argument, args: &[ArgumentV (value.formatter)(value.value, fmt) } +#[cfg(bootstrap)] unsafe fn getcount(args: &[ArgumentV1<'_>], cnt: &rt::v1::Count) -> Option { match *cnt { rt::v1::Count::Is(n) => Some(n), @@ -1445,11 +1557,17 @@ impl<'a> Formatter<'a> { /// assert_eq!(&format!("{Foo:0>4}"), "0Foo"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[inline] pub fn pad(&mut self, s: &str) -> Result { // Make sure there's a fast path up front if self.width.is_none() && self.precision.is_none() { - return self.buf.write_str(s); + self.buf.write_str(s) + } else { + self.pad_slow(s) } + } + + fn pad_slow(&mut self, s: &str) -> Result { // The `precision` field can be interpreted as a `max-width` for the // string being formatted. let s = if let Some(max) = self.precision { @@ -1629,6 +1747,7 @@ impl<'a> Formatter<'a> { /// assert_eq!(&format!("{Foo:0>8}"), "Foo"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[inline] pub fn write_str(&mut self, data: &str) -> Result { self.buf.write_str(data) } @@ -1652,6 +1771,7 @@ impl<'a> Formatter<'a> { /// assert_eq!(&format!("{:0>8}", Foo(2)), "Foo 2"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[inline] pub fn write_fmt(&mut self, fmt: Arguments<'_>) -> Result { write(self.buf, fmt) } @@ -1664,6 +1784,7 @@ impl<'a> Formatter<'a> { note = "use the `sign_plus`, `sign_minus`, `alternate`, \ or `sign_aware_zero_pad` methods instead" )] + #[inline] pub fn flags(&self) -> u32 { self.flags } @@ -1697,6 +1818,7 @@ impl<'a> Formatter<'a> { /// ``` #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] + #[inline] pub fn fill(&self) -> char { self.fill } @@ -1734,6 +1856,7 @@ impl<'a> Formatter<'a> { /// ``` #[must_use] #[stable(feature = "fmt_flags_align", since = "1.28.0")] + #[inline] pub fn align(&self) -> Option { match self.align { rt::v1::Alignment::Left => Some(Alignment::Left), @@ -1769,6 +1892,7 @@ impl<'a> Formatter<'a> { /// ``` #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] + #[inline] pub fn width(&self) -> Option { self.width } @@ -1800,6 +1924,7 @@ impl<'a> Formatter<'a> { /// ``` #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] + #[inline] pub fn precision(&self) -> Option { self.precision } @@ -1832,6 +1957,7 @@ impl<'a> Formatter<'a> { /// ``` #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] + #[inline] pub fn sign_plus(&self) -> bool { self.flags & (1 << FlagV1::SignPlus as u32) != 0 } @@ -1861,6 +1987,7 @@ impl<'a> Formatter<'a> { /// ``` #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] + #[inline] pub fn sign_minus(&self) -> bool { self.flags & (1 << FlagV1::SignMinus as u32) != 0 } @@ -1889,6 +2016,7 @@ impl<'a> Formatter<'a> { /// ``` #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] + #[inline] pub fn alternate(&self) -> bool { self.flags & (1 << FlagV1::Alternate as u32) != 0 } @@ -1915,6 +2043,7 @@ impl<'a> Formatter<'a> { /// ``` #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] + #[inline] pub fn sign_aware_zero_pad(&self) -> bool { self.flags & (1 << FlagV1::SignAwareZeroPad as u32) != 0 } @@ -2336,14 +2465,17 @@ impl<'a> Formatter<'a> { #[stable(since = "1.2.0", feature = "formatter_write")] impl Write for Formatter<'_> { + #[inline] fn write_str(&mut self, s: &str) -> Result { self.buf.write_str(s) } + #[inline] fn write_char(&mut self, c: char) -> Result { self.buf.write_char(c) } + #[inline] fn write_fmt(&mut self, args: Arguments<'_>) -> Result { write(self.buf, args) } @@ -2431,6 +2563,7 @@ impl Debug for str { #[stable(feature = "rust1", since = "1.0.0")] impl Display for str { + #[inline] fn fmt(&self, f: &mut Formatter<'_>) -> Result { f.pad(self) } diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index d4afe0f5326a3..87125e5ce04ca 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -45,7 +45,10 @@ pub const fn panic(expr: &'static str) -> ! { // truncation and padding (even though none is used here). Using // Arguments::new_v1 may allow the compiler to omit Formatter::pad from the // output binary, saving up to a few kilobytes. + #[cfg(bootstrap)] panic_fmt(fmt::Arguments::new_v1(&[expr], &[])); + #[cfg(not(bootstrap))] + panic_fmt(fmt::Arguments::from_static_str(expr)); } #[inline] diff --git a/library/core/tests/fmt/mod.rs b/library/core/tests/fmt/mod.rs index 61807635813c4..b241782c57dfe 100644 --- a/library/core/tests/fmt/mod.rs +++ b/library/core/tests/fmt/mod.rs @@ -24,9 +24,11 @@ fn test_estimated_capacity() { assert_eq!(format_args!("").estimated_capacity(), 0); assert_eq!(format_args!("{}", "").estimated_capacity(), 0); assert_eq!(format_args!("Hello").estimated_capacity(), 5); - assert_eq!(format_args!("Hello, {}!", "").estimated_capacity(), 16); + #[cfg(not(bootstrap))] + assert_eq!(format_args!("Hello, {}!", "").estimated_capacity(), 0); assert_eq!(format_args!("{}, hello!", "World").estimated_capacity(), 0); - assert_eq!(format_args!("{}. 16-bytes piece", "World").estimated_capacity(), 32); + #[cfg(not(bootstrap))] + assert_eq!(format_args!("{}. 16-bytes piece", "World").estimated_capacity(), 0); } #[test] diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 01a3873c75cec..9b1288a90b3ad 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -1655,6 +1655,7 @@ pub trait Write { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[inline] fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> Result<()> { // Create a shim which translates a Write to a fmt::Write and saves // off I/O errors. instead of discarding them diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 2dc12a18a8a66..abd3e3134eeb3 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -1026,6 +1026,7 @@ where )] #[doc(hidden)] #[cfg(not(test))] +#[inline] pub fn _print(args: fmt::Arguments<'_>) { print_to(args, stdout, "stdout"); } @@ -1037,6 +1038,7 @@ pub fn _print(args: fmt::Arguments<'_>) { )] #[doc(hidden)] #[cfg(not(test))] +#[inline] pub fn _eprint(args: fmt::Arguments<'_>) { print_to(args, stderr, "stderr"); } diff --git a/src/test/incremental/hashes/inherent_impls.rs b/src/test/incremental/hashes/inherent_impls.rs index 1abbff32c6f34..de4fa0e3cca8c 100644 --- a/src/test/incremental/hashes/inherent_impls.rs +++ b/src/test/incremental/hashes/inherent_impls.rs @@ -44,9 +44,9 @@ impl Foo { // This should affect the method itself, but not the impl. #[cfg(any(cfail1,cfail4))] impl Foo { - //-------------------------------------------------------------------------------------- + //------------------------------------------------------------------------- //-------------------------- - //-------------------------------------------------------------------------------------- + //------------------------------------------------------------------------- //-------------------------- pub fn method_body() { // ----------------------- @@ -59,9 +59,9 @@ impl Foo { #[rustc_clean(cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl Foo { - #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,promoted_mir,typeck")] + #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail3")] - #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,promoted_mir,typeck")] + #[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")] #[rustc_clean(cfg="cfail6")] pub fn method_body() { println!("Hello, world!"); @@ -76,12 +76,12 @@ impl Foo { impl Foo { //------------ //--------------- - //------------------------------------------------------------ + //----------------------------------------------- // //-------------------------- //------------ //--------------- - //------------------------------------------------------------ + //----------------------------------------------- // //-------------------------- #[inline] @@ -98,12 +98,12 @@ impl Foo { impl Foo { #[rustc_clean( cfg="cfail2", - except="hir_owner_nodes,optimized_mir,promoted_mir,typeck" + except="hir_owner_nodes,optimized_mir,typeck" )] #[rustc_clean(cfg="cfail3")] #[rustc_clean( cfg="cfail5", - except="hir_owner_nodes,optimized_mir,promoted_mir,typeck" + except="hir_owner_nodes,optimized_mir,typeck" )] #[rustc_clean(cfg="cfail6")] #[inline] diff --git a/src/test/incremental/hygiene/auxiliary/cached_hygiene.rs b/src/test/incremental/hygiene/auxiliary/cached_hygiene.rs index b31f60e972bf0..676324943ede3 100644 --- a/src/test/incremental/hygiene/auxiliary/cached_hygiene.rs +++ b/src/test/incremental/hygiene/auxiliary/cached_hygiene.rs @@ -13,7 +13,7 @@ macro_rules! first_macro { } } -#[rustc_clean(except="hir_owner_nodes,typeck,optimized_mir,promoted_mir", cfg="rpass2")] +#[rustc_clean(except="hir_owner_nodes,typeck,optimized_mir", cfg="rpass2")] #[inline(always)] pub fn changed_fn() { // This will cause additional hygiene to be generate, diff --git a/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff b/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff index dca36b1a76d0f..960b7794842fa 100644 --- a/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff +++ b/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff @@ -30,55 +30,62 @@ scope 3 { debug precision => _10; // in scope 3 at $DIR/funky_arms.rs:+13:17: +13:26 let _10: usize; // in scope 3 at $DIR/funky_arms.rs:+13:17: +13:26 + scope 5 (inlined Formatter::precision) { // at $DIR/funky_arms.rs:24:30: 24:45 + debug self => _8; // in scope 5 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + } } } } + scope 4 (inlined Formatter::sign_plus) { // at $DIR/funky_arms.rs:15:22: 15:37 + debug self => _5; // in scope 4 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + let mut _22: u32; // in scope 4 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + let mut _23: u32; // in scope 4 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + let mut _24: u32; // in scope 4 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + } bb0: { StorageLive(_4); // scope 0 at $DIR/funky_arms.rs:+4:9: +4:19 StorageLive(_5); // scope 0 at $DIR/funky_arms.rs:+4:22: +4:37 _5 = &(*_1); // scope 0 at $DIR/funky_arms.rs:+4:22: +4:37 - _4 = Formatter::sign_plus(move _5) -> bb1; // scope 0 at $DIR/funky_arms.rs:+4:22: +4:37 - // mir::Constant - // + span: $DIR/funky_arms.rs:15:26: 15:35 - // + literal: Const { ty: for<'r> fn(&'r Formatter) -> bool {Formatter::sign_plus}, val: Value() } - } - - bb1: { + StorageLive(_22); // scope 4 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageLive(_23); // scope 4 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _23 = ((*_5).0: u32); // scope 4 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageLive(_24); // scope 4 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _24 = const 1_u32; // scope 4 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL +- _22 = BitAnd(move _23, move _24); // scope 4 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL ++ _22 = BitAnd(move _23, const 1_u32); // scope 4 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageDead(_24); // scope 4 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageDead(_23); // scope 4 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _4 = Ne(move _22, const 0_u32); // scope 4 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageDead(_22); // scope 4 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageDead(_5); // scope 0 at $DIR/funky_arms.rs:+4:36: +4:37 StorageLive(_6); // scope 1 at $DIR/funky_arms.rs:+8:9: +8:13 - switchInt(_4) -> [false: bb3, otherwise: bb2]; // scope 1 at $DIR/funky_arms.rs:+8:16: +8:32 + switchInt(_4) -> [false: bb2, otherwise: bb1]; // scope 1 at $DIR/funky_arms.rs:+8:16: +8:32 } - bb2: { + bb1: { Deinit(_6); // scope 1 at $DIR/funky_arms.rs:+10:17: +10:41 discriminant(_6) = 1; // scope 1 at $DIR/funky_arms.rs:+10:17: +10:41 - goto -> bb4; // scope 1 at $DIR/funky_arms.rs:+10:17: +10:41 + goto -> bb3; // scope 1 at $DIR/funky_arms.rs:+10:17: +10:41 } - bb3: { + bb2: { Deinit(_6); // scope 1 at $DIR/funky_arms.rs:+9:18: +9:38 discriminant(_6) = 0; // scope 1 at $DIR/funky_arms.rs:+9:18: +9:38 - goto -> bb4; // scope 1 at $DIR/funky_arms.rs:+9:18: +9:38 + goto -> bb3; // scope 1 at $DIR/funky_arms.rs:+9:18: +9:38 } - bb4: { + bb3: { StorageLive(_7); // scope 3 at $DIR/funky_arms.rs:+13:30: +13:45 StorageLive(_8); // scope 3 at $DIR/funky_arms.rs:+13:30: +13:45 _8 = &(*_1); // scope 3 at $DIR/funky_arms.rs:+13:30: +13:45 - _7 = Formatter::precision(move _8) -> bb5; // scope 3 at $DIR/funky_arms.rs:+13:30: +13:45 - // mir::Constant - // + span: $DIR/funky_arms.rs:24:34: 24:43 - // + literal: Const { ty: for<'r> fn(&'r Formatter) -> Option {Formatter::precision}, val: Value() } - } - - bb5: { + _7 = ((*_8).4: std::option::Option); // scope 5 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageDead(_8); // scope 3 at $DIR/funky_arms.rs:+13:44: +13:45 _9 = discriminant(_7); // scope 3 at $DIR/funky_arms.rs:+13:12: +13:27 - switchInt(move _9) -> [1_isize: bb6, otherwise: bb8]; // scope 3 at $DIR/funky_arms.rs:+13:12: +13:27 + switchInt(move _9) -> [1_isize: bb4, otherwise: bb6]; // scope 3 at $DIR/funky_arms.rs:+13:12: +13:27 } - bb6: { + bb4: { StorageLive(_10); // scope 3 at $DIR/funky_arms.rs:+13:17: +13:26 _10 = ((_7 as Some).0: usize); // scope 3 at $DIR/funky_arms.rs:+13:17: +13:26 StorageLive(_11); // scope 3 at $DIR/funky_arms.rs:+15:43: +15:46 @@ -97,23 +104,23 @@ StorageDead(_15); // scope 3 at $DIR/funky_arms.rs:+15:78: +15:79 StorageLive(_17); // scope 3 at $DIR/funky_arms.rs:+15:81: +15:86 _17 = _3; // scope 3 at $DIR/funky_arms.rs:+15:81: +15:86 - _0 = float_to_exponential_common_exact::(move _11, move _12, move _13, move _14, move _17) -> bb7; // scope 3 at $DIR/funky_arms.rs:+15:9: +15:87 + _0 = float_to_exponential_common_exact::(move _11, move _12, move _13, move _14, move _17) -> bb5; // scope 3 at $DIR/funky_arms.rs:+15:9: +15:87 // mir::Constant // + span: $DIR/funky_arms.rs:26:9: 26:42 // + literal: Const { ty: for<'r, 's, 't0> fn(&'r mut Formatter<'s>, &'t0 T, Sign, u32, bool) -> Result<(), std::fmt::Error> {float_to_exponential_common_exact::}, val: Value() } } - bb7: { + bb5: { StorageDead(_17); // scope 3 at $DIR/funky_arms.rs:+15:86: +15:87 StorageDead(_14); // scope 3 at $DIR/funky_arms.rs:+15:86: +15:87 StorageDead(_13); // scope 3 at $DIR/funky_arms.rs:+15:86: +15:87 StorageDead(_12); // scope 3 at $DIR/funky_arms.rs:+15:86: +15:87 StorageDead(_11); // scope 3 at $DIR/funky_arms.rs:+15:86: +15:87 StorageDead(_10); // scope 2 at $DIR/funky_arms.rs:+16:5: +16:6 - goto -> bb10; // scope 2 at $DIR/funky_arms.rs:+13:5: +18:6 + goto -> bb8; // scope 2 at $DIR/funky_arms.rs:+13:5: +18:6 } - bb8: { + bb6: { StorageLive(_18); // scope 2 at $DIR/funky_arms.rs:+17:46: +17:49 _18 = &mut (*_1); // scope 2 at $DIR/funky_arms.rs:+17:46: +17:49 StorageLive(_19); // scope 2 at $DIR/funky_arms.rs:+17:51: +17:54 @@ -122,21 +129,21 @@ _20 = _6; // scope 2 at $DIR/funky_arms.rs:+17:56: +17:60 StorageLive(_21); // scope 2 at $DIR/funky_arms.rs:+17:62: +17:67 _21 = _3; // scope 2 at $DIR/funky_arms.rs:+17:62: +17:67 - _0 = float_to_exponential_common_shortest::(move _18, move _19, move _20, move _21) -> bb9; // scope 2 at $DIR/funky_arms.rs:+17:9: +17:68 + _0 = float_to_exponential_common_shortest::(move _18, move _19, move _20, move _21) -> bb7; // scope 2 at $DIR/funky_arms.rs:+17:9: +17:68 // mir::Constant // + span: $DIR/funky_arms.rs:28:9: 28:45 // + literal: Const { ty: for<'r, 's, 't0> fn(&'r mut Formatter<'s>, &'t0 T, Sign, bool) -> Result<(), std::fmt::Error> {float_to_exponential_common_shortest::}, val: Value() } } - bb9: { + bb7: { StorageDead(_21); // scope 2 at $DIR/funky_arms.rs:+17:67: +17:68 StorageDead(_20); // scope 2 at $DIR/funky_arms.rs:+17:67: +17:68 StorageDead(_19); // scope 2 at $DIR/funky_arms.rs:+17:67: +17:68 StorageDead(_18); // scope 2 at $DIR/funky_arms.rs:+17:67: +17:68 - goto -> bb10; // scope 2 at $DIR/funky_arms.rs:+13:5: +18:6 + goto -> bb8; // scope 2 at $DIR/funky_arms.rs:+13:5: +18:6 } - bb10: { + bb8: { StorageDead(_6); // scope 1 at $DIR/funky_arms.rs:+19:1: +19:2 StorageDead(_4); // scope 0 at $DIR/funky_arms.rs:+19:1: +19:2 StorageDead(_7); // scope 0 at $DIR/funky_arms.rs:+19:1: +19:2 diff --git a/src/test/pretty/dollar-crate.pp b/src/test/pretty/dollar-crate.pp index 3af37955f2380..c75e4cbdcab22 100644 --- a/src/test/pretty/dollar-crate.pp +++ b/src/test/pretty/dollar-crate.pp @@ -9,5 +9,5 @@ // pp-exact:dollar-crate.pp fn main() { - { ::std::io::_print(::core::fmt::Arguments::new_v1(&["rust\n"], &[])); }; + { ::std::io::_print(::core::fmt::Arguments::from_static_str("rust\n")); }; } diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index 752c36a0fbc5a..a2582bfeb3079 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -32,12 +32,10 @@ ({ let res = ((::alloc::fmt::format as - for<'r> fn(Arguments<'r>) -> String {format})(((::core::fmt::Arguments::new_v1 + for<'r> fn(Arguments<'r>) -> String {format})(((::core::fmt::Arguments::from_static_str as - fn(&[&'static str], &[ArgumentV1]) -> Arguments {Arguments::new_v1})((&([("test" - as &str)] as [&str; 1]) as &[&str; 1]), - (&([] as [ArgumentV1; 0]) as &[ArgumentV1; 0])) as - Arguments)) as String); + fn(&'static str) -> Arguments {Arguments::from_static_str})(("test" + as &str)) as Arguments)) as String); (res as String) } as String); } as ()) diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr index ab5c28fe47332..f49bdff63f869 100644 --- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr +++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr @@ -212,21 +212,19 @@ LL | #[suggestion(typeck::suggestion, code = "{name}")] | ^^^^^^^^ error: invalid format string: expected `'}'` but string was terminated - --> $DIR/diagnostic-derive.rs:171:16 + --> $DIR/diagnostic-derive.rs:171:10 | LL | #[derive(SessionDiagnostic)] - | - ^ expected `'}'` in format string - | | - | because of this opening brace + | ^^^^^^^^^^^^^^^^^ expected `'}'` in format string | = note: if you intended to print `{`, you can escape it using `{{` = note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info) error: invalid format string: unmatched `}` found - --> $DIR/diagnostic-derive.rs:181:15 + --> $DIR/diagnostic-derive.rs:181:10 | LL | #[derive(SessionDiagnostic)] - | ^ unmatched `}` in format string + | ^^^^^^^^^^^^^^^^^ unmatched `}` in format string | = note: if you intended to print `}`, you can escape it using `}}` = note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/attributes/key-value-expansion.stderr b/src/test/ui/attributes/key-value-expansion.stderr index 1b776322aaa64..6fb076eb5b6cc 100644 --- a/src/test/ui/attributes/key-value-expansion.stderr +++ b/src/test/ui/attributes/key-value-expansion.stderr @@ -17,8 +17,15 @@ LL | bug!(); error: unexpected expression: `{ let res = - ::alloc::fmt::format(::core::fmt::Arguments::new_v1(&[""], - &[::core::fmt::ArgumentV1::new_display(&"u8")])); + ::alloc::fmt::format(::core::fmt::Arguments::new(&match (&"u8",) { + _args => + |w: &mut dyn ::core::fmt::Write| -> ::core::fmt::Result + { + ::core::fmt::Display::fmt(_args.0, + &mut ::core::fmt::Formatter::new(w))?; + ::core::result::Result::Ok(()) + }, + })); res }.as_str()` --> $DIR/key-value-expansion.rs:48:23 diff --git a/src/test/ui/borrowck/issue-64453.stderr b/src/test/ui/borrowck/issue-64453.stderr index 245c3a40e0506..89853ee3344a4 100644 --- a/src/test/ui/borrowck/issue-64453.stderr +++ b/src/test/ui/borrowck/issue-64453.stderr @@ -1,4 +1,4 @@ -error: `Arguments::<'a>::new_v1` is not yet stable as a const fn +error: `Arguments::<'a>::from_static_str` is not yet stable as a const fn --> $DIR/issue-64453.rs:4:31 | LL | static settings_dir: String = format!(""); diff --git a/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr b/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr index ff89dd340349b..3449dee2b012e 100644 --- a/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr +++ b/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr @@ -9,7 +9,7 @@ LL | let c1 : () = c; | expected due to this | = note: expected unit type `()` - found closure `[mod1::f::{closure#0} closure_substs=(unavailable) substs=[T, _#16t, extern "rust-call" fn(()), _#15t]]` + found closure `[mod1::f::{closure#0} closure_substs=(unavailable) substs=[T, _#94t, extern "rust-call" fn(()), _#95t]]` help: use parentheses to call this closure | LL | let c1 : () = c(); diff --git a/src/test/ui/closures/print/closure-print-generic-verbose-2.stderr b/src/test/ui/closures/print/closure-print-generic-verbose-2.stderr index 5bbf84f963d7e..adc4f2a6e8f9a 100644 --- a/src/test/ui/closures/print/closure-print-generic-verbose-2.stderr +++ b/src/test/ui/closures/print/closure-print-generic-verbose-2.stderr @@ -9,7 +9,7 @@ LL | let c1 : () = c; | expected due to this | = note: expected unit type `()` - found closure `[f::{closure#0} closure_substs=(unavailable) substs=[T, _#16t, extern "rust-call" fn(()), _#15t]]` + found closure `[f::{closure#0} closure_substs=(unavailable) substs=[T, _#94t, extern "rust-call" fn(()), _#95t]]` help: use parentheses to call this closure | LL | let c1 : () = c(); diff --git a/src/test/ui/const-ptr/forbidden_slices.32bit.stderr b/src/test/ui/const-ptr/forbidden_slices.32bit.stderr index 82a3c92e66fdf..7e4709e52b0a1 100644 --- a/src/test/ui/const-ptr/forbidden_slices.32bit.stderr +++ b/src/test/ui/const-ptr/forbidden_slices.32bit.stderr @@ -7,10 +7,10 @@ LL | &*ptr::slice_from_raw_parts(data, len) | dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance) | inside `std::slice::from_raw_parts::` at $SRC_DIR/core/src/slice/raw.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:18:34 + ::: $DIR/forbidden_slices.rs:19:34 | LL | pub static S0: &[u32] = unsafe { from_raw_parts(ptr::null(), 0) }; - | ------------------------------ inside `S0` at $DIR/forbidden_slices.rs:18:34 + | ------------------------------ inside `S0` at $DIR/forbidden_slices.rs:19:34 error[E0080]: could not evaluate static initializer --> $SRC_DIR/core/src/slice/raw.rs:LL:COL @@ -21,10 +21,10 @@ LL | &*ptr::slice_from_raw_parts(data, len) | dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance) | inside `std::slice::from_raw_parts::<()>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:19:33 + ::: $DIR/forbidden_slices.rs:20:33 | LL | pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) }; - | ------------------------------ inside `S1` at $DIR/forbidden_slices.rs:19:33 + | ------------------------------ inside `S1` at $DIR/forbidden_slices.rs:20:33 error[E0080]: could not evaluate static initializer --> $SRC_DIR/core/src/slice/raw.rs:LL:COL @@ -35,24 +35,24 @@ LL | &*ptr::slice_from_raw_parts(data, len) | dereferencing pointer failed: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds | inside `std::slice::from_raw_parts::` at $SRC_DIR/core/src/slice/raw.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:22:34 + ::: $DIR/forbidden_slices.rs:23:34 | LL | pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 2) }; - | ---------------------- inside `S2` at $DIR/forbidden_slices.rs:22:34 + | ---------------------- inside `S2` at $DIR/forbidden_slices.rs:23:34 error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:25:1 + --> $DIR/forbidden_slices.rs:26:1 | LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }; | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered uninitialized bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { - ╾─ALLOC_ID─╼ 01 00 00 00 │ ╾──╼.... + ╾ALLOC_ID╼ 01 00 00 00 │ ╾╼.... } error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:27:1 + --> $DIR/forbidden_slices.rs:28:1 | LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size_of::<&u32>()) }; | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes @@ -60,29 +60,29 @@ LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported = note: the raw bytes of the constant (size: 8, align: 4) { - ╾─ALLOC_ID─╼ 04 00 00 00 │ ╾──╼.... + ╾ALLOC_ID╼ 04 00 00 00 │ ╾╼.... } error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:29:1 + --> $DIR/forbidden_slices.rs:30:1 | LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) }; | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered 0x11, but expected a boolean | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { - ╾─ALLOC_ID─╼ 04 00 00 00 │ ╾──╼.... + ╾ALLOC_ID╼ 04 00 00 00 │ ╾╼.... } error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:32:1 + --> $DIR/forbidden_slices.rs:33:1 | LL | pub static S7: &[u16] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { - ╾─A_ID+0x1─╼ 04 00 00 00 │ ╾──╼.... + ╾A_ID+0x1╼ 04 00 00 00 │ ╾╼.... } error[E0080]: could not evaluate static initializer @@ -94,10 +94,10 @@ LL | &*ptr::slice_from_raw_parts(data, len) | dereferencing pointer failed: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds | inside `std::slice::from_raw_parts::` at $SRC_DIR/core/src/slice/raw.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:43:5 + ::: $DIR/forbidden_slices.rs:44:5 | LL | from_raw_parts(ptr, 1) - | ---------------------- inside `S8` at $DIR/forbidden_slices.rs:43:5 + | ---------------------- inside `S8` at $DIR/forbidden_slices.rs:44:5 error[E0080]: could not evaluate static initializer --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -113,10 +113,10 @@ LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) } LL | unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) } | ------------------------------ inside `from_ptr_range::` at $SRC_DIR/core/src/slice/raw.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:46:34 + ::: $DIR/forbidden_slices.rs:47:34 | LL | pub static R0: &[u32] = unsafe { from_ptr_range(ptr::null()..ptr::null()) }; - | ---------------------------------------- inside `R0` at $DIR/forbidden_slices.rs:46:34 + | ---------------------------------------- inside `R0` at $DIR/forbidden_slices.rs:47:34 error[E0080]: could not evaluate static initializer --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -132,10 +132,10 @@ LL | assert!(0 < pointee_size && pointee_size <= isize::MAX as usize); LL | unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) } | ------------------------------ inside `from_ptr_range::<()>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:47:33 + ::: $DIR/forbidden_slices.rs:48:33 | LL | pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) }; - | ---------------------------------------- inside `R1` at $DIR/forbidden_slices.rs:47:33 + | ---------------------------------------- inside `R1` at $DIR/forbidden_slices.rs:48:33 | = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -151,24 +151,24 @@ LL | unsafe { intrinsics::offset(self, count) } LL | unsafe { self.offset(count as isize) } | --------------------------- inside `ptr::const_ptr::::add` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:50:25 + ::: $DIR/forbidden_slices.rs:51:25 | LL | from_ptr_range(ptr..ptr.add(2)) - | ---------- inside `R2` at $DIR/forbidden_slices.rs:50:25 + | ---------- inside `R2` at $DIR/forbidden_slices.rs:51:25 error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:52:1 + --> $DIR/forbidden_slices.rs:53:1 | LL | pub static R4: &[u8] = unsafe { | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered uninitialized bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { - ╾ALLOC_ID─╼ 01 00 00 00 │ ╾──╼.... + ╾ALLOC_ID╼ 01 00 00 00 │ ╾╼.... } error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:57:1 + --> $DIR/forbidden_slices.rs:58:1 | LL | pub static R5: &[u8] = unsafe { | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes @@ -176,29 +176,29 @@ LL | pub static R5: &[u8] = unsafe { = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported = note: the raw bytes of the constant (size: 8, align: 4) { - ╾ALLOC_ID─╼ 04 00 00 00 │ ╾──╼.... + ╾ALLOC_ID╼ 04 00 00 00 │ ╾╼.... } error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:62:1 + --> $DIR/forbidden_slices.rs:63:1 | LL | pub static R6: &[bool] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered 0x11, but expected a boolean | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { - ╾ALLOC_ID─╼ 04 00 00 00 │ ╾──╼.... + ╾ALLOC_ID╼ 04 00 00 00 │ ╾╼.... } error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:67:1 + --> $DIR/forbidden_slices.rs:68:1 | LL | pub static R7: &[u16] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { - ╾A_ID+0x1─╼ 04 00 00 00 │ ╾──╼.... + ╾A_ID+0x1╼ 04 00 00 00 │ ╾╼.... } error[E0080]: could not evaluate static initializer @@ -213,10 +213,10 @@ LL | unsafe { intrinsics::offset(self, count) } LL | unsafe { self.offset(count as isize) } | --------------------------- inside `ptr::const_ptr::::add` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:74:25 + ::: $DIR/forbidden_slices.rs:75:25 | LL | from_ptr_range(ptr..ptr.add(1)) - | ---------- inside `R8` at $DIR/forbidden_slices.rs:74:25 + | ---------- inside `R8` at $DIR/forbidden_slices.rs:75:25 error[E0080]: could not evaluate static initializer --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -232,10 +232,10 @@ LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) } LL | unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) } | ------------------------------ inside `from_ptr_range::` at $SRC_DIR/core/src/slice/raw.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:79:34 + ::: $DIR/forbidden_slices.rs:80:34 | LL | pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) }; - | ----------------------------------------------- inside `R9` at $DIR/forbidden_slices.rs:79:34 + | ----------------------------------------------- inside `R9` at $DIR/forbidden_slices.rs:80:34 error[E0080]: could not evaluate static initializer --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -251,10 +251,10 @@ LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) } LL | unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) } | ------------------------------ inside `from_ptr_range::` at $SRC_DIR/core/src/slice/raw.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:80:35 + ::: $DIR/forbidden_slices.rs:81:35 | LL | pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) }; - | ------------------------ inside `R10` at $DIR/forbidden_slices.rs:80:35 + | ------------------------ inside `R10` at $DIR/forbidden_slices.rs:81:35 error: aborting due to 18 previous errors diff --git a/src/test/ui/const-ptr/forbidden_slices.64bit.stderr b/src/test/ui/const-ptr/forbidden_slices.64bit.stderr index f88746af9769d..14edd7694e44c 100644 --- a/src/test/ui/const-ptr/forbidden_slices.64bit.stderr +++ b/src/test/ui/const-ptr/forbidden_slices.64bit.stderr @@ -7,10 +7,10 @@ LL | &*ptr::slice_from_raw_parts(data, len) | dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance) | inside `std::slice::from_raw_parts::` at $SRC_DIR/core/src/slice/raw.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:18:34 + ::: $DIR/forbidden_slices.rs:19:34 | LL | pub static S0: &[u32] = unsafe { from_raw_parts(ptr::null(), 0) }; - | ------------------------------ inside `S0` at $DIR/forbidden_slices.rs:18:34 + | ------------------------------ inside `S0` at $DIR/forbidden_slices.rs:19:34 error[E0080]: could not evaluate static initializer --> $SRC_DIR/core/src/slice/raw.rs:LL:COL @@ -21,10 +21,10 @@ LL | &*ptr::slice_from_raw_parts(data, len) | dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance) | inside `std::slice::from_raw_parts::<()>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:19:33 + ::: $DIR/forbidden_slices.rs:20:33 | LL | pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) }; - | ------------------------------ inside `S1` at $DIR/forbidden_slices.rs:19:33 + | ------------------------------ inside `S1` at $DIR/forbidden_slices.rs:20:33 error[E0080]: could not evaluate static initializer --> $SRC_DIR/core/src/slice/raw.rs:LL:COL @@ -35,24 +35,24 @@ LL | &*ptr::slice_from_raw_parts(data, len) | dereferencing pointer failed: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds | inside `std::slice::from_raw_parts::` at $SRC_DIR/core/src/slice/raw.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:22:34 + ::: $DIR/forbidden_slices.rs:23:34 | LL | pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 2) }; - | ---------------------- inside `S2` at $DIR/forbidden_slices.rs:22:34 + | ---------------------- inside `S2` at $DIR/forbidden_slices.rs:23:34 error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:25:1 + --> $DIR/forbidden_slices.rs:26:1 | LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }; | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered uninitialized bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { - ╾───────ALLOC_ID───────╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........ + ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾╼........ } error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:27:1 + --> $DIR/forbidden_slices.rs:28:1 | LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size_of::<&u32>()) }; | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes @@ -60,29 +60,29 @@ LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported = note: the raw bytes of the constant (size: 16, align: 8) { - ╾───────ALLOC_ID───────╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........ + ╾ALLOC_ID╼ 08 00 00 00 00 00 00 00 │ ╾╼........ } error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:29:1 + --> $DIR/forbidden_slices.rs:30:1 | LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) }; | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered 0x11, but expected a boolean | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { - ╾───────ALLOC_ID───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........ + ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾╼........ } error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:32:1 + --> $DIR/forbidden_slices.rs:33:1 | LL | pub static S7: &[u16] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { - ╾─────ALLOC_ID+0x1─────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........ + ╾ALLOC_ID+0x1╼ 04 00 00 00 00 00 00 00 │ ╾╼........ } error[E0080]: could not evaluate static initializer @@ -94,10 +94,10 @@ LL | &*ptr::slice_from_raw_parts(data, len) | dereferencing pointer failed: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds | inside `std::slice::from_raw_parts::` at $SRC_DIR/core/src/slice/raw.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:43:5 + ::: $DIR/forbidden_slices.rs:44:5 | LL | from_raw_parts(ptr, 1) - | ---------------------- inside `S8` at $DIR/forbidden_slices.rs:43:5 + | ---------------------- inside `S8` at $DIR/forbidden_slices.rs:44:5 error[E0080]: could not evaluate static initializer --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -113,10 +113,10 @@ LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) } LL | unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) } | ------------------------------ inside `from_ptr_range::` at $SRC_DIR/core/src/slice/raw.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:46:34 + ::: $DIR/forbidden_slices.rs:47:34 | LL | pub static R0: &[u32] = unsafe { from_ptr_range(ptr::null()..ptr::null()) }; - | ---------------------------------------- inside `R0` at $DIR/forbidden_slices.rs:46:34 + | ---------------------------------------- inside `R0` at $DIR/forbidden_slices.rs:47:34 error[E0080]: could not evaluate static initializer --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -132,10 +132,10 @@ LL | assert!(0 < pointee_size && pointee_size <= isize::MAX as usize); LL | unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) } | ------------------------------ inside `from_ptr_range::<()>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:47:33 + ::: $DIR/forbidden_slices.rs:48:33 | LL | pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) }; - | ---------------------------------------- inside `R1` at $DIR/forbidden_slices.rs:47:33 + | ---------------------------------------- inside `R1` at $DIR/forbidden_slices.rs:48:33 | = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -151,24 +151,24 @@ LL | unsafe { intrinsics::offset(self, count) } LL | unsafe { self.offset(count as isize) } | --------------------------- inside `ptr::const_ptr::::add` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:50:25 + ::: $DIR/forbidden_slices.rs:51:25 | LL | from_ptr_range(ptr..ptr.add(2)) - | ---------- inside `R2` at $DIR/forbidden_slices.rs:50:25 + | ---------- inside `R2` at $DIR/forbidden_slices.rs:51:25 error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:52:1 + --> $DIR/forbidden_slices.rs:53:1 | LL | pub static R4: &[u8] = unsafe { | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered uninitialized bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { - ╾──────ALLOC_ID───────╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........ + ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾╼........ } error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:57:1 + --> $DIR/forbidden_slices.rs:58:1 | LL | pub static R5: &[u8] = unsafe { | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes @@ -176,29 +176,29 @@ LL | pub static R5: &[u8] = unsafe { = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported = note: the raw bytes of the constant (size: 16, align: 8) { - ╾──────ALLOC_ID───────╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........ + ╾ALLOC_ID╼ 08 00 00 00 00 00 00 00 │ ╾╼........ } error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:62:1 + --> $DIR/forbidden_slices.rs:63:1 | LL | pub static R6: &[bool] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered 0x11, but expected a boolean | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { - ╾──────ALLOC_ID───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........ + ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾╼........ } error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:67:1 + --> $DIR/forbidden_slices.rs:68:1 | LL | pub static R7: &[u16] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { - ╾────ALLOC_ID+0x1─────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........ + ╾ALLOC_ID+0x1╼ 04 00 00 00 00 00 00 00 │ ╾╼........ } error[E0080]: could not evaluate static initializer @@ -213,10 +213,10 @@ LL | unsafe { intrinsics::offset(self, count) } LL | unsafe { self.offset(count as isize) } | --------------------------- inside `ptr::const_ptr::::add` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:74:25 + ::: $DIR/forbidden_slices.rs:75:25 | LL | from_ptr_range(ptr..ptr.add(1)) - | ---------- inside `R8` at $DIR/forbidden_slices.rs:74:25 + | ---------- inside `R8` at $DIR/forbidden_slices.rs:75:25 error[E0080]: could not evaluate static initializer --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -232,10 +232,10 @@ LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) } LL | unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) } | ------------------------------ inside `from_ptr_range::` at $SRC_DIR/core/src/slice/raw.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:79:34 + ::: $DIR/forbidden_slices.rs:80:34 | LL | pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) }; - | ----------------------------------------------- inside `R9` at $DIR/forbidden_slices.rs:79:34 + | ----------------------------------------------- inside `R9` at $DIR/forbidden_slices.rs:80:34 error[E0080]: could not evaluate static initializer --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -251,10 +251,10 @@ LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) } LL | unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) } | ------------------------------ inside `from_ptr_range::` at $SRC_DIR/core/src/slice/raw.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:80:35 + ::: $DIR/forbidden_slices.rs:81:35 | LL | pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) }; - | ------------------------ inside `R10` at $DIR/forbidden_slices.rs:80:35 + | ------------------------ inside `R10` at $DIR/forbidden_slices.rs:81:35 error: aborting due to 18 previous errors diff --git a/src/test/ui/const-ptr/forbidden_slices.rs b/src/test/ui/const-ptr/forbidden_slices.rs index e2184911f422c..e0f4b0a79b42c 100644 --- a/src/test/ui/const-ptr/forbidden_slices.rs +++ b/src/test/ui/const-ptr/forbidden_slices.rs @@ -1,6 +1,7 @@ // stderr-per-bitwidth // normalize-stderr-test "alloc[0-9]+" -> "ALLOC_ID" // normalize-stderr-test "a[0-9]+\+0x" -> "A_ID+0x" +// normalize-stderr-test "─" -> "" // error-pattern: could not evaluate static initializer #![feature( slice_from_ptr_range, diff --git a/src/test/ui/consts/const-eval/format.rs b/src/test/ui/consts/const-eval/format.rs index e43633da3ccb9..2eb2e2b024b1f 100644 --- a/src/test/ui/consts/const-eval/format.rs +++ b/src/test/ui/consts/const-eval/format.rs @@ -1,21 +1,17 @@ const fn failure() { panic!("{:?}", 0); - //~^ ERROR cannot call non-const formatting macro in constant functions - //~| ERROR erroneous constant used - //~| ERROR erroneous constant used - //~| WARN this was previously accepted by the compiler - //~| WARN this was previously accepted by the compiler + //~^ ERROR + //~| ERROR + //~| ERROR + //~| ERROR } const fn print() { println!("{:?}", 0); - //~^ ERROR cannot call non-const formatting macro in constant functions - //~| ERROR `Arguments::<'a>::new_v1` is not yet stable as a const fn - //~| ERROR cannot call non-const fn `_print` in constant functions - //~| ERROR erroneous constant used - //~| ERROR erroneous constant used - //~| WARN this was previously accepted by the compiler - //~| WARN this was previously accepted by the compiler + //~^ ERROR + //~| ERROR + //~| ERROR + //~| WARN } fn main() {} diff --git a/src/test/ui/consts/const-eval/format.stderr b/src/test/ui/consts/const-eval/format.stderr index a476b0f587fe1..1632f38752ce3 100644 --- a/src/test/ui/consts/const-eval/format.stderr +++ b/src/test/ui/consts/const-eval/format.stderr @@ -1,23 +1,45 @@ -error[E0015]: cannot call non-const formatting macro in constant functions - --> $DIR/format.rs:2:20 +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/format.rs:2:5 | LL | panic!("{:?}", 0); - | ^ + | ^^^^^^^^^^^^^^^^^ | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable = 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:11:22 +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/format.rs:2:5 | -LL | println!("{:?}", 0); - | ^ +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::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + = 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: `Arguments::<'a>::new_v1` is not yet stable as a const fn - --> $DIR/format.rs:11:5 +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/format.rs:2:5 + | +LL | panic!("{:?}", 0); + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + = 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[E0658]: mutable references are not allowed in constant functions + --> $DIR/format.rs:2:5 + | +LL | panic!("{:?}", 0); + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + = 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: `Arguments::<'a>::new` is not yet stable as a const fn + --> $DIR/format.rs:10:5 | LL | println!("{:?}", 0); | ^^^^^^^^^^^^^^^^^^^ @@ -26,7 +48,7 @@ LL | println!("{:?}", 0); = 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[E0015]: cannot call non-const fn `_print` in constant functions - --> $DIR/format.rs:11:5 + --> $DIR/format.rs:10:5 | LL | println!("{:?}", 0); | ^^^^^^^^^^^^^^^^^^^ @@ -35,84 +57,23 @@ LL | println!("{:?}", 0); = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: erroneous constant used - --> $DIR/format.rs:2:12 - | -LL | panic!("{:?}", 0); - | ^^^^^^ referenced constant has errors - | - = note: `#[deny(const_err)]` on by default - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #71800 - -error: erroneous constant used - --> $DIR/format.rs:2:20 - | -LL | panic!("{:?}", 0); - | ^ referenced constant has errors - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #71800 - = 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: erroneous constant used - --> $DIR/format.rs:11:14 - | -LL | println!("{:?}", 0); - | ^^^^^^ referenced constant has errors - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #71800 - -error: erroneous constant used - --> $DIR/format.rs:11:22 + --> $DIR/format.rs:10:22 | LL | println!("{:?}", 0); | ^ referenced constant has errors | + = note: `#[deny(const_err)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 = 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: aborting due to 8 previous errors +error: aborting due to 7 previous errors -For more information about this error, try `rustc --explain E0015`. +Some errors have detailed explanations: E0015, E0658. +For more information about an error, try `rustc --explain E0015`. Future incompatibility report: Future breakage diagnostic: error: erroneous constant used - --> $DIR/format.rs:2:12 - | -LL | panic!("{:?}", 0); - | ^^^^^^ referenced constant has errors - | - = note: `#[deny(const_err)]` on by default - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #71800 - -Future breakage diagnostic: -error: erroneous constant used - --> $DIR/format.rs:2:20 - | -LL | panic!("{:?}", 0); - | ^ referenced constant has errors - | - = note: `#[deny(const_err)]` on by default - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #71800 - = 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) - -Future breakage diagnostic: -error: erroneous constant used - --> $DIR/format.rs:11:14 - | -LL | println!("{:?}", 0); - | ^^^^^^ referenced constant has errors - | - = note: `#[deny(const_err)]` on by default - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #71800 - -Future breakage diagnostic: -error: erroneous constant used - --> $DIR/format.rs:11:22 + --> $DIR/format.rs:10:22 | LL | println!("{:?}", 0); | ^ referenced constant has errors diff --git a/src/test/ui/fmt/format-args-capture-issue-93378.rs b/src/test/ui/fmt/format-args-capture-issue-93378.rs index 6744444426472..9d722a0287a5c 100644 --- a/src/test/ui/fmt/format-args-capture-issue-93378.rs +++ b/src/test/ui/fmt/format-args-capture-issue-93378.rs @@ -3,9 +3,9 @@ fn main() { let b = "b"; println!("{a} {b} {} {} {c} {}", c = "c"); - //~^ ERROR: invalid reference to positional arguments 1 and 2 (there is 1 argument) + //~^ ERROR: 3 positional arguments in format string, but there is 1 argument let n = 1; println!("{a:.n$} {b:.*}"); - //~^ ERROR: invalid reference to positional argument 0 (no arguments were given) + //~^ ERROR: 1 positional argument in format string, but no arguments were given } diff --git a/src/test/ui/fmt/format-args-capture-issue-93378.stderr b/src/test/ui/fmt/format-args-capture-issue-93378.stderr index b8e2b2afb3867..6429b0d46f6af 100644 --- a/src/test/ui/fmt/format-args-capture-issue-93378.stderr +++ b/src/test/ui/fmt/format-args-capture-issue-93378.stderr @@ -1,19 +1,14 @@ -error: invalid reference to positional arguments 1 and 2 (there is 1 argument) - --> $DIR/format-args-capture-issue-93378.rs:5:26 +error: 3 positional arguments in format string, but there is 1 argument + --> $DIR/format-args-capture-issue-93378.rs:5:23 | LL | println!("{a} {b} {} {} {c} {}", c = "c"); - | ^^ ^^ - | - = note: positional arguments are zero-based + | ^^ ^^ ^^ --- -error: invalid reference to positional argument 0 (no arguments were given) - --> $DIR/format-args-capture-issue-93378.rs:9:23 +error: 1 positional argument in format string, but no arguments were given + --> $DIR/format-args-capture-issue-93378.rs:9:26 | LL | println!("{a:.n$} {b:.*}"); - | - ^^^--^ - | | | - | | this precision flag adds an extra required argument at position 0, which is why there are 3 arguments expected - | this parameter corresponds to the precision flag + | ^^ this precision flag adds an extra required argument at position 0, which is why there is 1 argument expected | = note: positional arguments are zero-based = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html diff --git a/src/test/ui/fmt/ifmt-bad-arg.rs b/src/test/ui/fmt/ifmt-bad-arg.rs index f00cb05c9ebc3..68861d7bf3faf 100644 --- a/src/test/ui/fmt/ifmt-bad-arg.rs +++ b/src/test/ui/fmt/ifmt-bad-arg.rs @@ -20,9 +20,9 @@ fn main() { //~^ ERROR: invalid reference to positional argument 2 (there are 2 arguments) format!("{} {value} {} {}", 1, value=2); - //~^ ERROR: invalid reference to positional argument 2 (there are 2 arguments) + //~^ ERROR: 3 positional arguments in format string, but there are 2 arguments format!("{name} {value} {} {} {} {} {} {}", 0, name=1, value=2); - //~^ ERROR: invalid reference to positional arguments 3, 4 and 5 (there are 3 arguments) + //~^ ERROR: 6 positional arguments in format string, but there are 3 arguments format!("{} {foo} {} {bar} {}", 1, 2, 3); //~^ ERROR: cannot find value `foo` in this scope @@ -79,7 +79,7 @@ tenth number: {}", //~^ ERROR 4 positional arguments in format string, but there are 3 arguments //~| ERROR mismatched types println!("{} {:07$.*} {}", 1, 3.2, 4); - //~^ ERROR 4 positional arguments in format string, but there are 3 arguments + //~^ ERROR invalid reference to positional arguments 3 and 7 (there are 3 arguments) //~| ERROR mismatched types println!("{} {:07$} {}", 1, 3.2, 4); //~^ ERROR invalid reference to positional argument 7 (there are 3 arguments) @@ -95,5 +95,5 @@ tenth number: {}", println!("{:.*}"); //~^ ERROR 2 positional arguments in format string, but no arguments were given println!("{:.0$}"); - //~^ ERROR 1 positional argument in format string, but no arguments were given + //~^ ERROR invalid reference to positional argument 0 (no arguments were given) } diff --git a/src/test/ui/fmt/ifmt-bad-arg.stderr b/src/test/ui/fmt/ifmt-bad-arg.stderr index dbb4bc6d9370e..9df5d58145a4b 100644 --- a/src/test/ui/fmt/ifmt-bad-arg.stderr +++ b/src/test/ui/fmt/ifmt-bad-arg.stderr @@ -5,10 +5,10 @@ LL | format!("{}"); | ^^ error: invalid reference to positional argument 1 (there is 1 argument) - --> $DIR/ifmt-bad-arg.rs:9:14 + --> $DIR/ifmt-bad-arg.rs:9:15 | LL | format!("{1}", 1); - | ^^^ + | ^ | = note: positional arguments are zero-based @@ -27,36 +27,32 @@ LL | format!("{} {}"); | ^^ ^^ error: invalid reference to positional argument 1 (there is 1 argument) - --> $DIR/ifmt-bad-arg.rs:16:18 + --> $DIR/ifmt-bad-arg.rs:16:19 | LL | format!("{0} {1}", 1); - | ^^^ + | ^ | = note: positional arguments are zero-based error: invalid reference to positional argument 2 (there are 2 arguments) - --> $DIR/ifmt-bad-arg.rs:19:22 + --> $DIR/ifmt-bad-arg.rs:19:23 | LL | format!("{0} {1} {2}", 1, 2); - | ^^^ + | ^ | = note: positional arguments are zero-based -error: invalid reference to positional argument 2 (there are 2 arguments) - --> $DIR/ifmt-bad-arg.rs:22:28 +error: 3 positional arguments in format string, but there are 2 arguments + --> $DIR/ifmt-bad-arg.rs:22:14 | LL | format!("{} {value} {} {}", 1, value=2); - | ^^ - | - = note: positional arguments are zero-based + | ^^ ^^ ^^ - - -error: invalid reference to positional arguments 3, 4 and 5 (there are 3 arguments) - --> $DIR/ifmt-bad-arg.rs:24:38 +error: 6 positional arguments in format string, but there are 3 arguments + --> $DIR/ifmt-bad-arg.rs:24:29 | LL | format!("{name} {value} {} {} {} {} {} {}", 0, name=1, value=2); - | ^^ ^^ ^^ - | - = note: positional arguments are zero-based + | ^^ ^^ ^^ ^^ ^^ ^^ - - - error: multiple unused formatting arguments --> $DIR/ifmt-bad-arg.rs:32:17 @@ -117,20 +113,20 @@ LL | format!("{} {}", 1, 2, foo=1, bar=2); | multiple missing formatting specifiers error: duplicate argument named `foo` - --> $DIR/ifmt-bad-arg.rs:40:33 + --> $DIR/ifmt-bad-arg.rs:40:29 | LL | format!("{foo}", foo=1, foo=2); - | - ^ duplicate argument - | | - | previously here + | --- ^^^ duplicate argument + | | + | previously here error: positional arguments cannot follow named arguments --> $DIR/ifmt-bad-arg.rs:41:35 | LL | format!("{foo} {} {}", foo=1, 2); - | - ^ positional arguments must be before named arguments - | | - | named argument + | ----- ^ positional arguments must be before named arguments + | | + | named argument error: named argument never used --> $DIR/ifmt-bad-arg.rs:45:51 @@ -191,33 +187,26 @@ error: 4 positional arguments in format string, but there are 3 arguments | LL | println!("{} {:.*} {}", 1, 3.2, 4); | ^^ ^^--^ ^^ - --- - - | | | - | | this parameter corresponds to the precision flag + | | | this precision flag adds an extra required argument at position 1, which is why there are 4 arguments expected | = note: positional arguments are zero-based = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html -error: 4 positional arguments in format string, but there are 3 arguments - --> $DIR/ifmt-bad-arg.rs:81:15 +error: invalid reference to positional arguments 3 and 7 (there are 3 arguments) + --> $DIR/ifmt-bad-arg.rs:81:21 | LL | println!("{} {:07$.*} {}", 1, 3.2, 4); - | ^^ ^^^----^ ^^ - --- - - | | | | - | | | this parameter corresponds to the precision flag - | | this precision flag adds an extra required argument at position 1, which is why there are 4 arguments expected - | this width flag expects an `usize` argument at position 7, but there are 3 arguments + | ^^ ^ | = note: positional arguments are zero-based = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html error: invalid reference to positional argument 7 (there are 3 arguments) - --> $DIR/ifmt-bad-arg.rs:84:18 + --> $DIR/ifmt-bad-arg.rs:84:21 | LL | println!("{} {:07$} {}", 1, 3.2, 4); - | ^^^--^ - | | - | this width flag expects an `usize` argument at position 7, but there are 3 arguments + | ^^ | = note: positional arguments are zero-based = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html @@ -240,24 +229,19 @@ LL | println!("{:foo}", 1); - `X`, which uses the `UpperHex` trait error: invalid reference to positional arguments 4, 5, 6 and 7 (there is 1 argument) - --> $DIR/ifmt-bad-arg.rs:87:15 + --> $DIR/ifmt-bad-arg.rs:87:16 | LL | println!("{5} {:4$} {6:7$}", 1); - | ^^^ ^^--^ ^^^--^ - | | | - | | this width flag expects an `usize` argument at position 7, but there is 1 argument - | this width flag expects an `usize` argument at position 4, but there is 1 argument + | ^ ^^ ^ ^^ | = note: positional arguments are zero-based = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html error: invalid reference to positional argument 0 (no arguments were given) - --> $DIR/ifmt-bad-arg.rs:90:15 + --> $DIR/ifmt-bad-arg.rs:90:20 | LL | println!("{foo:0$}"); - | ^^^^^--^ - | | - | this width flag expects an `usize` argument at position 0, but no arguments were given + | ^^ | = note: positional arguments are zero-based = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html @@ -273,13 +257,11 @@ LL | println!("{:.*}"); = note: positional arguments are zero-based = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html -error: 1 positional argument in format string, but no arguments were given - --> $DIR/ifmt-bad-arg.rs:97:15 +error: invalid reference to positional argument 0 (no arguments were given) + --> $DIR/ifmt-bad-arg.rs:97:16 | LL | println!("{:.0$}"); - | ^^---^ - | | - | this precision flag expects an `usize` argument at position 0, but no arguments were given + | ^^^^ | = note: positional arguments are zero-based = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html @@ -318,36 +300,32 @@ error[E0308]: mismatched types --> $DIR/ifmt-bad-arg.rs:78:32 | LL | println!("{} {:.*} {}", 1, 3.2, 4); - | ---------------------------^^^---- - | | | - | | expected `usize`, found floating-point number - | arguments to this function are incorrect - | - = note: expected reference `&usize` - found reference `&{float}` -note: associated function defined here - --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL - | -LL | pub fn from_usize(x: &usize) -> ArgumentV1<'_> { - | ^^^^^^^^^^ + | ^^^ + | | + | expected `usize`, found floating-point number + | arguments to this enum variant are incorrect + | +note: tuple variant defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + | +LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T), + | ^^^^ = 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[E0308]: mismatched types --> $DIR/ifmt-bad-arg.rs:81:35 | LL | println!("{} {:07$.*} {}", 1, 3.2, 4); - | ------------------------------^^^---- - | | | - | | expected `usize`, found floating-point number - | arguments to this function are incorrect - | - = note: expected reference `&usize` - found reference `&{float}` -note: associated function defined here - --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL - | -LL | pub fn from_usize(x: &usize) -> ArgumentV1<'_> { - | ^^^^^^^^^^ + | ^^^ + | | + | expected `usize`, found floating-point number + | arguments to this enum variant are incorrect + | +note: tuple variant defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + | +LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T), + | ^^^^ = 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: aborting due to 38 previous errors diff --git a/src/test/ui/fmt/ifmt-unimpl.stderr b/src/test/ui/fmt/ifmt-unimpl.stderr index 0e34f913511a3..44b9461f407fa 100644 --- a/src/test/ui/fmt/ifmt-unimpl.stderr +++ b/src/test/ui/fmt/ifmt-unimpl.stderr @@ -15,12 +15,7 @@ LL | format!("{:X}", "3"); NonZeroIsize and 21 others = note: required for `&str` to implement `UpperHex` -note: required by a bound in `ArgumentV1::<'a>::new_upper_hex` - --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL - | -LL | arg_new!(new_upper_hex, UpperHex); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `ArgumentV1::<'a>::new_upper_hex` - = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `arg_new` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/fmt/send-sync.stderr b/src/test/ui/fmt/send-sync.stderr index 3ed040c3ab359..9f776473fcb97 100644 --- a/src/test/ui/fmt/send-sync.stderr +++ b/src/test/ui/fmt/send-sync.stderr @@ -1,16 +1,14 @@ -error[E0277]: `core::fmt::Opaque` cannot be shared between threads safely +error[E0277]: `dyn for<'r> Fn(&'r mut (dyn std::fmt::Write + 'r)) -> Result<(), std::fmt::Error>` cannot be shared between threads safely --> $DIR/send-sync.rs:8:10 | LL | send(format_args!("{:?}", c)); - | ---- ^^^^^^^^^^^^^^^^^^^^^^^ `core::fmt::Opaque` cannot be shared between threads safely + | ---- ^^^^^^^^^^^^^^^^^^^^^^^ `dyn for<'r> Fn(&'r mut (dyn std::fmt::Write + 'r)) -> Result<(), std::fmt::Error>` cannot be shared between threads safely | | | required by a bound introduced by this call | - = help: within `[ArgumentV1<'_>]`, the trait `Sync` is not implemented for `core::fmt::Opaque` - = note: required because it appears within the type `&core::fmt::Opaque` - = note: required because it appears within the type `ArgumentV1<'_>` - = note: required because it appears within the type `[ArgumentV1<'_>]` - = note: required for `&[ArgumentV1<'_>]` to implement `Send` + = help: the trait `Sync` is not implemented for `dyn for<'r> Fn(&'r mut (dyn std::fmt::Write + 'r)) -> Result<(), std::fmt::Error>` + = note: required for `&dyn for<'r> Fn(&'r mut (dyn std::fmt::Write + 'r)) -> Result<(), std::fmt::Error>` to implement `Send` + = note: required because it appears within the type `core::fmt::Inner<'_>` = note: required because it appears within the type `Arguments<'_>` note: required by a bound in `send` --> $DIR/send-sync.rs:1:12 @@ -18,19 +16,17 @@ note: required by a bound in `send` LL | fn send(_: T) {} | ^^^^ required by this bound in `send` -error[E0277]: `core::fmt::Opaque` cannot be shared between threads safely +error[E0277]: `dyn for<'r> Fn(&'r mut (dyn std::fmt::Write + 'r)) -> Result<(), std::fmt::Error>` cannot be shared between threads safely --> $DIR/send-sync.rs:9:10 | LL | sync(format_args!("{:?}", c)); - | ---- ^^^^^^^^^^^^^^^^^^^^^^^ `core::fmt::Opaque` cannot be shared between threads safely + | ---- ^^^^^^^^^^^^^^^^^^^^^^^ `dyn for<'r> Fn(&'r mut (dyn std::fmt::Write + 'r)) -> Result<(), std::fmt::Error>` cannot be shared between threads safely | | | required by a bound introduced by this call | - = help: within `Arguments<'_>`, the trait `Sync` is not implemented for `core::fmt::Opaque` - = note: required because it appears within the type `&core::fmt::Opaque` - = note: required because it appears within the type `ArgumentV1<'_>` - = note: required because it appears within the type `[ArgumentV1<'_>]` - = note: required because it appears within the type `&[ArgumentV1<'_>]` + = help: within `Arguments<'_>`, the trait `Sync` is not implemented for `dyn for<'r> Fn(&'r mut (dyn std::fmt::Write + 'r)) -> Result<(), std::fmt::Error>` + = note: required because it appears within the type `&dyn for<'r> Fn(&'r mut (dyn std::fmt::Write + 'r)) -> Result<(), std::fmt::Error>` + = note: required because it appears within the type `core::fmt::Inner<'_>` = note: required because it appears within the type `Arguments<'_>` note: required by a bound in `sync` --> $DIR/send-sync.rs:2:12 diff --git a/src/test/ui/issues/issue-69455.stderr b/src/test/ui/issues/issue-69455.stderr index 9d11cf19ea77c..fc343bb54aace 100644 --- a/src/test/ui/issues/issue-69455.stderr +++ b/src/test/ui/issues/issue-69455.stderr @@ -1,14 +1,16 @@ -error[E0282]: type annotations needed - --> $DIR/issue-69455.rs:29:20 +error[E0284]: type annotations needed + --> $DIR/issue-69455.rs:29:41 | LL | println!("{}", 23u64.test(xs.iter().sum())); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the associated function `new_display` + | ---- ^^^ cannot infer type of the type parameter `S` declared on the associated function `sum` + | | + | type must be known at this point | - = 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) + = note: cannot satisfy `>::Output == _` help: consider specifying the generic argument | -LL | println!("{}", 23u64.test(xs.iter().sum())::); - | +++++ +LL | println!("{}", 23u64.test(xs.iter().sum::())); + | +++++ error[E0283]: type annotations needed --> $DIR/issue-69455.rs:29:41 @@ -33,5 +35,5 @@ LL | println!("{}", 23u64.test(xs.iter().sum::())); error: aborting due to 2 previous errors -Some errors have detailed explanations: E0282, E0283. -For more information about an error, try `rustc --explain E0282`. +Some errors have detailed explanations: E0283, E0284. +For more information about an error, try `rustc --explain E0283`. diff --git a/src/test/ui/issues/issue-75307.rs b/src/test/ui/issues/issue-75307.rs index 2fe112a3b95d4..cffa6bea8ed38 100644 --- a/src/test/ui/issues/issue-75307.rs +++ b/src/test/ui/issues/issue-75307.rs @@ -1,3 +1,3 @@ fn main() { - format!(r"{}{}{}", named_arg=1); //~ ERROR invalid reference to positional arguments 1 and 2 + format!(r"{}{}{}", named_arg=1); //~ ERROR 3 positional arguments in format string, but there is 1 argument } diff --git a/src/test/ui/issues/issue-75307.stderr b/src/test/ui/issues/issue-75307.stderr index 10c952006c208..c5b0b11e7d099 100644 --- a/src/test/ui/issues/issue-75307.stderr +++ b/src/test/ui/issues/issue-75307.stderr @@ -1,10 +1,8 @@ -error: invalid reference to positional arguments 1 and 2 (there is 1 argument) - --> $DIR/issue-75307.rs:2:17 +error: 3 positional arguments in format string, but there is 1 argument + --> $DIR/issue-75307.rs:2:15 | LL | format!(r"{}{}{}", named_arg=1); - | ^^^^ - | - = note: positional arguments are zero-based + | ^^^^^^ - error: aborting due to previous error diff --git a/src/test/ui/lint/function-item-references.stderr b/src/test/ui/lint/function-item-references.stderr index a9d18bb6a4743..485ec4ed06438 100644 --- a/src/test/ui/lint/function-item-references.stderr +++ b/src/test/ui/lint/function-item-references.stderr @@ -10,6 +10,54 @@ note: the lint level is defined here LL | #![warn(function_item_references)] | ^^^^^^^^^^^^^^^^^^^^^^^^ +warning: taking a reference to a function item does not give a function pointer + --> $DIR/function-item-references.rs:142:41 + | +LL | std::mem::transmute::<_, usize>(&foo); + | ^^^^ help: cast `foo` to obtain a function pointer: `foo as fn() -> _` + +warning: taking a reference to a function item does not give a function pointer + --> $DIR/function-item-references.rs:144:50 + | +LL | std::mem::transmute::<_, (usize, usize)>((&foo, &bar)); + | ^^^^^^^^^^^^ help: cast `foo` to obtain a function pointer: `foo as fn() -> _` + +warning: taking a reference to a function item does not give a function pointer + --> $DIR/function-item-references.rs:144:50 + | +LL | std::mem::transmute::<_, (usize, usize)>((&foo, &bar)); + | ^^^^^^^^^^^^ help: cast `bar` to obtain a function pointer: `bar as fn(_) -> _` + +warning: taking a reference to a function item does not give a function pointer + --> $DIR/function-item-references.rs:147:41 + | +LL | std::mem::transmute::<_, usize>(&take_generic_ref::); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: cast `take_generic_ref` to obtain a function pointer: `take_generic_ref:: as fn(_)` + +warning: taking a reference to a function item does not give a function pointer + --> $DIR/function-item-references.rs:156:15 + | +LL | print_ptr(&bar); + | ^^^^ help: cast `bar` to obtain a function pointer: `bar as fn(_) -> _` + +warning: taking a reference to a function item does not give a function pointer + --> $DIR/function-item-references.rs:158:24 + | +LL | bound_by_ptr_trait(&bar); + | ^^^^ help: cast `bar` to obtain a function pointer: `bar as fn(_) -> _` + +warning: taking a reference to a function item does not give a function pointer + --> $DIR/function-item-references.rs:160:30 + | +LL | bound_by_ptr_trait_tuple((&foo, &bar)); + | ^^^^^^^^^^^^ help: cast `bar` to obtain a function pointer: `bar as fn(_) -> _` + +warning: taking a reference to a function item does not give a function pointer + --> $DIR/function-item-references.rs:160:30 + | +LL | bound_by_ptr_trait_tuple((&foo, &bar)); + | ^^^^^^^^^^^^ help: cast `foo` to obtain a function pointer: `foo as fn() -> _` + warning: taking a reference to a function item does not give a function pointer --> $DIR/function-item-references.rs:81:22 | @@ -154,53 +202,5 @@ warning: taking a reference to a function item does not give a function pointer LL | println!("{:p} {:p} {:p}", &nop, &foo, &bar); | ^^^^ help: cast `bar` to obtain a function pointer: `bar as fn(_) -> _` -warning: taking a reference to a function item does not give a function pointer - --> $DIR/function-item-references.rs:142:41 - | -LL | std::mem::transmute::<_, usize>(&foo); - | ^^^^ help: cast `foo` to obtain a function pointer: `foo as fn() -> _` - -warning: taking a reference to a function item does not give a function pointer - --> $DIR/function-item-references.rs:144:50 - | -LL | std::mem::transmute::<_, (usize, usize)>((&foo, &bar)); - | ^^^^^^^^^^^^ help: cast `foo` to obtain a function pointer: `foo as fn() -> _` - -warning: taking a reference to a function item does not give a function pointer - --> $DIR/function-item-references.rs:144:50 - | -LL | std::mem::transmute::<_, (usize, usize)>((&foo, &bar)); - | ^^^^^^^^^^^^ help: cast `bar` to obtain a function pointer: `bar as fn(_) -> _` - -warning: taking a reference to a function item does not give a function pointer - --> $DIR/function-item-references.rs:147:41 - | -LL | std::mem::transmute::<_, usize>(&take_generic_ref::); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: cast `take_generic_ref` to obtain a function pointer: `take_generic_ref:: as fn(_)` - -warning: taking a reference to a function item does not give a function pointer - --> $DIR/function-item-references.rs:156:15 - | -LL | print_ptr(&bar); - | ^^^^ help: cast `bar` to obtain a function pointer: `bar as fn(_) -> _` - -warning: taking a reference to a function item does not give a function pointer - --> $DIR/function-item-references.rs:158:24 - | -LL | bound_by_ptr_trait(&bar); - | ^^^^ help: cast `bar` to obtain a function pointer: `bar as fn(_) -> _` - -warning: taking a reference to a function item does not give a function pointer - --> $DIR/function-item-references.rs:160:30 - | -LL | bound_by_ptr_trait_tuple((&foo, &bar)); - | ^^^^^^^^^^^^ help: cast `bar` to obtain a function pointer: `bar as fn(_) -> _` - -warning: taking a reference to a function item does not give a function pointer - --> $DIR/function-item-references.rs:160:30 - | -LL | bound_by_ptr_trait_tuple((&foo, &bar)); - | ^^^^^^^^^^^^ help: cast `foo` to obtain a function pointer: `foo as fn() -> _` - warning: 33 warnings emitted diff --git a/src/test/ui/macros/format-parse-errors.stderr b/src/test/ui/macros/format-parse-errors.stderr index 1a7578e6076eb..f9ea4c63377b0 100644 --- a/src/test/ui/macros/format-parse-errors.stderr +++ b/src/test/ui/macros/format-parse-errors.stderr @@ -22,7 +22,7 @@ error: positional arguments cannot follow named arguments --> $DIR/format-parse-errors.rs:10:9 | LL | foo = foo, - | --- named argument + | --------- named argument LL | bar, | ^^^ positional arguments must be before named arguments diff --git a/src/test/ui/macros/issue-99265.stderr b/src/test/ui/macros/issue-99265.stderr index 2bfeedd7d0737..9185dbff61ee0 100644 --- a/src/test/ui/macros/issue-99265.stderr +++ b/src/test/ui/macros/issue-99265.stderr @@ -77,18 +77,18 @@ help: use the named argument by name to avoid ambiguity LL | println!("Hello {:width$}!", "x", width = 5); | ~~~~~~ -warning: named argument `width` is not used by name - --> $DIR/issue-99265.rs:23:46 +warning: named argument `f` is not used by name + --> $DIR/issue-99265.rs:23:33 | LL | println!("Hello {:1$.2$}!", f = 0.02f32, width = 5, precision = 2); - | -- ^^^^^ this named argument is referred to by position in formatting string - | | - | this formatting argument uses named argument `width` by position + | -------- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `f` by position | help: use the named argument by name to avoid ambiguity | -LL | println!("Hello {:width$.2$}!", f = 0.02f32, width = 5, precision = 2); - | ~~~~~~ +LL | println!("Hello {f:1$.2$}!", f = 0.02f32, width = 5, precision = 2); + | + warning: named argument `precision` is not used by name --> $DIR/issue-99265.rs:23:57 @@ -103,31 +103,31 @@ help: use the named argument by name to avoid ambiguity LL | println!("Hello {:1$.precision$}!", f = 0.02f32, width = 5, precision = 2); | ~~~~~~~~~~ -warning: named argument `f` is not used by name - --> $DIR/issue-99265.rs:23:33 +warning: named argument `width` is not used by name + --> $DIR/issue-99265.rs:23:46 | LL | println!("Hello {:1$.2$}!", f = 0.02f32, width = 5, precision = 2); - | -- ^ this named argument is referred to by position in formatting string - | | - | this formatting argument uses named argument `f` by position + | -- ^^^^^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `width` by position | help: use the named argument by name to avoid ambiguity | -LL | println!("Hello {f:1$.2$}!", f = 0.02f32, width = 5, precision = 2); - | + +LL | println!("Hello {:width$.2$}!", f = 0.02f32, width = 5, precision = 2); + | ~~~~~~ -warning: named argument `width` is not used by name - --> $DIR/issue-99265.rs:31:47 +warning: named argument `f` is not used by name + --> $DIR/issue-99265.rs:31:34 | LL | println!("Hello {0:1$.2$}!", f = 0.02f32, width = 5, precision = 2); - | -- ^^^^^ this named argument is referred to by position in formatting string - | | - | this formatting argument uses named argument `width` by position + | --------- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `f` by position | help: use the named argument by name to avoid ambiguity | -LL | println!("Hello {0:width$.2$}!", f = 0.02f32, width = 5, precision = 2); - | ~~~~~~ +LL | println!("Hello {f:1$.2$}!", f = 0.02f32, width = 5, precision = 2); + | ~ warning: named argument `precision` is not used by name --> $DIR/issue-99265.rs:31:58 @@ -142,32 +142,32 @@ help: use the named argument by name to avoid ambiguity LL | println!("Hello {0:1$.precision$}!", f = 0.02f32, width = 5, precision = 2); | ~~~~~~~~~~ -warning: named argument `f` is not used by name - --> $DIR/issue-99265.rs:31:34 +warning: named argument `width` is not used by name + --> $DIR/issue-99265.rs:31:47 | LL | println!("Hello {0:1$.2$}!", f = 0.02f32, width = 5, precision = 2); - | - ^ this named argument is referred to by position in formatting string - | | - | this formatting argument uses named argument `f` by position + | -- ^^^^^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `width` by position | help: use the named argument by name to avoid ambiguity | -LL | println!("Hello {f:1$.2$}!", f = 0.02f32, width = 5, precision = 2); - | ~ +LL | println!("Hello {0:width$.2$}!", f = 0.02f32, width = 5, precision = 2); + | ~~~~~~ -warning: named argument `width` is not used by name - --> $DIR/issue-99265.rs:52:9 +warning: named argument `f` is not used by name + --> $DIR/issue-99265.rs:49:9 | LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}", - | -- this formatting argument uses named argument `width` by position + | --------- this formatting argument uses named argument `f` by position ... -LL | width = 5, - | ^^^^^ this named argument is referred to by position in formatting string +LL | f = 0.02f32, + | ^ this named argument is referred to by position in formatting string | help: use the named argument by name to avoid ambiguity | -LL | "{}, Hello {1:width$.3$} {4:5$.6$}! {1}", - | ~~~~~~ +LL | "{}, Hello {f:2$.3$} {4:5$.6$}! {1}", + | ~ warning: named argument `precision` is not used by name --> $DIR/issue-99265.rs:54:9 @@ -183,33 +183,33 @@ help: use the named argument by name to avoid ambiguity LL | "{}, Hello {1:2$.precision$} {4:5$.6$}! {1}", | ~~~~~~~~~~ -warning: named argument `f` is not used by name - --> $DIR/issue-99265.rs:49:9 +warning: named argument `width` is not used by name + --> $DIR/issue-99265.rs:52:9 | LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}", - | - this formatting argument uses named argument `f` by position + | -- this formatting argument uses named argument `width` by position ... -LL | f = 0.02f32, - | ^ this named argument is referred to by position in formatting string +LL | width = 5, + | ^^^^^ this named argument is referred to by position in formatting string | help: use the named argument by name to avoid ambiguity | -LL | "{}, Hello {f:2$.3$} {4:5$.6$}! {1}", - | ~ +LL | "{}, Hello {1:width$.3$} {4:5$.6$}! {1}", + | ~~~~~~ -warning: named argument `width2` is not used by name - --> $DIR/issue-99265.rs:58:9 +warning: named argument `g` is not used by name + --> $DIR/issue-99265.rs:56:9 | LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}", - | -- this formatting argument uses named argument `width2` by position + | --------- this formatting argument uses named argument `g` by position ... -LL | width2 = 5, - | ^^^^^^ this named argument is referred to by position in formatting string +LL | g = 0.02f32, + | ^ this named argument is referred to by position in formatting string | help: use the named argument by name to avoid ambiguity | -LL | "{}, Hello {1:2$.3$} {4:width2$.6$}! {1}", - | ~~~~~~~ +LL | "{}, Hello {1:2$.3$} {g:5$.6$}! {1}", + | ~ warning: named argument `precision2` is not used by name --> $DIR/issue-99265.rs:60:9 @@ -225,25 +225,25 @@ help: use the named argument by name to avoid ambiguity LL | "{}, Hello {1:2$.3$} {4:5$.precision2$}! {1}", | ~~~~~~~~~~~ -warning: named argument `g` is not used by name - --> $DIR/issue-99265.rs:56:9 +warning: named argument `width2` is not used by name + --> $DIR/issue-99265.rs:58:9 | LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}", - | - this formatting argument uses named argument `g` by position + | -- this formatting argument uses named argument `width2` by position ... -LL | g = 0.02f32, - | ^ this named argument is referred to by position in formatting string +LL | width2 = 5, + | ^^^^^^ this named argument is referred to by position in formatting string | help: use the named argument by name to avoid ambiguity | -LL | "{}, Hello {1:2$.3$} {g:5$.6$}! {1}", - | ~ +LL | "{}, Hello {1:2$.3$} {4:width2$.6$}! {1}", + | ~~~~~~~ warning: named argument `f` is not used by name --> $DIR/issue-99265.rs:49:9 | LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}", - | - this formatting argument uses named argument `f` by position + | --- this formatting argument uses named argument `f` by position ... LL | f = 0.02f32, | ^ this named argument is referred to by position in formatting string @@ -257,7 +257,7 @@ warning: named argument `f` is not used by name --> $DIR/issue-99265.rs:64:31 | LL | println!("Hello {:0.1}!", f = 0.02f32); - | -- ^ this named argument is referred to by position in formatting string + | ------ ^ this named argument is referred to by position in formatting string | | | this formatting argument uses named argument `f` by position | @@ -270,15 +270,28 @@ warning: named argument `f` is not used by name --> $DIR/issue-99265.rs:68:32 | LL | println!("Hello {0:0.1}!", f = 0.02f32); - | - ^ this named argument is referred to by position in formatting string - | | - | this formatting argument uses named argument `f` by position + | ------- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `f` by position | help: use the named argument by name to avoid ambiguity | LL | println!("Hello {f:0.1}!", f = 0.02f32); | ~ +warning: named argument `v` is not used by name + --> $DIR/issue-99265.rs:79:23 + | +LL | println!("{:0$}", v = val); + | ----- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `v` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{v:0$}", v = val); + | + + warning: named argument `v` is not used by name --> $DIR/issue-99265.rs:79:23 | @@ -293,17 +306,17 @@ LL | println!("{:v$}", v = val); | ~~ warning: named argument `v` is not used by name - --> $DIR/issue-99265.rs:79:23 + --> $DIR/issue-99265.rs:84:24 | -LL | println!("{:0$}", v = val); - | -- ^ this named argument is referred to by position in formatting string +LL | println!("{0:0$}", v = val); + | ------ ^ this named argument is referred to by position in formatting string | | | this formatting argument uses named argument `v` by position | help: use the named argument by name to avoid ambiguity | LL | println!("{v:0$}", v = val); - | + + | ~ warning: named argument `v` is not used by name --> $DIR/issue-99265.rs:84:24 @@ -318,31 +331,18 @@ help: use the named argument by name to avoid ambiguity LL | println!("{0:v$}", v = val); | ~~ -warning: named argument `v` is not used by name - --> $DIR/issue-99265.rs:84:24 - | -LL | println!("{0:0$}", v = val); - | - ^ this named argument is referred to by position in formatting string - | | - | this formatting argument uses named argument `v` by position - | -help: use the named argument by name to avoid ambiguity - | -LL | println!("{v:0$}", v = val); - | ~ - warning: named argument `v` is not used by name --> $DIR/issue-99265.rs:89:26 | LL | println!("{:0$.0$}", v = val); - | -- ^ this named argument is referred to by position in formatting string - | | - | this formatting argument uses named argument `v` by position + | -------- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `v` by position | help: use the named argument by name to avoid ambiguity | -LL | println!("{:v$.0$}", v = val); - | ~~ +LL | println!("{v:0$.0$}", v = val); + | + warning: named argument `v` is not used by name --> $DIR/issue-99265.rs:89:26 @@ -361,27 +361,27 @@ warning: named argument `v` is not used by name --> $DIR/issue-99265.rs:89:26 | LL | println!("{:0$.0$}", v = val); - | -- ^ this named argument is referred to by position in formatting string - | | - | this formatting argument uses named argument `v` by position + | -- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `v` by position | help: use the named argument by name to avoid ambiguity | -LL | println!("{v:0$.0$}", v = val); - | + +LL | println!("{:v$.0$}", v = val); + | ~~ warning: named argument `v` is not used by name --> $DIR/issue-99265.rs:96:27 | LL | println!("{0:0$.0$}", v = val); - | -- ^ this named argument is referred to by position in formatting string - | | - | this formatting argument uses named argument `v` by position + | --------- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `v` by position | help: use the named argument by name to avoid ambiguity | -LL | println!("{0:v$.0$}", v = val); - | ~~ +LL | println!("{v:0$.0$}", v = val); + | ~ warning: named argument `v` is not used by name --> $DIR/issue-99265.rs:96:27 @@ -400,14 +400,14 @@ warning: named argument `v` is not used by name --> $DIR/issue-99265.rs:96:27 | LL | println!("{0:0$.0$}", v = val); - | - ^ this named argument is referred to by position in formatting string - | | - | this formatting argument uses named argument `v` by position + | -- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `v` by position | help: use the named argument by name to avoid ambiguity | -LL | println!("{v:0$.0$}", v = val); - | ~ +LL | println!("{0:v$.0$}", v = val); + | ~~ warning: named argument `a` is not used by name --> $DIR/issue-99265.rs:104:28 @@ -426,28 +426,28 @@ warning: named argument `a` is not used by name --> $DIR/issue-99265.rs:104:28 | LL | println!("{} {a} {0}", a = 1); - | - ^ this named argument is referred to by position in formatting string - | | - | this formatting argument uses named argument `a` by position + | --- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `a` by position | help: use the named argument by name to avoid ambiguity | LL | println!("{} {a} {a}", a = 1); | ~ -warning: named argument `b` is not used by name - --> $DIR/issue-99265.rs:115:23 +warning: named argument `a` is not used by name + --> $DIR/issue-99265.rs:115:14 | LL | {:1$.2$}", - | -- this formatting argument uses named argument `b` by position + | -------- this formatting argument uses named argument `a` by position ... LL | a = 1.0, b = 1, c = 2, - | ^ this named argument is referred to by position in formatting string + | ^ this named argument is referred to by position in formatting string | help: use the named argument by name to avoid ambiguity | -LL | {:b$.2$}", - | ~~ +LL | {a:1$.2$}", + | + warning: named argument `c` is not used by name --> $DIR/issue-99265.rs:115:30 @@ -463,33 +463,33 @@ help: use the named argument by name to avoid ambiguity LL | {:1$.c$}", | ~~ -warning: named argument `a` is not used by name - --> $DIR/issue-99265.rs:115:14 +warning: named argument `b` is not used by name + --> $DIR/issue-99265.rs:115:23 | LL | {:1$.2$}", - | -- this formatting argument uses named argument `a` by position + | -- this formatting argument uses named argument `b` by position ... LL | a = 1.0, b = 1, c = 2, - | ^ this named argument is referred to by position in formatting string + | ^ this named argument is referred to by position in formatting string | help: use the named argument by name to avoid ambiguity | -LL | {a:1$.2$}", - | + +LL | {:b$.2$}", + | ~~ -warning: named argument `b` is not used by name - --> $DIR/issue-99265.rs:126:23 +warning: named argument `a` is not used by name + --> $DIR/issue-99265.rs:126:14 | LL | {0:1$.2$}", - | -- this formatting argument uses named argument `b` by position + | --------- this formatting argument uses named argument `a` by position ... LL | a = 1.0, b = 1, c = 2, - | ^ this named argument is referred to by position in formatting string + | ^ this named argument is referred to by position in formatting string | help: use the named argument by name to avoid ambiguity | -LL | {0:b$.2$}", - | ~~ +LL | {a:1$.2$}", + | ~ warning: named argument `c` is not used by name --> $DIR/issue-99265.rs:126:30 @@ -505,32 +505,32 @@ help: use the named argument by name to avoid ambiguity LL | {0:1$.c$}", | ~~ -warning: named argument `a` is not used by name - --> $DIR/issue-99265.rs:126:14 +warning: named argument `b` is not used by name + --> $DIR/issue-99265.rs:126:23 | LL | {0:1$.2$}", - | - this formatting argument uses named argument `a` by position + | -- this formatting argument uses named argument `b` by position ... LL | a = 1.0, b = 1, c = 2, - | ^ this named argument is referred to by position in formatting string + | ^ this named argument is referred to by position in formatting string | help: use the named argument by name to avoid ambiguity | -LL | {a:1$.2$}", - | ~ +LL | {0:b$.2$}", + | ~~ -warning: named argument `width` is not used by name - --> $DIR/issue-99265.rs:132:39 +warning: named argument `x` is not used by name + --> $DIR/issue-99265.rs:132:30 | LL | println!("{{{:1$.2$}}}", x = 1.0, width = 3, precision = 2); - | -- ^^^^^ this named argument is referred to by position in formatting string - | | - | this formatting argument uses named argument `width` by position + | -------- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `x` by position | help: use the named argument by name to avoid ambiguity | -LL | println!("{{{:width$.2$}}}", x = 1.0, width = 3, precision = 2); - | ~~~~~~ +LL | println!("{{{x:1$.2$}}}", x = 1.0, width = 3, precision = 2); + | + warning: named argument `precision` is not used by name --> $DIR/issue-99265.rs:132:50 @@ -545,18 +545,18 @@ help: use the named argument by name to avoid ambiguity LL | println!("{{{:1$.precision$}}}", x = 1.0, width = 3, precision = 2); | ~~~~~~~~~~ -warning: named argument `x` is not used by name - --> $DIR/issue-99265.rs:132:30 +warning: named argument `width` is not used by name + --> $DIR/issue-99265.rs:132:39 | LL | println!("{{{:1$.2$}}}", x = 1.0, width = 3, precision = 2); - | -- ^ this named argument is referred to by position in formatting string - | | - | this formatting argument uses named argument `x` by position + | -- ^^^^^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `width` by position | help: use the named argument by name to avoid ambiguity | -LL | println!("{{{x:1$.2$}}}", x = 1.0, width = 3, precision = 2); - | + +LL | println!("{{{:width$.2$}}}", x = 1.0, width = 3, precision = 2); + | ~~~~~~ warning: 42 warnings emitted diff --git a/src/test/ui/macros/issue-99907.stderr b/src/test/ui/macros/issue-99907.stderr index 4786ce003b4c2..eefb28dee35b8 100644 --- a/src/test/ui/macros/issue-99907.stderr +++ b/src/test/ui/macros/issue-99907.stderr @@ -2,7 +2,7 @@ warning: named argument `f` is not used by name --> $DIR/issue-99907.rs:5:30 | LL | println!("Hello {:.1}!", f = 0.02f32); - | -- ^ this named argument is referred to by position in formatting string + | ----- ^ this named argument is referred to by position in formatting string | | | this formatting argument uses named argument `f` by position | @@ -16,7 +16,7 @@ warning: named argument `f` is not used by name --> $DIR/issue-99907.rs:9:31 | LL | println!("Hello {:1.1}!", f = 0.02f32); - | -- ^ this named argument is referred to by position in formatting string + | ------ ^ this named argument is referred to by position in formatting string | | | this formatting argument uses named argument `f` by position | diff --git a/src/test/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout b/src/test/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout index 90f858f80e6b5..6fca4f937d4b5 100644 --- a/src/test/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout +++ b/src/test/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout @@ -25,8 +25,18 @@ fn arbitrary_consuming_method_for_demonstration_purposes() { { - ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem as usize\nWith captures:\n elem = ", - "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + ::std::rt::panic_fmt(::core::fmt::Arguments::new(&match (&__capture0,) + { + _args => + |w: &mut dyn ::core::fmt::Write| -> ::core::fmt::Result + { + w.write_str("Assertion failed: elem as usize\nWith captures:\n elem = ")?; + ::core::fmt::Debug::fmt(_args.0, + &mut ::core::fmt::Formatter::new(w))?; + w.write_str("\n")?; + ::core::result::Result::Ok(()) + }, + })) } } }; @@ -41,8 +51,18 @@ fn addr_of() { if ::core::intrinsics::unlikely(!&*__local_bind0) { (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); { - ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: &elem\nWith captures:\n elem = ", - "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + ::std::rt::panic_fmt(::core::fmt::Arguments::new(&match (&__capture0,) + { + _args => + |w: &mut dyn ::core::fmt::Write| -> ::core::fmt::Result + { + w.write_str("Assertion failed: &elem\nWith captures:\n elem = ")?; + ::core::fmt::Debug::fmt(_args.0, + &mut ::core::fmt::Formatter::new(w))?; + w.write_str("\n")?; + ::core::result::Result::Ok(()) + }, + })) } } }; @@ -57,8 +77,18 @@ fn binary() { if ::core::intrinsics::unlikely(!(*__local_bind0 == 1)) { (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); { - ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem == 1\nWith captures:\n elem = ", - "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + ::std::rt::panic_fmt(::core::fmt::Arguments::new(&match (&__capture0,) + { + _args => + |w: &mut dyn ::core::fmt::Write| -> ::core::fmt::Result + { + w.write_str("Assertion failed: elem == 1\nWith captures:\n elem = ")?; + ::core::fmt::Debug::fmt(_args.0, + &mut ::core::fmt::Formatter::new(w))?; + w.write_str("\n")?; + ::core::result::Result::Ok(()) + }, + })) } } }; @@ -70,8 +100,18 @@ fn binary() { if ::core::intrinsics::unlikely(!(*__local_bind0 >= 1)) { (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); { - ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem >= 1\nWith captures:\n elem = ", - "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + ::std::rt::panic_fmt(::core::fmt::Arguments::new(&match (&__capture0,) + { + _args => + |w: &mut dyn ::core::fmt::Write| -> ::core::fmt::Result + { + w.write_str("Assertion failed: elem >= 1\nWith captures:\n elem = ")?; + ::core::fmt::Debug::fmt(_args.0, + &mut ::core::fmt::Formatter::new(w))?; + w.write_str("\n")?; + ::core::result::Result::Ok(()) + }, + })) } } }; @@ -83,8 +123,18 @@ fn binary() { if ::core::intrinsics::unlikely(!(*__local_bind0 > 0)) { (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); { - ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem > 0\nWith captures:\n elem = ", - "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + ::std::rt::panic_fmt(::core::fmt::Arguments::new(&match (&__capture0,) + { + _args => + |w: &mut dyn ::core::fmt::Write| -> ::core::fmt::Result + { + w.write_str("Assertion failed: elem > 0\nWith captures:\n elem = ")?; + ::core::fmt::Debug::fmt(_args.0, + &mut ::core::fmt::Formatter::new(w))?; + w.write_str("\n")?; + ::core::result::Result::Ok(()) + }, + })) } } }; @@ -96,8 +146,18 @@ fn binary() { if ::core::intrinsics::unlikely(!(*__local_bind0 < 3)) { (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); { - ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem < 3\nWith captures:\n elem = ", - "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + ::std::rt::panic_fmt(::core::fmt::Arguments::new(&match (&__capture0,) + { + _args => + |w: &mut dyn ::core::fmt::Write| -> ::core::fmt::Result + { + w.write_str("Assertion failed: elem < 3\nWith captures:\n elem = ")?; + ::core::fmt::Debug::fmt(_args.0, + &mut ::core::fmt::Formatter::new(w))?; + w.write_str("\n")?; + ::core::result::Result::Ok(()) + }, + })) } } }; @@ -109,8 +169,18 @@ fn binary() { if ::core::intrinsics::unlikely(!(*__local_bind0 <= 3)) { (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); { - ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem <= 3\nWith captures:\n elem = ", - "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + ::std::rt::panic_fmt(::core::fmt::Arguments::new(&match (&__capture0,) + { + _args => + |w: &mut dyn ::core::fmt::Write| -> ::core::fmt::Result + { + w.write_str("Assertion failed: elem <= 3\nWith captures:\n elem = ")?; + ::core::fmt::Debug::fmt(_args.0, + &mut ::core::fmt::Formatter::new(w))?; + w.write_str("\n")?; + ::core::result::Result::Ok(()) + }, + })) } } }; @@ -122,8 +192,18 @@ fn binary() { if ::core::intrinsics::unlikely(!(*__local_bind0 != 3)) { (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); { - ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem != 3\nWith captures:\n elem = ", - "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + ::std::rt::panic_fmt(::core::fmt::Arguments::new(&match (&__capture0,) + { + _args => + |w: &mut dyn ::core::fmt::Write| -> ::core::fmt::Result + { + w.write_str("Assertion failed: elem != 3\nWith captures:\n elem = ")?; + ::core::fmt::Debug::fmt(_args.0, + &mut ::core::fmt::Formatter::new(w))?; + w.write_str("\n")?; + ::core::result::Result::Ok(()) + }, + })) } } }; @@ -138,8 +218,18 @@ fn unary() { if ::core::intrinsics::unlikely(!**__local_bind0) { (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); { - ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: *elem\nWith captures:\n elem = ", - "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + ::std::rt::panic_fmt(::core::fmt::Arguments::new(&match (&__capture0,) + { + _args => + |w: &mut dyn ::core::fmt::Write| -> ::core::fmt::Result + { + w.write_str("Assertion failed: *elem\nWith captures:\n elem = ")?; + ::core::fmt::Debug::fmt(_args.0, + &mut ::core::fmt::Formatter::new(w))?; + w.write_str("\n")?; + ::core::result::Result::Ok(()) + }, + })) } } };