Skip to content

Commit f3eb8ce

Browse files
committed
Make top-level rustc_parse functions fallible.
Currently we have an awkward mix of fallible and infallible functions: ``` new_parser_from_source_str maybe_new_parser_from_source_str new_parser_from_file (maybe_new_parser_from_file) // missing (new_parser_from_source_file) // missing maybe_new_parser_from_source_file source_str_to_stream maybe_source_file_to_stream ``` We could add the two missing functions, but instead this commit removes of all the infallible ones and renames the fallible ones leaving us with these which are all fallible: ``` new_parser_from_source_str new_parser_from_file new_parser_from_source_file source_str_to_stream source_file_to_stream ``` This requires making `unwrap_or_emit_fatal` public so callers of formerly infallible functions can still work. This does make some of the call sites slightly more verbose, but I think it's worth it for the simpler API. Also, there are two `catch_unwind` calls and one `catch_fatal_errors` call in this diff that become removable thanks this change. (I will do that in a follow-up PR.)
1 parent 4eb6303 commit f3eb8ce

File tree

16 files changed

+105
-75
lines changed

16 files changed

+105
-75
lines changed

compiler/rustc_builtin_macros/src/cmdline_attrs.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,17 @@ use crate::errors;
44
use rustc_ast::attr::mk_attr;
55
use rustc_ast::token;
66
use rustc_ast::{self as ast, AttrItem, AttrStyle};
7+
use rustc_parse::{new_parser_from_source_str, unwrap_or_emit_fatal};
78
use rustc_session::parse::ParseSess;
89
use rustc_span::FileName;
910

1011
pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) {
1112
for raw_attr in attrs {
12-
let mut parser = rustc_parse::new_parser_from_source_str(
13+
let mut parser = unwrap_or_emit_fatal(new_parser_from_source_str(
1314
psess,
1415
FileName::cli_crate_attr_source_code(raw_attr),
1516
raw_attr.clone(),
16-
);
17+
));
1718

1819
let start_span = parser.token.span;
1920
let AttrItem { path, args, tokens: _ } = match parser.parse_attr_item(false) {

compiler/rustc_builtin_macros/src/source_util.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ use rustc_expand::base::{
1212
};
1313
use rustc_expand::module::DirOwnership;
1414
use rustc_lint_defs::BuiltinLintDiag;
15-
use rustc_parse::new_parser_from_file;
1615
use rustc_parse::parser::{ForceCollect, Parser};
16+
use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal};
1717
use rustc_session::lint::builtin::INCOMPLETE_INCLUDE;
1818
use rustc_span::source_map::SourceMap;
1919
use rustc_span::symbol::Symbol;
@@ -126,7 +126,7 @@ pub(crate) fn expand_include<'cx>(
126126
return ExpandResult::Ready(DummyResult::any(sp, guar));
127127
}
128128
};
129-
let p = new_parser_from_file(cx.psess(), &file, Some(sp));
129+
let p = unwrap_or_emit_fatal(new_parser_from_file(cx.psess(), &file, Some(sp)));
130130

131131
// If in the included file we have e.g., `mod bar;`,
132132
// then the path of `bar.rs` should be relative to the directory of `file`.

compiler/rustc_driver_impl/src/lib.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use rustc_interface::{interface, Queries};
3232
use rustc_lint::unerased_lint_store;
3333
use rustc_metadata::creader::MetadataLoader;
3434
use rustc_metadata::locator;
35-
use rustc_parse::{new_parser_from_file, new_parser_from_source_str};
35+
use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal};
3636
use rustc_session::config::{nightly_options, CG_OPTIONS, Z_OPTIONS};
3737
use rustc_session::config::{ErrorOutputType, Input, OutFileName, OutputType};
3838
use rustc_session::getopts::{self, Matches};
@@ -1261,12 +1261,12 @@ pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option<geto
12611261
}
12621262

12631263
fn parse_crate_attrs<'a>(sess: &'a Session) -> PResult<'a, ast::AttrVec> {
1264-
let mut parser = match &sess.io.input {
1264+
let mut parser = unwrap_or_emit_fatal(match &sess.io.input {
12651265
Input::File(file) => new_parser_from_file(&sess.psess, file, None),
12661266
Input::Str { name, input } => {
12671267
new_parser_from_source_str(&sess.psess, name.clone(), input.clone())
12681268
}
1269-
};
1269+
});
12701270
parser.parse_inner_attributes()
12711271
}
12721272

compiler/rustc_expand/src/module.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use crate::errors::{
55
use rustc_ast::ptr::P;
66
use rustc_ast::{token, AttrVec, Attribute, Inline, Item, ModSpans};
77
use rustc_errors::{Diag, ErrorGuaranteed};
8-
use rustc_parse::new_parser_from_file;
98
use rustc_parse::validate_attr;
9+
use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal};
1010
use rustc_session::parse::ParseSess;
1111
use rustc_session::Session;
1212
use rustc_span::symbol::{sym, Ident};
@@ -66,7 +66,8 @@ pub(crate) fn parse_external_mod(
6666
}
6767

6868
// Actually parse the external file as a module.
69-
let mut parser = new_parser_from_file(&sess.psess, &mp.file_path, Some(span));
69+
let mut parser =
70+
unwrap_or_emit_fatal(new_parser_from_file(&sess.psess, &mp.file_path, Some(span)));
7071
let (inner_attrs, items, inner_span) =
7172
parser.parse_mod(&token::Eof).map_err(|err| ModError::ParserError(err))?;
7273
attrs.extend(inner_attrs);

compiler/rustc_expand/src/proc_macro_server.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use rustc_data_structures::sync::Lrc;
1414
use rustc_errors::{Diag, ErrorGuaranteed, MultiSpan, PResult};
1515
use rustc_parse::lexer::nfc_normalize;
1616
use rustc_parse::parser::Parser;
17-
use rustc_parse::source_str_to_stream;
17+
use rustc_parse::{new_parser_from_source_str, source_str_to_stream, unwrap_or_emit_fatal};
1818
use rustc_session::parse::ParseSess;
1919
use rustc_span::def_id::CrateNum;
2020
use rustc_span::symbol::{self, sym, Symbol};
@@ -468,7 +468,8 @@ impl server::FreeFunctions for Rustc<'_, '_> {
468468

469469
fn literal_from_str(&mut self, s: &str) -> Result<Literal<Self::Span, Self::Symbol>, ()> {
470470
let name = FileName::proc_macro_source_code(s);
471-
let mut parser = rustc_parse::new_parser_from_source_str(self.psess(), name, s.to_owned());
471+
let mut parser =
472+
unwrap_or_emit_fatal(new_parser_from_source_str(self.psess(), name, s.to_owned()));
472473

473474
let first_span = parser.token.span.data();
474475
let minus_present = parser.eat(&token::BinOp(token::Minus));
@@ -540,12 +541,12 @@ impl server::TokenStream for Rustc<'_, '_> {
540541
}
541542

542543
fn from_str(&mut self, src: &str) -> Self::TokenStream {
543-
source_str_to_stream(
544+
unwrap_or_emit_fatal(source_str_to_stream(
544545
self.psess(),
545546
FileName::proc_macro_source_code(src),
546547
src.to_string(),
547548
Some(self.call_site),
548-
)
549+
))
549550
}
550551

551552
fn to_string(&mut self, stream: &Self::TokenStream) -> String {

compiler/rustc_interface/src/interface.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use rustc_lint::LintStore;
1414
use rustc_middle::ty;
1515
use rustc_middle::ty::CurrentGcx;
1616
use rustc_middle::util::Providers;
17-
use rustc_parse::maybe_new_parser_from_source_str;
17+
use rustc_parse::new_parser_from_source_str;
1818
use rustc_query_impl::QueryCtxt;
1919
use rustc_query_system::query::print_query_stack;
2020
use rustc_session::config::{self, Cfg, CheckCfg, ExpectedValues, Input, OutFileName};
@@ -67,7 +67,7 @@ pub(crate) fn parse_cfg(dcx: &DiagCtxt, cfgs: Vec<String>) -> Cfg {
6767
};
6868
}
6969

70-
match maybe_new_parser_from_source_str(&psess, filename, s.to_string()) {
70+
match new_parser_from_source_str(&psess, filename, s.to_string()) {
7171
Ok(mut parser) => match parser.parse_meta_item() {
7272
Ok(meta_item) if parser.token == token::Eof => {
7373
if meta_item.path.segments.len() != 1 {
@@ -166,7 +166,7 @@ pub(crate) fn parse_check_cfg(dcx: &DiagCtxt, specs: Vec<String>) -> CheckCfg {
166166
error!("expected `cfg(name, values(\"value1\", \"value2\", ... \"valueN\"))`")
167167
};
168168

169-
let mut parser = match maybe_new_parser_from_source_str(&psess, filename, s.to_string()) {
169+
let mut parser = match new_parser_from_source_str(&psess, filename, s.to_string()) {
170170
Ok(parser) => parser,
171171
Err(errs) => {
172172
errs.into_iter().for_each(|err| err.cancel());

compiler/rustc_interface/src/passes.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ use rustc_middle::arena::Arena;
1919
use rustc_middle::dep_graph::DepGraph;
2020
use rustc_middle::ty::{self, GlobalCtxt, RegisteredTools, TyCtxt};
2121
use rustc_middle::util::Providers;
22-
use rustc_parse::{new_parser_from_file, new_parser_from_source_str, validate_attr};
22+
use rustc_parse::{
23+
new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal, validate_attr,
24+
};
2325
use rustc_passes::{abi_test, hir_stats, layout_test};
2426
use rustc_resolve::Resolver;
2527
use rustc_session::code_stats::VTableSizeInfo;
@@ -43,12 +45,12 @@ use tracing::{info, instrument};
4345

4446
pub fn parse<'a>(sess: &'a Session) -> PResult<'a, ast::Crate> {
4547
let krate = sess.time("parse_crate", || {
46-
let mut parser = match &sess.io.input {
48+
let mut parser = unwrap_or_emit_fatal(match &sess.io.input {
4749
Input::File(file) => new_parser_from_file(&sess.psess, file, None),
4850
Input::Str { input, name } => {
4951
new_parser_from_source_str(&sess.psess, name.clone(), input.clone())
5052
}
51-
};
53+
});
5254
parser.parse_crate_mod()
5355
})?;
5456

compiler/rustc_parse/src/lib.rs

+30-24
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ mod errors;
3434
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
3535

3636
// Unwrap the result if `Ok`, otherwise emit the diagnostics and abort.
37-
fn unwrap_or_emit_fatal<T>(expr: Result<T, Vec<Diag<'_>>>) -> T {
37+
pub fn unwrap_or_emit_fatal<T>(expr: Result<T, Vec<Diag<'_>>>) -> T {
3838
match expr {
3939
Ok(expr) => expr,
4040
Err(errs) => {
@@ -46,25 +46,28 @@ fn unwrap_or_emit_fatal<T>(expr: Result<T, Vec<Diag<'_>>>) -> T {
4646
}
4747
}
4848

49-
/// Creates a new parser from a source string.
50-
pub fn new_parser_from_source_str(psess: &ParseSess, name: FileName, source: String) -> Parser<'_> {
51-
unwrap_or_emit_fatal(maybe_new_parser_from_source_str(psess, name, source))
52-
}
53-
54-
/// Creates a new parser from a source string. Returns any buffered errors from lexing the initial
55-
/// token stream; these must be consumed via `emit`, `cancel`, etc., otherwise a panic will occur
56-
/// when they are dropped.
57-
pub fn maybe_new_parser_from_source_str(
49+
/// Creates a new parser from a source string. On failure, the errors must be consumed via
50+
/// `unwrap_or_emit_fatal`, `emit`, `cancel`, etc., otherwise a panic will occur when they are
51+
/// dropped.
52+
pub fn new_parser_from_source_str(
5853
psess: &ParseSess,
5954
name: FileName,
6055
source: String,
6156
) -> Result<Parser<'_>, Vec<Diag<'_>>> {
62-
maybe_new_parser_from_source_file(psess, psess.source_map().new_source_file(name, source))
57+
let source_file = psess.source_map().new_source_file(name, source);
58+
new_parser_from_source_file(psess, source_file)
6359
}
6460

65-
/// Creates a new parser, aborting if the file doesn't exist. If a span is given, that is used on
66-
/// an error as the source of the problem.
67-
pub fn new_parser_from_file<'a>(psess: &'a ParseSess, path: &Path, sp: Option<Span>) -> Parser<'a> {
61+
/// Creates a new parser from a filename. On failure, the errors must be consumed via
62+
/// `unwrap_or_emit_fatal`, `emit`, `cancel`, etc., otherwise a panic will occur when they are
63+
/// dropped.
64+
///
65+
/// If a span is given, that is used on an error as the source of the problem.
66+
pub fn new_parser_from_file<'a>(
67+
psess: &'a ParseSess,
68+
path: &Path,
69+
sp: Option<Span>,
70+
) -> Result<Parser<'a>, Vec<Diag<'a>>> {
6871
let source_file = psess.source_map().load_file(path).unwrap_or_else(|e| {
6972
let msg = format!("couldn't read {}: {}", path.display(), e);
7073
let mut err = psess.dcx.struct_fatal(msg);
@@ -73,23 +76,21 @@ pub fn new_parser_from_file<'a>(psess: &'a ParseSess, path: &Path, sp: Option<Sp
7376
}
7477
err.emit();
7578
});
76-
77-
unwrap_or_emit_fatal(maybe_new_parser_from_source_file(psess, source_file))
79+
new_parser_from_source_file(psess, source_file)
7880
}
7981

8082
/// Given a session and a `source_file`, return a parser. Returns any buffered errors from lexing
8183
/// the initial token stream.
82-
fn maybe_new_parser_from_source_file(
84+
fn new_parser_from_source_file(
8385
psess: &ParseSess,
8486
source_file: Lrc<SourceFile>,
8587
) -> Result<Parser<'_>, Vec<Diag<'_>>> {
8688
let end_pos = source_file.end_position();
87-
let stream = maybe_source_file_to_stream(psess, source_file, None)?;
89+
let stream = source_file_to_stream(psess, source_file, None)?;
8890
let mut parser = Parser::new(psess, stream, None);
8991
if parser.token == token::Eof {
9092
parser.token.span = Span::new(end_pos, end_pos, parser.token.span.ctxt(), None);
9193
}
92-
9394
Ok(parser)
9495
}
9596

@@ -98,14 +99,14 @@ pub fn source_str_to_stream(
9899
name: FileName,
99100
source: String,
100101
override_span: Option<Span>,
101-
) -> TokenStream {
102+
) -> Result<TokenStream, Vec<Diag<'_>>> {
102103
let source_file = psess.source_map().new_source_file(name, source);
103-
unwrap_or_emit_fatal(maybe_source_file_to_stream(psess, source_file, override_span))
104+
source_file_to_stream(psess, source_file, override_span)
104105
}
105106

106107
/// Given a source file, produces a sequence of token trees. Returns any buffered errors from
107108
/// parsing the token stream.
108-
fn maybe_source_file_to_stream<'psess>(
109+
fn source_file_to_stream<'psess>(
109110
psess: &'psess ParseSess,
110111
source_file: Lrc<SourceFile>,
111112
override_span: Option<Span>,
@@ -138,13 +139,18 @@ pub fn parse_in<'a, T>(
138139
pub fn fake_token_stream_for_item(psess: &ParseSess, item: &ast::Item) -> TokenStream {
139140
let source = pprust::item_to_string(item);
140141
let filename = FileName::macro_expansion_source_code(&source);
141-
source_str_to_stream(psess, filename, source, Some(item.span))
142+
unwrap_or_emit_fatal(source_str_to_stream(psess, filename, source, Some(item.span)))
142143
}
143144

144145
pub fn fake_token_stream_for_crate(psess: &ParseSess, krate: &ast::Crate) -> TokenStream {
145146
let source = pprust::crate_to_string_for_macros(krate);
146147
let filename = FileName::macro_expansion_source_code(&source);
147-
source_str_to_stream(psess, filename, source, Some(krate.spans.inner_span))
148+
unwrap_or_emit_fatal(source_str_to_stream(
149+
psess,
150+
filename,
151+
source,
152+
Some(krate.spans.inner_span),
153+
))
148154
}
149155

150156
pub fn parse_cfg_attr(

compiler/rustc_parse/src/parser/tests.rs

+17-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use crate::parser::ForceCollect;
2-
use crate::{new_parser_from_source_str, parser::Parser, source_str_to_stream};
2+
use crate::{
3+
new_parser_from_source_str, parser::Parser, source_str_to_stream, unwrap_or_emit_fatal,
4+
};
35
use ast::token::IdentIsRaw;
46
use rustc_ast::ptr::P;
57
use rustc_ast::token::{self, Delimiter, Token};
@@ -29,7 +31,11 @@ fn psess() -> ParseSess {
2931

3032
/// Map string to parser (via tts).
3133
fn string_to_parser(psess: &ParseSess, source_str: String) -> Parser<'_> {
32-
new_parser_from_source_str(psess, PathBuf::from("bogofile").into(), source_str)
34+
unwrap_or_emit_fatal(new_parser_from_source_str(
35+
psess,
36+
PathBuf::from("bogofile").into(),
37+
source_str,
38+
))
3339
}
3440

3541
fn create_test_handler() -> (DiagCtxt, Lrc<SourceMap>, Arc<Mutex<Vec<u8>>>) {
@@ -82,7 +88,12 @@ where
8288
/// Maps a string to tts, using a made-up filename.
8389
pub(crate) fn string_to_stream(source_str: String) -> TokenStream {
8490
let psess = psess();
85-
source_str_to_stream(&psess, PathBuf::from("bogofile").into(), source_str, None)
91+
unwrap_or_emit_fatal(source_str_to_stream(
92+
&psess,
93+
PathBuf::from("bogofile").into(),
94+
source_str,
95+
None,
96+
))
8697
}
8798

8899
/// Parses a string, returns a crate.
@@ -1064,7 +1075,8 @@ fn parse_item_from_source_str(
10641075
source: String,
10651076
psess: &ParseSess,
10661077
) -> PResult<'_, Option<P<ast::Item>>> {
1067-
new_parser_from_source_str(psess, name, source).parse_item(ForceCollect::No)
1078+
unwrap_or_emit_fatal(new_parser_from_source_str(psess, name, source))
1079+
.parse_item(ForceCollect::No)
10681080
}
10691081

10701082
// Produces a `rustc_span::span`.
@@ -1345,7 +1357,7 @@ fn ttdelim_span() {
13451357
source: String,
13461358
psess: &ParseSess,
13471359
) -> PResult<'_, P<ast::Expr>> {
1348-
new_parser_from_source_str(psess, name, source).parse_expr()
1360+
unwrap_or_emit_fatal(new_parser_from_source_str(psess, name, source)).parse_expr()
13491361
}
13501362

13511363
create_default_session_globals_then(|| {

src/librustdoc/clean/render_macro_matchers.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ fn snippet_equal_to_token(tcx: TyCtxt<'_>, matcher: &TokenTree) -> Option<String
6565
let psess = ParseSess::new(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec());
6666
let file_name = source_map.span_to_filename(span);
6767
let mut parser =
68-
match rustc_parse::maybe_new_parser_from_source_str(&psess, file_name, snippet.clone()) {
68+
match rustc_parse::new_parser_from_source_str(&psess, file_name, snippet.clone()) {
6969
Ok(parser) => parser,
7070
Err(errs) => {
7171
errs.into_iter().for_each(|err| err.cancel());

src/librustdoc/doctest.rs

+11-12
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_interface::interface;
99
use rustc_middle::hir::map::Map;
1010
use rustc_middle::hir::nested_filter;
1111
use rustc_middle::ty::TyCtxt;
12-
use rustc_parse::maybe_new_parser_from_source_str;
12+
use rustc_parse::new_parser_from_source_str;
1313
use rustc_parse::parser::attr::InnerAttrPolicy;
1414
use rustc_resolve::rustdoc::span_of_fragments;
1515
use rustc_session::config::{self, CrateType, ErrorOutputType};
@@ -638,7 +638,7 @@ pub(crate) fn make_test(
638638
let mut found_extern_crate = crate_name.is_none();
639639
let mut found_macro = false;
640640

641-
let mut parser = match maybe_new_parser_from_source_str(&psess, filename, source) {
641+
let mut parser = match new_parser_from_source_str(&psess, filename, source) {
642642
Ok(p) => p,
643643
Err(errs) => {
644644
errs.into_iter().for_each(|err| err.cancel());
@@ -818,16 +818,15 @@ fn check_if_attr_is_complete(source: &str, edition: Edition) -> bool {
818818

819819
let dcx = DiagCtxt::new(Box::new(emitter)).disable_warnings();
820820
let psess = ParseSess::with_dcx(dcx, sm);
821-
let mut parser =
822-
match maybe_new_parser_from_source_str(&psess, filename, source.to_owned()) {
823-
Ok(p) => p,
824-
Err(errs) => {
825-
errs.into_iter().for_each(|err| err.cancel());
826-
// If there is an unclosed delimiter, an error will be returned by the
827-
// tokentrees.
828-
return false;
829-
}
830-
};
821+
let mut parser = match new_parser_from_source_str(&psess, filename, source.to_owned()) {
822+
Ok(p) => p,
823+
Err(errs) => {
824+
errs.into_iter().for_each(|err| err.cancel());
825+
// If there is an unclosed delimiter, an error will be returned by the
826+
// tokentrees.
827+
return false;
828+
}
829+
};
831830
// If a parsing error happened, it's very likely that the attribute is incomplete.
832831
if let Err(e) = parser.parse_attribute(InnerAttrPolicy::Permitted) {
833832
e.cancel();

0 commit comments

Comments
 (0)