Skip to content

Commit

Permalink
Auto merge of rust-lang#96558 - bjorn3:librarify_parse_format, r=davi…
Browse files Browse the repository at this point in the history
…dtwco

Make rustc_parse_format compile on stable

This allows it to be used by lightweight formatting systems and may allow it to be used by rust-analyzer.
  • Loading branch information
bors committed May 3, 2022
2 parents 086bf7a + d33140d commit e1b71fe
Show file tree
Hide file tree
Showing 9 changed files with 231 additions and 191 deletions.
1 change: 0 additions & 1 deletion Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4171,7 +4171,6 @@ name = "rustc_parse_format"
version = "0.0.0"
dependencies = [
"rustc_lexer",
"rustc_span",
]

[[package]]
Expand Down
39 changes: 27 additions & 12 deletions compiler/rustc_builtin_macros/src/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -626,15 +626,15 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl

if !parser.errors.is_empty() {
let err = parser.errors.remove(0);
let err_sp = template_span.from_inner(err.span);
let err_sp = template_span.from_inner(InnerSpan::new(err.span.start, err.span.end));
let msg = &format!("invalid asm template string: {}", err.description);
let mut e = ecx.struct_span_err(err_sp, msg);
e.span_label(err_sp, err.label + " in asm template string");
if let Some(note) = err.note {
e.note(&note);
}
if let Some((label, span)) = err.secondary_label {
let err_sp = template_span.from_inner(span);
let err_sp = template_span.from_inner(InnerSpan::new(span.start, span.end));
e.span_label(err_sp, label);
}
e.emit();
Expand All @@ -643,7 +643,10 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl

curarg = parser.curarg;

let mut arg_spans = parser.arg_places.iter().map(|span| template_span.from_inner(*span));
let mut arg_spans = parser
.arg_places
.iter()
.map(|span| template_span.from_inner(InnerSpan::new(span.start, span.end)));
for piece in unverified_pieces {
match piece {
parse::Piece::String(s) => {
Expand Down Expand Up @@ -699,14 +702,21 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
Some(idx)
}
}
parse::ArgumentNamed(name, span) => match args.named_args.get(&name) {
Some(&idx) => Some(idx),
None => {
let msg = format!("there is no argument named `{}`", name);
ecx.struct_span_err(template_span.from_inner(span), &msg).emit();
None
parse::ArgumentNamed(name, span) => {
match args.named_args.get(&Symbol::intern(name)) {
Some(&idx) => Some(idx),
None => {
let msg = format!("there is no argument named `{}`", name);
ecx.struct_span_err(
template_span
.from_inner(InnerSpan::new(span.start, span.end)),
&msg,
)
.emit();
None
}
}
},
}
};

let mut chars = arg.format.ty.chars();
Expand All @@ -715,7 +725,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
let span = arg
.format
.ty_span
.map(|sp| template_sp.from_inner(sp))
.map(|sp| template_sp.from_inner(InnerSpan::new(sp.start, sp.end)))
.unwrap_or(template_sp);
ecx.struct_span_err(
span,
Expand All @@ -741,7 +751,12 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
let template_num_lines = 1 + template_str.matches('\n').count();
line_spans.extend(std::iter::repeat(template_sp).take(template_num_lines));
} else {
line_spans.extend(parser.line_spans.iter().map(|span| template_span.from_inner(*span)));
line_spans.extend(
parser
.line_spans
.iter()
.map(|span| template_span.from_inner(InnerSpan::new(span.start, span.end))),
);
};
}

Expand Down
34 changes: 23 additions & 11 deletions compiler/rustc_builtin_macros/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ impl<'a, 'b> Context<'a, 'b> {
fn resolve_name_inplace(&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: Symbol| *self.names.get(&s).unwrap_or(&0);
let lookup = |s: &str| *self.names.get(&Symbol::intern(s)).unwrap_or(&0);

match *p {
parse::String(_) => {}
Expand Down Expand Up @@ -276,7 +276,9 @@ impl<'a, 'b> Context<'a, 'b> {
// it's written second, so it should come after width/precision.
let pos = match arg.position {
parse::ArgumentIs(i) | parse::ArgumentImplicitlyIs(i) => Exact(i),
parse::ArgumentNamed(s, span) => Named(s, span),
parse::ArgumentNamed(s, span) => {
Named(Symbol::intern(s), InnerSpan::new(span.start, span.end))
}
};

let ty = Placeholder(match arg.format.ty {
Expand All @@ -291,7 +293,10 @@ impl<'a, 'b> Context<'a, 'b> {
"X" => "UpperHex",
_ => {
let fmtsp = self.fmtsp;
let sp = arg.format.ty_span.map(|sp| fmtsp.from_inner(sp));
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),
Expand Down Expand Up @@ -340,14 +345,17 @@ impl<'a, 'b> Context<'a, 'b> {
}
}

fn verify_count(&mut self, c: parse::Count) {
fn verify_count(&mut self, c: parse::Count<'_>) {
match c {
parse::CountImplied | parse::CountIs(..) => {}
parse::CountIsParam(i) => {
self.verify_arg_type(Exact(i), Count);
}
parse::CountIsName(s, span) => {
self.verify_arg_type(Named(s, span), Count);
self.verify_arg_type(
Named(Symbol::intern(s), InnerSpan::new(span.start, span.end)),
Count,
);
}
}
}
Expand Down Expand Up @@ -425,7 +433,7 @@ impl<'a, 'b> Context<'a, 'b> {

for fmt in &self.arg_with_formatting {
if let Some(span) = fmt.precision_span {
let span = self.fmtsp.from_inner(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(
Expand Down Expand Up @@ -471,7 +479,7 @@ impl<'a, 'b> Context<'a, 'b> {
}
}
if let Some(span) = fmt.width_span {
let span = self.fmtsp.from_inner(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(
Expand Down Expand Up @@ -610,7 +618,7 @@ impl<'a, 'b> Context<'a, 'b> {
ecx.std_path(&[sym::fmt, sym::rt, sym::v1, s])
}

fn build_count(&self, c: parse::Count) -> P<ast::Expr> {
fn build_count(&self, c: parse::Count<'_>) -> P<ast::Expr> {
let sp = self.macsp;
let count = |c, arg| {
let mut path = Context::rtpath(self.ecx, sym::Count);
Expand Down Expand Up @@ -1033,7 +1041,7 @@ pub fn expand_preparsed_format_args(
if !parser.errors.is_empty() {
let err = parser.errors.remove(0);
let sp = if efmt_kind_is_lit {
fmt_span.from_inner(err.span)
fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end))
} else {
// The format string could be another macro invocation, e.g.:
// format!(concat!("abc", "{}"), 4);
Expand All @@ -1052,14 +1060,18 @@ pub fn expand_preparsed_format_args(
}
if let Some((label, span)) = err.secondary_label {
if efmt_kind_is_lit {
e.span_label(fmt_span.from_inner(span), label);
e.span_label(fmt_span.from_inner(InnerSpan::new(span.start, span.end)), label);
}
}
e.emit();
return DummyResult::raw_expr(sp, true);
}

let arg_spans = parser.arg_places.iter().map(|span| fmt_span.from_inner(*span)).collect();
let arg_spans = parser
.arg_places
.iter()
.map(|span| fmt_span.from_inner(InnerSpan::new(span.start, span.end)))
.collect();

let named_pos: FxHashSet<usize> = names.values().cloned().collect();

Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_lint/src/non_fmt_panic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,10 @@ fn check_panic_str<'tcx>(
if n_arguments > 0 && fmt_parser.errors.is_empty() {
let arg_spans: Vec<_> = match &fmt_parser.arg_places[..] {
[] => vec![fmt_span],
v => v.iter().map(|span| fmt_span.from_inner(*span)).collect(),
v => v
.iter()
.map(|span| fmt_span.from_inner(InnerSpan::new(span.start, span.end)))
.collect(),
};
cx.struct_span_lint(NON_FMT_PANICS, arg_spans, |lint| {
let mut l = lint.build(match n_arguments {
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_parse_format/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,4 @@ version = "0.0.0"
edition = "2021"

[dependencies]
rustc_span = { path = "../rustc_span" }
rustc_lexer = { path = "../rustc_lexer" }
44 changes: 28 additions & 16 deletions compiler/rustc_parse_format/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
html_playground_url = "https://play.rust-lang.org/",
test(attr(deny(warnings)))
)]
#![feature(nll)]
#![feature(bool_to_option)]
// We want to be able to build this crate with a stable compiler, so no
// `#![feature]` attributes should be added.

pub use Alignment::*;
pub use Count::*;
Expand All @@ -22,7 +22,19 @@ use std::iter;
use std::str;
use std::string;

use rustc_span::{InnerSpan, Symbol};
// Note: copied from rustc_span
/// Range inside of a `Span` used for diagnostics when we only have access to relative positions.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct InnerSpan {
pub start: usize,
pub end: usize,
}

impl InnerSpan {
pub fn new(start: usize, end: usize) -> InnerSpan {
InnerSpan { start, end }
}
}

/// The type of format string that we are parsing.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
Expand Down Expand Up @@ -57,7 +69,7 @@ pub enum Piece<'a> {
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Argument<'a> {
/// Where to find this argument
pub position: Position,
pub position: Position<'a>,
/// How to format the argument
pub format: FormatSpec<'a>,
}
Expand All @@ -72,11 +84,11 @@ pub struct FormatSpec<'a> {
/// Packed version of various flags provided.
pub flags: u32,
/// The integer precision to use.
pub precision: Count,
pub precision: Count<'a>,
/// The span of the precision formatting flag (for diagnostics).
pub precision_span: Option<InnerSpan>,
/// The string width requested for the resulting format.
pub width: Count,
pub width: Count<'a>,
/// The span of the width formatting flag (for diagnostics).
pub width_span: Option<InnerSpan>,
/// The descriptor string representing the name of the format desired for
Expand All @@ -89,16 +101,16 @@ pub struct FormatSpec<'a> {

/// Enum describing where an argument for a format can be located.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Position {
pub enum Position<'a> {
/// The argument is implied to be located at an index
ArgumentImplicitlyIs(usize),
/// The argument is located at a specific index given in the format
ArgumentIs(usize),
/// The argument has a name.
ArgumentNamed(Symbol, InnerSpan),
ArgumentNamed(&'a str, InnerSpan),
}

impl Position {
impl Position<'_> {
pub fn index(&self) -> Option<usize> {
match self {
ArgumentIs(i) | ArgumentImplicitlyIs(i) => Some(*i),
Expand Down Expand Up @@ -143,11 +155,11 @@ pub enum Flag {
/// A count is used for the precision and width parameters of an integer, and
/// can reference either an argument or a literal integer.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Count {
pub enum Count<'a> {
/// The count is specified explicitly.
CountIs(usize),
/// The count is specified by the argument with the given name.
CountIsName(Symbol, InnerSpan),
CountIsName(&'a str, InnerSpan),
/// The count is specified by the argument at the given index.
CountIsParam(usize),
/// The count is implied and cannot be explicitly specified.
Expand Down Expand Up @@ -489,7 +501,7 @@ impl<'a> Parser<'a> {
/// integer index of an argument, a named argument, or a blank string.
/// Returns `Some(parsed_position)` if the position is not implicitly
/// consuming a macro argument, `None` if it's the case.
fn position(&mut self) -> Option<Position> {
fn position(&mut self) -> Option<Position<'a>> {
if let Some(i) = self.integer() {
Some(ArgumentIs(i))
} else {
Expand All @@ -498,7 +510,7 @@ impl<'a> Parser<'a> {
let word = self.word();
let end = start + word.len();
let span = self.to_span_index(start).to(self.to_span_index(end));
Some(ArgumentNamed(Symbol::intern(word), span))
Some(ArgumentNamed(word, span))
}

// This is an `ArgumentNext`.
Expand Down Expand Up @@ -651,7 +663,7 @@ impl<'a> Parser<'a> {
/// Parses a `Count` parameter at the current position. This does not check
/// for 'CountIsNextParam' because that is only used in precision, not
/// width.
fn count(&mut self, start: usize) -> (Count, Option<InnerSpan>) {
fn count(&mut self, start: usize) -> (Count<'a>, Option<InnerSpan>) {
if let Some(i) = self.integer() {
if let Some(end) = self.consume_pos('$') {
let span = self.to_span_index(start).to(self.to_span_index(end + 1));
Expand All @@ -667,7 +679,7 @@ impl<'a> Parser<'a> {
(CountImplied, None)
} else if let Some(end) = self.consume_pos('$') {
let span = self.to_span_index(start + 1).to(self.to_span_index(end));
(CountIsName(Symbol::intern(word), span), None)
(CountIsName(word, span), None)
} else {
self.cur = tmp;
(CountImplied, None)
Expand Down Expand Up @@ -723,7 +735,7 @@ impl<'a> Parser<'a> {
break;
}
}
found.then_some(cur)
if found { Some(cur) } else { None }
}
}

Expand Down
Loading

0 comments on commit e1b71fe

Please sign in to comment.