summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_builtin_macros/src/format.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_builtin_macros/src/format.rs')
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs193
1 files changed, 86 insertions, 107 deletions
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 9eb96ec76..210048710 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -130,64 +130,46 @@ impl PositionalNamedArgsLint {
/// CountIsParam, which contains an index into the arguments.
fn maybe_add_positional_named_arg(
&mut self,
- current_positional_arg: usize,
- total_args_length: usize,
- format_argument_index: usize,
+ arg: Option<&FormatArg>,
ty: PositionalNamedArgType,
cur_piece: usize,
inner_span_to_replace: Option<rustc_parse_format::InnerSpan>,
- names: &FxHashMap<Symbol, (usize, Span)>,
has_formatting: bool,
) {
- let start_of_named_args = total_args_length - names.len();
- if current_positional_arg >= start_of_named_args {
- self.maybe_push(
- format_argument_index,
- ty,
- cur_piece,
- inner_span_to_replace,
- names,
- has_formatting,
- )
+ if let Some(arg) = arg {
+ if let Some(name) = arg.name {
+ self.push(name, ty, cur_piece, inner_span_to_replace, has_formatting)
+ }
}
}
- /// Try constructing a PositionalNamedArg struct and pushing it into the vec of positional
- /// named arguments. If a named arg associated with `format_argument_index` cannot be found,
- /// a new item will not be added as the lint cannot be emitted in this case.
- fn maybe_push(
+ /// Construct a PositionalNamedArg struct and push it into the vec of positional
+ /// named arguments.
+ fn push(
&mut self,
- format_argument_index: usize,
+ arg_name: Ident,
ty: PositionalNamedArgType,
cur_piece: usize,
inner_span_to_replace: Option<rustc_parse_format::InnerSpan>,
- names: &FxHashMap<Symbol, (usize, Span)>,
has_formatting: bool,
) {
- let named_arg = names
- .iter()
- .find(|&(_, &(index, _))| index == format_argument_index)
- .map(|found| found.clone());
-
- if let Some((&replacement, &(_, positional_named_arg_span))) = named_arg {
- // 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,
- positional_named_arg_span,
- has_formatting,
- });
- }
+ // 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,
+ });
}
}
@@ -211,7 +193,7 @@ struct Context<'a, 'b> {
/// * `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<P<ast::Expr>>,
+ args: Vec<FormatArg>,
/// The number of arguments that were added by implicit capturing.
num_captured_args: usize,
/// Placeholder slot numbers indexed by argument.
@@ -219,7 +201,7 @@ struct Context<'a, 'b> {
/// Unique format specs seen for each argument.
arg_unique_types: Vec<Vec<ArgumentType>>,
/// Map from named arguments to their resolved indices.
- names: FxHashMap<Symbol, (usize, Span)>,
+ names: FxHashMap<Symbol, usize>,
/// The latest consecutive literal strings, or empty if there weren't any.
literal: String,
@@ -282,7 +264,7 @@ struct Context<'a, 'b> {
pub struct FormatArg {
expr: P<ast::Expr>,
- named: bool,
+ name: Option<Ident>,
}
/// Parses the arguments from the given list of tokens, returning the diagnostic
@@ -298,9 +280,9 @@ fn parse_args<'a>(
ecx: &mut ExtCtxt<'a>,
sp: Span,
tts: TokenStream,
-) -> PResult<'a, (P<ast::Expr>, Vec<FormatArg>, FxHashMap<Symbol, (usize, Span)>)> {
+) -> PResult<'a, (P<ast::Expr>, Vec<FormatArg>, FxHashMap<Symbol, usize>)> {
let mut args = Vec::<FormatArg>::new();
- let mut names = FxHashMap::<Symbol, (usize, Span)>::default();
+ let mut names = FxHashMap::<Symbol, usize>::default();
let mut p = ecx.new_parser_from_tts(tts);
@@ -365,9 +347,9 @@ fn parse_args<'a>(
p.bump();
p.expect(&token::Eq)?;
let e = p.parse_expr()?;
- if let Some((prev, _)) = names.get(&ident.name) {
+ 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(args[prev].expr.span, "previously here")
.span_label(e.span, "duplicate argument")
.emit();
continue;
@@ -378,8 +360,8 @@ fn parse_args<'a>(
// 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, ident.span));
- args.push(FormatArg { expr: e, named: true });
+ names.insert(ident.name, slot);
+ args.push(FormatArg { expr: e, name: Some(ident) });
}
_ => {
let e = p.parse_expr()?;
@@ -389,12 +371,12 @@ fn parse_args<'a>(
"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.0].expr.span, "named argument");
+ for &pos in names.values() {
+ err.span_label(args[pos].expr.span, "named argument");
}
err.emit();
}
- args.push(FormatArg { expr: e, named: false });
+ args.push(FormatArg { expr: e, name: None });
}
}
}
@@ -410,8 +392,7 @@ impl<'a, 'b> Context<'a, 'b> {
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)).unwrap_or(&(0, Span::default())).0;
+ let lookup = |s: &str| self.names.get(&Symbol::intern(s)).copied().unwrap_or(0);
match *p {
parse::String(_) => {}
@@ -432,7 +413,7 @@ impl<'a, 'b> Context<'a, 'b> {
/// 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<'_>) {
+ fn verify_piece(&mut self, p: &parse::Piece<'a>) {
match *p {
parse::String(..) => {}
parse::NextArgument(ref arg) => {
@@ -452,18 +433,20 @@ impl<'a, 'b> Context<'a, 'b> {
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(
- i,
- self.args.len(),
- i,
+ self.args.get(i),
PositionalNamedArgType::Arg,
self.curpiece,
Some(arg.position_span),
- &self.names,
has_precision || has_width,
);
@@ -471,13 +454,10 @@ impl<'a, 'b> Context<'a, 'b> {
}
parse::ArgumentImplicitlyIs(i) => {
self.unused_names_lint.maybe_add_positional_named_arg(
- i,
- self.args.len(),
- i,
+ self.args.get(i),
PositionalNamedArgType::Arg,
self.curpiece,
None,
- &self.names,
has_precision || has_width,
);
Exact(i)
@@ -561,15 +541,12 @@ impl<'a, 'b> Context<'a, 'b> {
) {
match c {
parse::CountImplied | parse::CountIs(..) => {}
- parse::CountIsParam(i) => {
+ parse::CountIsParam(i) | parse::CountIsStar(i) => {
self.unused_names_lint.maybe_add_positional_named_arg(
- i,
- self.args.len(),
- i,
+ self.args.get(i),
named_arg_type,
self.curpiece,
*inner_span,
- &self.names,
true,
);
self.verify_arg_type(Exact(i), Count);
@@ -609,7 +586,11 @@ impl<'a, 'b> Context<'a, 'b> {
let mut zero_based_note = false;
let count = self.pieces.len()
- + self.arg_with_formatting.iter().filter(|fmt| fmt.precision_span.is_some()).count();
+ + 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,
@@ -622,7 +603,7 @@ impl<'a, 'b> Context<'a, 'b> {
);
for arg in &self.args {
// Point at the arguments that will be formatted.
- e.span_label(arg.span, "");
+ e.span_label(arg.expr.span, "");
}
} else {
let (mut refs, spans): (Vec<_>, Vec<_>) = refs.unzip();
@@ -658,7 +639,7 @@ impl<'a, 'b> Context<'a, 'b> {
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() => {
+ parse::CountIsParam(pos) if pos >= self.num_args() => {
e.span_label(
span,
&format!(
@@ -670,12 +651,12 @@ impl<'a, 'b> Context<'a, 'b> {
);
zero_based_note = true;
}
- parse::CountIsParam(pos) => {
+ parse::CountIsStar(pos) => {
let count = self.pieces.len()
+ self
.arg_with_formatting
.iter()
- .filter(|fmt| fmt.precision_span.is_some())
+ .filter(|fmt| matches!(fmt.precision, parse::CountIsStar(_)))
.count();
e.span_label(
span,
@@ -692,7 +673,7 @@ impl<'a, 'b> Context<'a, 'b> {
);
if let Some(arg) = self.args.get(pos) {
e.span_label(
- arg.span,
+ arg.expr.span,
"this parameter corresponds to the precision flag",
);
}
@@ -771,7 +752,7 @@ impl<'a, 'b> Context<'a, 'b> {
match self.names.get(&name) {
Some(&idx) => {
// Treat as positional arg.
- self.verify_arg_type(Capture(idx.0), ty)
+ self.verify_arg_type(Capture(idx), ty)
}
None => {
// For the moment capturing variables from format strings expanded from macros is
@@ -787,8 +768,11 @@ impl<'a, 'b> Context<'a, 'b> {
self.fmtsp
};
self.num_captured_args += 1;
- self.args.push(self.ecx.expr_ident(span, Ident::new(name, span)));
- self.names.insert(name, (idx, span));
+ 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);
@@ -853,7 +837,7 @@ impl<'a, 'b> Context<'a, 'b> {
};
match c {
parse::CountIs(i) => count(sym::Is, Some(self.ecx.expr_usize(sp, i))),
- parse::CountIsParam(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.
@@ -924,31 +908,27 @@ impl<'a, 'b> Context<'a, 'b> {
},
position_span: arg.position_span,
format: parse::FormatSpec {
- fill: arg.format.fill,
+ fill: None,
align: parse::AlignUnknown,
flags: 0,
precision: parse::CountImplied,
- precision_span: None,
+ precision_span: arg.format.precision_span,
width: parse::CountImplied,
- width_span: None,
+ 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 arg.format.precision_span.is_some() || arg.format.width_span.is_some() {
- self.arg_with_formatting.push(arg.format);
- }
- if !pos_simple || arg.format != simple_arg.format || fill != ' ' {
+ if !pos_simple || arg.format != simple_arg.format {
self.all_pieces_simple = false;
}
// Build the format
- let fill = self.ecx.expr_lit(sp, ast::LitKind::Char(fill));
+ 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));
@@ -1054,11 +1034,11 @@ impl<'a, 'b> Context<'a, 'b> {
// 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(|e| may_contain_yield_point(e));
+ 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];
+ 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());
@@ -1087,7 +1067,9 @@ impl<'a, 'b> Context<'a, 'b> {
// span is otherwise unavailable in the MIR used by borrowck).
let heads = original_args
.into_iter()
- .map(|e| self.ecx.expr_addr_of(e.span.with_ctxt(self.macsp.ctxt()), e))
+ .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));
@@ -1199,7 +1181,7 @@ fn create_lints_for_named_arguments_used_positionally(cx: &mut Context<'_, '_>)
cx.ecx.buffered_early_lint.push(BufferedEarlyLint {
span: MultiSpan::from_span(named_arg.positional_named_arg_span),
- msg: msg.clone(),
+ msg: msg.into(),
node_id: ast::CRATE_NODE_ID,
lint_id: LintId::of(&NAMED_ARGUMENTS_USED_POSITIONALLY),
diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally {
@@ -1220,7 +1202,7 @@ pub fn expand_preparsed_format_args(
sp: Span,
efmt: P<ast::Expr>,
args: Vec<FormatArg>,
- names: FxHashMap<Symbol, (usize, Span)>,
+ names: FxHashMap<Symbol, usize>,
append_newline: bool,
) -> P<ast::Expr> {
// NOTE: this verbose way of initializing `Vec<Vec<ArgumentType>>` is because
@@ -1312,16 +1294,17 @@ pub fn expand_preparsed_format_args(
if err.should_be_replaced_with_positional_argument {
let captured_arg_span =
fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end));
- let positional_args = args.iter().filter(|arg| !arg.named).collect::<Vec<_>>();
+ 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 positional_args.last() {
+ let span = match args[..n_positional_args].last() {
Some(arg) => arg.expr.span,
None => fmt_sp,
};
e.multipart_suggestion_verbose(
"consider using a positional formatting argument instead",
vec![
- (captured_arg_span, positional_args.len().to_string()),
+ (captured_arg_span, n_positional_args.to_string()),
(span.shrink_to_hi(), format!(", {}", arg)),
],
Applicability::MachineApplicable,
@@ -1338,11 +1321,9 @@ pub fn expand_preparsed_format_args(
.map(|span| fmt_span.from_inner(InnerSpan::new(span.start, span.end)))
.collect();
- let named_pos: FxHashSet<usize> = names.values().cloned().map(|(i, _)| i).collect();
-
let mut cx = Context {
ecx,
- args: args.into_iter().map(|arg| arg.expr).collect(),
+ args,
num_captured_args: 0,
arg_types,
arg_unique_types,
@@ -1410,14 +1391,12 @@ pub fn expand_preparsed_format_args(
.enumerate()
.filter(|(i, ty)| ty.is_empty() && !cx.count_positions.contains_key(&i))
.map(|(i, _)| {
- let msg = if named_pos.contains(&i) {
- // named argument
+ let msg = if cx.args[i].name.is_some() {
"named argument never used"
} else {
- // positional argument
"argument never used"
};
- (cx.args[i].span, msg)
+ (cx.args[i].expr.span, msg)
})
.collect::<Vec<_>>();