about summary refs log tree commit diff
path: root/compiler/rustc_parse/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_parse/src')
-rw-r--r--compiler/rustc_parse/src/lexer/mod.rs4
-rw-r--r--compiler/rustc_parse/src/lexer/tokentrees.rs50
-rw-r--r--compiler/rustc_parse/src/lexer/unicode_chars.rs75
-rw-r--r--compiler/rustc_parse/src/lib.rs158
-rw-r--r--compiler/rustc_parse/src/parser/attr.rs2
-rw-r--r--compiler/rustc_parse/src/parser/tests.rs22
6 files changed, 134 insertions, 177 deletions
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index d3a6a033978..43f4963b27a 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -42,7 +42,7 @@ pub(crate) struct UnmatchedDelim {
     pub candidate_span: Option<Span>,
 }
 
-pub(crate) fn parse_token_trees<'psess, 'src>(
+pub(crate) fn lex_token_trees<'psess, 'src>(
     psess: &'psess ParseSess,
     mut src: &'src str,
     mut start_pos: BytePos,
@@ -66,7 +66,7 @@ pub(crate) fn parse_token_trees<'psess, 'src>(
         last_lifetime: None,
     };
     let (stream, res, unmatched_delims) =
-        tokentrees::TokenTreesReader::parse_all_token_trees(string_reader);
+        tokentrees::TokenTreesReader::lex_all_token_trees(string_reader);
     match res {
         Ok(()) if unmatched_delims.is_empty() => Ok(stream),
         _ => {
diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs
index eabe0226b2f..f7645446081 100644
--- a/compiler/rustc_parse/src/lexer/tokentrees.rs
+++ b/compiler/rustc_parse/src/lexer/tokentrees.rs
@@ -2,6 +2,7 @@ use super::diagnostics::report_suspicious_mismatch_block;
 use super::diagnostics::same_indentation_level;
 use super::diagnostics::TokenTreeDiagInfo;
 use super::{StringReader, UnmatchedDelim};
+use crate::Parser;
 use rustc_ast::token::{self, Delimiter, Token};
 use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
 use rustc_ast_pretty::pprust::token_to_string;
@@ -17,7 +18,7 @@ pub(super) struct TokenTreesReader<'psess, 'src> {
 }
 
 impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
-    pub(super) fn parse_all_token_trees(
+    pub(super) fn lex_all_token_trees(
         string_reader: StringReader<'psess, 'src>,
     ) -> (TokenStream, Result<(), Vec<PErr<'psess>>>, Vec<UnmatchedDelim>) {
         let mut tt_reader = TokenTreesReader {
@@ -25,14 +26,13 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
             token: Token::dummy(),
             diag_info: TokenTreeDiagInfo::default(),
         };
-        let (_open_spacing, stream, res) =
-            tt_reader.parse_token_trees(/* is_delimited */ false);
+        let (_open_spacing, stream, res) = tt_reader.lex_token_trees(/* is_delimited */ false);
         (stream, res, tt_reader.diag_info.unmatched_delims)
     }
 
-    // Parse a stream of tokens into a list of `TokenTree`s. The `Spacing` in
-    // the result is that of the opening delimiter.
-    fn parse_token_trees(
+    // Lex into a token stream. The `Spacing` in the result is that of the
+    // opening delimiter.
+    fn lex_token_trees(
         &mut self,
         is_delimited: bool,
     ) -> (Spacing, TokenStream, Result<(), Vec<PErr<'psess>>>) {
@@ -42,12 +42,10 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
         let mut buf = Vec::new();
         loop {
             match self.token.kind {
-                token::OpenDelim(delim) => {
-                    buf.push(match self.parse_token_tree_open_delim(delim) {
-                        Ok(val) => val,
-                        Err(errs) => return (open_spacing, TokenStream::new(buf), Err(errs)),
-                    })
-                }
+                token::OpenDelim(delim) => buf.push(match self.lex_token_tree_open_delim(delim) {
+                    Ok(val) => val,
+                    Err(errs) => return (open_spacing, TokenStream::new(buf), Err(errs)),
+                }),
                 token::CloseDelim(delim) => {
                     return (
                         open_spacing,
@@ -95,24 +93,24 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
         err
     }
 
-    fn parse_token_tree_open_delim(
+    fn lex_token_tree_open_delim(
         &mut self,
         open_delim: Delimiter,
     ) -> Result<TokenTree, Vec<PErr<'psess>>> {
-        // The span for beginning of the delimited section
+        // The span for beginning of the delimited section.
         let pre_span = self.token.span;
 
         self.diag_info.open_braces.push((open_delim, self.token.span));
 
-        // Parse the token trees within the delimiters.
+        // Lex the token trees within the delimiters.
         // We stop at any delimiter so we can try to recover if the user
         // uses an incorrect delimiter.
-        let (open_spacing, tts, res) = self.parse_token_trees(/* is_delimited */ true);
+        let (open_spacing, tts, res) = self.lex_token_trees(/* is_delimited */ true);
         if let Err(errs) = res {
             return Err(self.unclosed_delim_err(tts, errs));
         }
 
-        // Expand to cover the entire delimited token tree
+        // Expand to cover the entire delimited token tree.
         let delim_span = DelimSpan::from_pair(pre_span, self.token.span);
         let sm = self.string_reader.psess.source_map();
 
@@ -150,7 +148,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
                     self.diag_info.last_unclosed_found_span = Some(self.token.span);
                     // This is a conservative error: only report the last unclosed
                     // delimiter. The previous unclosed delimiters could actually be
-                    // closed! The parser just hasn't gotten to them yet.
+                    // closed! The lexer just hasn't gotten to them yet.
                     if let Some(&(_, sp)) = self.diag_info.open_braces.last() {
                         unclosed_delimiter = Some(sp);
                     };
@@ -234,11 +232,11 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
     ) -> Vec<PErr<'psess>> {
         // If there are unclosed delims, see if there are diff markers and if so, point them
         // out instead of complaining about the unclosed delims.
-        let mut parser = crate::stream_to_parser(self.string_reader.psess, tts, None);
+        let mut parser = Parser::new(self.string_reader.psess, tts, None);
         let mut diff_errs = vec![];
-        // Suggest removing a `{` we think appears in an `if`/`while` condition
-        // We want to suggest removing a `{` only if we think we're in an `if`/`while` condition, but
-        // we have no way of tracking this in the lexer itself, so we piggyback on the parser
+        // Suggest removing a `{` we think appears in an `if`/`while` condition.
+        // We want to suggest removing a `{` only if we think we're in an `if`/`while` condition,
+        // but we have no way of tracking this in the lexer itself, so we piggyback on the parser.
         let mut in_cond = false;
         while parser.token != token::Eof {
             if let Err(diff_err) = parser.err_vcs_conflict_marker() {
@@ -249,14 +247,15 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
                 parser.token.kind,
                 token::CloseDelim(Delimiter::Brace) | token::FatArrow
             ) {
-                // end of the `if`/`while` body, or the end of a `match` guard
+                // End of the `if`/`while` body, or the end of a `match` guard.
                 in_cond = false;
             } else if in_cond && parser.token == token::OpenDelim(Delimiter::Brace) {
                 // Store the `&&` and `let` to use their spans later when creating the diagnostic
                 let maybe_andand = parser.look_ahead(1, |t| t.clone());
                 let maybe_let = parser.look_ahead(2, |t| t.clone());
                 if maybe_andand == token::OpenDelim(Delimiter::Brace) {
-                    // This might be the beginning of the `if`/`while` body (i.e., the end of the condition)
+                    // This might be the beginning of the `if`/`while` body (i.e., the end of the
+                    // condition).
                     in_cond = false;
                 } else if maybe_andand == token::AndAnd && maybe_let.is_keyword(kw::Let) {
                     let mut err = parser.dcx().struct_span_err(
@@ -288,8 +287,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
     }
 
     fn close_delim_err(&mut self, delim: Delimiter) -> PErr<'psess> {
-        // An unexpected closing delimiter (i.e., there is no
-        // matching opening delimiter).
+        // An unexpected closing delimiter (i.e., there is no matching opening delimiter).
         let token_str = token_to_string(&self.token);
         let msg = format!("unexpected closing delimiter: `{token_str}`");
         let mut err = self.string_reader.psess.dcx.struct_span_err(self.token.span, msg);
diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs
index c9470151a7b..8eb299108d1 100644
--- a/compiler/rustc_parse/src/lexer/unicode_chars.rs
+++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs
@@ -129,42 +129,42 @@ pub(super) const UNICODE_ARRAY: &[(char, &str, &str)] = &[
     ('。', "Ideographic Full Stop", "."),
     ('︒', "Presentation Form For Vertical Ideographic Full Stop", "."),
 
-    ('՝', "Armenian Comma", "\'"),
-    (''', "Fullwidth Apostrophe", "\'"),
-    ('‘', "Left Single Quotation Mark", "\'"),
-    ('’', "Right Single Quotation Mark", "\'"),
-    ('‛', "Single High-Reversed-9 Quotation Mark", "\'"),
-    ('′', "Prime", "\'"),
-    ('‵', "Reversed Prime", "\'"),
-    ('՚', "Armenian Apostrophe", "\'"),
-    ('׳', "Hebrew Punctuation Geresh", "\'"),
-    ('`', "Grave Accent", "\'"),
-    ('`', "Greek Varia", "\'"),
-    ('`', "Fullwidth Grave Accent", "\'"),
-    ('´', "Acute Accent", "\'"),
-    ('΄', "Greek Tonos", "\'"),
-    ('´', "Greek Oxia", "\'"),
-    ('᾽', "Greek Koronis", "\'"),
-    ('᾿', "Greek Psili", "\'"),
-    ('῾', "Greek Dasia", "\'"),
-    ('ʹ', "Modifier Letter Prime", "\'"),
-    ('ʹ', "Greek Numeral Sign", "\'"),
-    ('ˈ', "Modifier Letter Vertical Line", "\'"),
-    ('ˊ', "Modifier Letter Acute Accent", "\'"),
-    ('ˋ', "Modifier Letter Grave Accent", "\'"),
-    ('˴', "Modifier Letter Middle Grave Accent", "\'"),
-    ('ʻ', "Modifier Letter Turned Comma", "\'"),
-    ('ʽ', "Modifier Letter Reversed Comma", "\'"),
-    ('ʼ', "Modifier Letter Apostrophe", "\'"),
-    ('ʾ', "Modifier Letter Right Half Ring", "\'"),
-    ('ꞌ', "Latin Small Letter Saltillo", "\'"),
-    ('י', "Hebrew Letter Yod", "\'"),
-    ('ߴ', "Nko High Tone Apostrophe", "\'"),
-    ('ߵ', "Nko Low Tone Apostrophe", "\'"),
-    ('ᑊ', "Canadian Syllabics West-Cree P", "\'"),
-    ('ᛌ', "Runic Letter Short-Twig-Sol S", "\'"),
-    ('𖽑', "Miao Sign Aspiration", "\'"),
-    ('𖽒', "Miao Sign Reformed Voicing", "\'"),
+    ('՝', "Armenian Comma", "'"),
+    (''', "Fullwidth Apostrophe", "'"),
+    ('‘', "Left Single Quotation Mark", "'"),
+    ('’', "Right Single Quotation Mark", "'"),
+    ('‛', "Single High-Reversed-9 Quotation Mark", "'"),
+    ('′', "Prime", "'"),
+    ('‵', "Reversed Prime", "'"),
+    ('՚', "Armenian Apostrophe", "'"),
+    ('׳', "Hebrew Punctuation Geresh", "'"),
+    ('`', "Grave Accent", "'"),
+    ('`', "Greek Varia", "'"),
+    ('`', "Fullwidth Grave Accent", "'"),
+    ('´', "Acute Accent", "'"),
+    ('΄', "Greek Tonos", "'"),
+    ('´', "Greek Oxia", "'"),
+    ('᾽', "Greek Koronis", "'"),
+    ('᾿', "Greek Psili", "'"),
+    ('῾', "Greek Dasia", "'"),
+    ('ʹ', "Modifier Letter Prime", "'"),
+    ('ʹ', "Greek Numeral Sign", "'"),
+    ('ˈ', "Modifier Letter Vertical Line", "'"),
+    ('ˊ', "Modifier Letter Acute Accent", "'"),
+    ('ˋ', "Modifier Letter Grave Accent", "'"),
+    ('˴', "Modifier Letter Middle Grave Accent", "'"),
+    ('ʻ', "Modifier Letter Turned Comma", "'"),
+    ('ʽ', "Modifier Letter Reversed Comma", "'"),
+    ('ʼ', "Modifier Letter Apostrophe", "'"),
+    ('ʾ', "Modifier Letter Right Half Ring", "'"),
+    ('ꞌ', "Latin Small Letter Saltillo", "'"),
+    ('י', "Hebrew Letter Yod", "'"),
+    ('ߴ', "Nko High Tone Apostrophe", "'"),
+    ('ߵ', "Nko Low Tone Apostrophe", "'"),
+    ('ᑊ', "Canadian Syllabics West-Cree P", "'"),
+    ('ᛌ', "Runic Letter Short-Twig-Sol S", "'"),
+    ('𖽑', "Miao Sign Aspiration", "'"),
+    ('𖽒', "Miao Sign Reformed Voicing", "'"),
 
     ('᳓', "Vedic Sign Nihshvasa", "\""),
     ('"', "Fullwidth Quotation Mark", "\""),
@@ -298,6 +298,7 @@ pub(super) const UNICODE_ARRAY: &[(char, &str, &str)] = &[
     ('〉', "Right Angle Bracket", ">"),
     ('》', "Right Double Angle Bracket", ">"),
     ('>', "Fullwidth Greater-Than Sign", ">"),
+
     ('⩵', "Two Consecutive Equals Signs", "==")
 ];
 
@@ -332,7 +333,7 @@ const ASCII_ARRAY: &[(&str, &str, Option<token::TokenKind>)] = &[
     (">", "Greater-Than Sign", Some(token::Gt)),
     // FIXME: Literals are already lexed by this point, so we can't recover gracefully just by
     // spitting the correct token out.
-    ("\'", "Single Quote", None),
+    ("'", "Single Quote", None),
     ("\"", "Quotation Mark", None),
 ];
 
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index 322739be3fb..b316327a262 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -34,84 +34,41 @@ mod errors;
 
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
 
-// A bunch of utility functions of the form `parse_<thing>_from_<source>`
-// where <thing> includes crate, expr, item, stmt, tts, and one that
-// uses a HOF to parse anything, and <source> includes file and
-// `source_str`.
-
-/// A variant of 'panictry!' that works on a `Vec<Diag>` instead of a single `Diag`.
-macro_rules! panictry_buffer {
-    ($e:expr) => {{
-        use std::result::Result::{Err, Ok};
-        match $e {
-            Ok(e) => e,
-            Err(errs) => {
-                for e in errs {
-                    e.emit();
-                }
-                FatalError.raise()
+// Unwrap the result if `Ok`, otherwise emit the diagnostics and abort.
+pub fn unwrap_or_emit_fatal<T>(expr: Result<T, Vec<Diag<'_>>>) -> T {
+    match expr {
+        Ok(expr) => expr,
+        Err(errs) => {
+            for err in errs {
+                err.emit();
             }
+            FatalError.raise()
         }
-    }};
-}
-
-pub fn parse_crate_from_file<'a>(input: &Path, psess: &'a ParseSess) -> PResult<'a, ast::Crate> {
-    let mut parser = new_parser_from_file(psess, input, None);
-    parser.parse_crate_mod()
-}
-
-pub fn parse_crate_attrs_from_file<'a>(
-    input: &Path,
-    psess: &'a ParseSess,
-) -> PResult<'a, ast::AttrVec> {
-    let mut parser = new_parser_from_file(psess, input, None);
-    parser.parse_inner_attributes()
-}
-
-pub fn parse_crate_from_source_str(
-    name: FileName,
-    source: String,
-    psess: &ParseSess,
-) -> PResult<'_, ast::Crate> {
-    new_parser_from_source_str(psess, name, source).parse_crate_mod()
-}
-
-pub fn parse_crate_attrs_from_source_str(
-    name: FileName,
-    source: String,
-    psess: &ParseSess,
-) -> PResult<'_, ast::AttrVec> {
-    new_parser_from_source_str(psess, name, source).parse_inner_attributes()
-}
-
-pub fn parse_stream_from_source_str(
-    name: FileName,
-    source: String,
-    psess: &ParseSess,
-    override_span: Option<Span>,
-) -> TokenStream {
-    source_file_to_stream(psess, psess.source_map().new_source_file(name, source), override_span)
-}
-
-/// Creates a new parser from a source string.
-pub fn new_parser_from_source_str(psess: &ParseSess, name: FileName, source: String) -> Parser<'_> {
-    panictry_buffer!(maybe_new_parser_from_source_str(psess, name, source))
+    }
 }
 
-/// Creates a new parser from a source string. Returns any buffered errors from lexing the initial
-/// token stream; these must be consumed via `emit`, `cancel`, etc., otherwise a panic will occur
-/// when they are dropped.
-pub fn maybe_new_parser_from_source_str(
+/// Creates a new parser from a source string. On failure, the errors must be consumed via
+/// `unwrap_or_emit_fatal`, `emit`, `cancel`, etc., otherwise a panic will occur when they are
+/// dropped.
+pub fn new_parser_from_source_str(
     psess: &ParseSess,
     name: FileName,
     source: String,
 ) -> Result<Parser<'_>, Vec<Diag<'_>>> {
-    maybe_source_file_to_parser(psess, psess.source_map().new_source_file(name, source))
+    let source_file = psess.source_map().new_source_file(name, source);
+    new_parser_from_source_file(psess, source_file)
 }
 
-/// Creates a new parser, aborting if the file doesn't exist. If a span is given, that is used on
-/// an error as the source of the problem.
-pub fn new_parser_from_file<'a>(psess: &'a ParseSess, path: &Path, sp: Option<Span>) -> Parser<'a> {
+/// Creates a new parser from a filename. On failure, the errors must be consumed via
+/// `unwrap_or_emit_fatal`, `emit`, `cancel`, etc., otherwise a panic will occur when they are
+/// dropped.
+///
+/// If a span is given, that is used on an error as the source of the problem.
+pub fn new_parser_from_file<'a>(
+    psess: &'a ParseSess,
+    path: &Path,
+    sp: Option<Span>,
+) -> Result<Parser<'a>, Vec<Diag<'a>>> {
     let source_file = psess.source_map().load_file(path).unwrap_or_else(|e| {
         let msg = format!("couldn't read {}: {}", path.display(), e);
         let mut err = psess.dcx.struct_fatal(msg);
@@ -120,40 +77,37 @@ pub fn new_parser_from_file<'a>(psess: &'a ParseSess, path: &Path, sp: Option<Sp
         }
         err.emit();
     });
-
-    panictry_buffer!(maybe_source_file_to_parser(psess, source_file))
+    new_parser_from_source_file(psess, source_file)
 }
 
 /// Given a session and a `source_file`, return a parser. Returns any buffered errors from lexing
 /// the initial token stream.
-fn maybe_source_file_to_parser(
+fn new_parser_from_source_file(
     psess: &ParseSess,
     source_file: Lrc<SourceFile>,
 ) -> Result<Parser<'_>, Vec<Diag<'_>>> {
     let end_pos = source_file.end_position();
-    let stream = maybe_file_to_stream(psess, source_file, None)?;
-    let mut parser = stream_to_parser(psess, stream, None);
+    let stream = source_file_to_stream(psess, source_file, None)?;
+    let mut parser = Parser::new(psess, stream, None);
     if parser.token == token::Eof {
         parser.token.span = Span::new(end_pos, end_pos, parser.token.span.ctxt(), None);
     }
-
     Ok(parser)
 }
 
-// Base abstractions
-
-/// Given a `source_file`, produces a sequence of token trees.
-pub fn source_file_to_stream(
+pub fn source_str_to_stream(
     psess: &ParseSess,
-    source_file: Lrc<SourceFile>,
+    name: FileName,
+    source: String,
     override_span: Option<Span>,
-) -> TokenStream {
-    panictry_buffer!(maybe_file_to_stream(psess, source_file, override_span))
+) -> Result<TokenStream, Vec<Diag<'_>>> {
+    let source_file = psess.source_map().new_source_file(name, source);
+    source_file_to_stream(psess, source_file, override_span)
 }
 
 /// Given a source file, produces a sequence of token trees. Returns any buffered errors from
 /// parsing the token stream.
-fn maybe_file_to_stream<'psess>(
+fn source_file_to_stream<'psess>(
     psess: &'psess ParseSess,
     source_file: Lrc<SourceFile>,
     override_span: Option<Span>,
@@ -165,16 +119,7 @@ fn maybe_file_to_stream<'psess>(
         ));
     });
 
-    lexer::parse_token_trees(psess, src.as_str(), source_file.start_pos, override_span)
-}
-
-/// Given a stream and the `ParseSess`, produces a parser.
-pub fn stream_to_parser<'a>(
-    psess: &'a ParseSess,
-    stream: TokenStream,
-    subparser_name: Option<&'static str>,
-) -> Parser<'a> {
-    Parser::new(psess, stream, subparser_name)
+    lexer::lex_token_trees(psess, src.as_str(), source_file.start_pos, override_span)
 }
 
 /// Runs the given subparser `f` on the tokens of the given `attr`'s item.
@@ -195,19 +140,28 @@ pub fn parse_in<'a, T>(
 pub fn fake_token_stream_for_item(psess: &ParseSess, item: &ast::Item) -> TokenStream {
     let source = pprust::item_to_string(item);
     let filename = FileName::macro_expansion_source_code(&source);
-    parse_stream_from_source_str(filename, source, psess, Some(item.span))
+    unwrap_or_emit_fatal(source_str_to_stream(psess, filename, source, Some(item.span)))
 }
 
 pub fn fake_token_stream_for_crate(psess: &ParseSess, krate: &ast::Crate) -> TokenStream {
     let source = pprust::crate_to_string_for_macros(krate);
     let filename = FileName::macro_expansion_source_code(&source);
-    parse_stream_from_source_str(filename, source, psess, Some(krate.spans.inner_span))
+    unwrap_or_emit_fatal(source_str_to_stream(
+        psess,
+        filename,
+        source,
+        Some(krate.spans.inner_span),
+    ))
 }
 
 pub fn parse_cfg_attr(
     attr: &Attribute,
     psess: &ParseSess,
 ) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> {
+    const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]";
+    const CFG_ATTR_NOTE_REF: &str = "for more information, visit \
+        <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>";
+
     match attr.get_normal_item().args {
         ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, ref tokens })
             if !tokens.is_empty() =>
@@ -222,16 +176,12 @@ pub fn parse_cfg_attr(
                 }
             }
         }
-        _ => error_malformed_cfg_attr_missing(attr.span, psess),
+        _ => {
+            psess.dcx.emit_err(errors::MalformedCfgAttr {
+                span: attr.span,
+                sugg: CFG_ATTR_GRAMMAR_HELP,
+            });
+        }
     }
     None
 }
-
-const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]";
-const CFG_ATTR_NOTE_REF: &str = "for more information, visit \
-    <https://doc.rust-lang.org/reference/conditional-compilation.html\
-    #the-cfg_attr-attribute>";
-
-fn error_malformed_cfg_attr_missing(span: Span, psess: &ParseSess) {
-    psess.dcx.emit_err(errors::MalformedCfgAttr { span, sugg: CFG_ATTR_GRAMMAR_HELP });
-}
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index a57eb70c705..4acc610d8c4 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -265,7 +265,7 @@ impl<'a> Parser<'a> {
     /// terminated by a semicolon.
     ///
     /// Matches `inner_attrs*`.
-    pub(crate) fn parse_inner_attributes(&mut self) -> PResult<'a, ast::AttrVec> {
+    pub fn parse_inner_attributes(&mut self) -> PResult<'a, ast::AttrVec> {
         let mut attrs = ast::AttrVec::new();
         loop {
             let start_pos: u32 = self.num_bump_calls.try_into().unwrap();
diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs
index a31e350541a..79a6cf1b541 100644
--- a/compiler/rustc_parse/src/parser/tests.rs
+++ b/compiler/rustc_parse/src/parser/tests.rs
@@ -1,5 +1,7 @@
 use crate::parser::ForceCollect;
-use crate::{new_parser_from_source_str, parser::Parser, source_file_to_stream};
+use crate::{
+    new_parser_from_source_str, parser::Parser, source_str_to_stream, unwrap_or_emit_fatal,
+};
 use ast::token::IdentIsRaw;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Delimiter, Token};
@@ -29,7 +31,11 @@ fn psess() -> ParseSess {
 
 /// Map string to parser (via tts).
 fn string_to_parser(psess: &ParseSess, source_str: String) -> Parser<'_> {
-    new_parser_from_source_str(psess, PathBuf::from("bogofile").into(), source_str)
+    unwrap_or_emit_fatal(new_parser_from_source_str(
+        psess,
+        PathBuf::from("bogofile").into(),
+        source_str,
+    ))
 }
 
 fn create_test_handler() -> (DiagCtxt, Lrc<SourceMap>, Arc<Mutex<Vec<u8>>>) {
@@ -82,11 +88,12 @@ where
 /// Maps a string to tts, using a made-up filename.
 pub(crate) fn string_to_stream(source_str: String) -> TokenStream {
     let psess = psess();
-    source_file_to_stream(
+    unwrap_or_emit_fatal(source_str_to_stream(
         &psess,
-        psess.source_map().new_source_file(PathBuf::from("bogofile").into(), source_str),
+        PathBuf::from("bogofile").into(),
+        source_str,
         None,
-    )
+    ))
 }
 
 /// Parses a string, returns a crate.
@@ -1068,7 +1075,8 @@ fn parse_item_from_source_str(
     source: String,
     psess: &ParseSess,
 ) -> PResult<'_, Option<P<ast::Item>>> {
-    new_parser_from_source_str(psess, name, source).parse_item(ForceCollect::No)
+    unwrap_or_emit_fatal(new_parser_from_source_str(psess, name, source))
+        .parse_item(ForceCollect::No)
 }
 
 // Produces a `rustc_span::span`.
@@ -1349,7 +1357,7 @@ fn ttdelim_span() {
         source: String,
         psess: &ParseSess,
     ) -> PResult<'_, P<ast::Expr>> {
-        new_parser_from_source_str(psess, name, source).parse_expr()
+        unwrap_or_emit_fatal(new_parser_from_source_str(psess, name, source)).parse_expr()
     }
 
     create_default_session_globals_then(|| {