Skip to content

Commit d63734f

Browse files
committed
Emit errors during parsing when calling interface::parse_cfg/parse_check_cfg
1 parent fe4cabf commit d63734f

File tree

42 files changed

+190
-97
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+190
-97
lines changed

compiler/rustc_errors/src/emitter.rs

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -534,30 +534,28 @@ impl Emitter for HumanEmitter {
534534
}
535535
}
536536

537-
/// An emitter that does nothing when emitting a non-fatal diagnostic.
538-
/// Fatal diagnostics are forwarded to `fatal_emitter` to avoid silent
537+
/// An emitter that does nothing when emitting a non-error diagnostic.
538+
/// Error diagnostics are forwarded to `error_emitter` to avoid silent
539539
/// failures of rustc, as witnessed e.g. in issue #89358.
540-
pub struct FatalOnlyEmitter {
541-
pub fatal_emitter: Box<dyn Emitter + DynSend>,
542-
pub fatal_note: Option<String>,
540+
pub struct ErrorOnlyEmitter {
541+
pub error_emitter: Box<dyn Emitter + DynSend>,
542+
pub error_note: String,
543543
}
544544

545-
impl Emitter for FatalOnlyEmitter {
545+
impl Emitter for ErrorOnlyEmitter {
546546
fn source_map(&self) -> Option<&SourceMap> {
547547
None
548548
}
549549

550550
fn emit_diagnostic(&mut self, mut diag: DiagInner, registry: &Registry) {
551-
if diag.level == Level::Fatal {
552-
if let Some(fatal_note) = &self.fatal_note {
553-
diag.sub(Level::Note, fatal_note.clone(), MultiSpan::new());
554-
}
555-
self.fatal_emitter.emit_diagnostic(diag, registry);
551+
if diag.is_error() {
552+
diag.sub(Level::Note, self.error_note.clone(), MultiSpan::new());
553+
self.error_emitter.emit_diagnostic(diag, registry);
556554
}
557555
}
558556

559557
fn translator(&self) -> &Translator {
560-
self.fatal_emitter.translator()
558+
self.error_emitter.translator()
561559
}
562560
}
563561

compiler/rustc_interface/src/interface.rs

Lines changed: 37 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use rustc_middle::ty::CurrentGcx;
1515
use rustc_middle::util::Providers;
1616
use rustc_parse::lexer::StripTokens;
1717
use rustc_parse::new_parser_from_source_str;
18+
use rustc_parse::parser::Recovery;
1819
use rustc_parse::parser::attr::AllowLeadingUnsafe;
1920
use rustc_query_impl::QueryCtxt;
2021
use rustc_query_system::query::print_query_stack;
@@ -52,7 +53,7 @@ pub struct Compiler {
5253
pub(crate) fn parse_cfg(dcx: DiagCtxtHandle<'_>, cfgs: Vec<String>) -> Cfg {
5354
cfgs.into_iter()
5455
.map(|s| {
55-
let psess = ParseSess::with_fatal_emitter(
56+
let psess = ParseSess::with_error_emitter(
5657
vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE],
5758
format!("this error occurred on the command line: `--cfg={s}`"),
5859
);
@@ -63,47 +64,46 @@ pub(crate) fn parse_cfg(dcx: DiagCtxtHandle<'_>, cfgs: Vec<String>) -> Cfg {
6364
#[allow(rustc::untranslatable_diagnostic)]
6465
#[allow(rustc::diagnostic_outside_of_impl)]
6566
dcx.fatal(format!(
66-
concat!("invalid `--cfg` argument: `{}` ({})"),
67+
"invalid `--cfg` argument: `{}` ({})",
6768
s, $reason,
6869
));
6970
};
7071
}
7172

7273
match new_parser_from_source_str(&psess, filename, s.to_string(), StripTokens::Nothing)
7374
{
74-
Ok(mut parser) => match parser.parse_meta_item(AllowLeadingUnsafe::No) {
75-
Ok(meta_item) if parser.token == token::Eof => {
76-
if meta_item.path.segments.len() != 1 {
77-
error!("argument key must be an identifier");
78-
}
79-
match &meta_item.kind {
80-
MetaItemKind::List(..) => {}
81-
MetaItemKind::NameValue(lit) if !lit.kind.is_str() => {
82-
error!("argument value must be a string");
75+
Ok(mut parser) => {
76+
parser = parser.recovery(Recovery::Forbidden);
77+
match parser.parse_meta_item(AllowLeadingUnsafe::No) {
78+
Ok(meta_item) if parser.token == token::Eof => {
79+
if meta_item.path.segments.len() != 1 {
80+
error!("argument key must be an identifier");
8381
}
84-
MetaItemKind::NameValue(..) | MetaItemKind::Word => {
85-
let ident = meta_item.ident().expect("multi-segment cfg key");
82+
match &meta_item.kind {
83+
MetaItemKind::List(..) => {}
84+
MetaItemKind::NameValue(lit) if !lit.kind.is_str() => {
85+
error!("argument value must be a string");
86+
}
87+
MetaItemKind::NameValue(..) | MetaItemKind::Word => {
88+
let ident = meta_item.ident().expect("multi-segment cfg key");
8689

87-
if ident.is_reserved() {
8890
if !ident.name.can_be_raw() {
89-
if s.trim().starts_with(&format!("r#{}", ident.as_str())) {
90-
error!(format!("argument key must be an identifier, but `{}` cannot be a raw identifier", ident.name));
91-
} else {
92-
error!(format!("argument key must be an identifier but found keyword `{}`", ident.name));
93-
}
94-
} else if !s.trim().starts_with(&ident.to_string()) {
95-
error!(format!("argument key must be an identifier but found keyword `{}`, escape it using `{}`", ident.as_str(), ident));
91+
error!(format!("argument key must be an identifier, but `{}` cannot be a raw identifier", ident.name));
9692
}
97-
}
9893

99-
return (ident.name, meta_item.value_str());
94+
return (ident.name, meta_item.value_str());
95+
}
10096
}
10197
}
98+
Ok(..) => {}
99+
Err(err) => {
100+
err.emit();
101+
},
102102
}
103-
Ok(..) => {}
104-
Err(err) => err.cancel(),
105103
},
106-
Err(errs) => errs.into_iter().for_each(|err| err.cancel()),
104+
Err(errs) => errs.into_iter().for_each(|err| {
105+
err.emit();
106+
}),
107107
};
108108

109109
// If the user tried to use a key="value" flag, but is missing the quotes, provide
@@ -129,7 +129,7 @@ pub(crate) fn parse_check_cfg(dcx: DiagCtxtHandle<'_>, specs: Vec<String>) -> Ch
129129
let mut check_cfg = CheckCfg { exhaustive_names, exhaustive_values, ..CheckCfg::default() };
130130

131131
for s in specs {
132-
let psess = ParseSess::with_fatal_emitter(
132+
let psess = ParseSess::with_error_emitter(
133133
vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE],
134134
format!("this error occurred on the command line: `--check-cfg={s}`"),
135135
);
@@ -186,16 +186,19 @@ pub(crate) fn parse_check_cfg(dcx: DiagCtxtHandle<'_>, specs: Vec<String>) -> Ch
186186
{
187187
Ok(parser) => parser,
188188
Err(errs) => {
189-
errs.into_iter().for_each(|err| err.cancel());
189+
errs.into_iter().for_each(|err| {
190+
err.emit();
191+
});
190192
expected_error();
191193
}
192194
};
195+
parser = parser.recovery(Recovery::Forbidden);
193196

194197
let meta_item = match parser.parse_meta_item(AllowLeadingUnsafe::No) {
195198
Ok(meta_item) if parser.token == token::Eof => meta_item,
196199
Ok(..) => expected_error(),
197200
Err(err) => {
198-
err.cancel();
201+
err.emit();
199202
expected_error();
200203
}
201204
};
@@ -215,13 +218,6 @@ pub(crate) fn parse_check_cfg(dcx: DiagCtxtHandle<'_>, specs: Vec<String>) -> Ch
215218
let mut values_specified = false;
216219
let mut values_any_specified = false;
217220

218-
let arg_strs = s
219-
.trim()
220-
.trim_start_matches("cfg(")
221-
.trim_end_matches(')')
222-
.split(',')
223-
.collect::<Vec<_>>();
224-
225221
for arg in args {
226222
if arg.is_word()
227223
&& let Some(ident) = arg.ident()
@@ -230,26 +226,11 @@ pub(crate) fn parse_check_cfg(dcx: DiagCtxtHandle<'_>, specs: Vec<String>) -> Ch
230226
error!("`cfg()` names cannot be after values");
231227
}
232228

233-
if ident.is_reserved() {
234-
if !ident.name.can_be_raw() {
235-
if arg_strs[names.len()].starts_with(&format!("r#{}", ident.as_str())) {
236-
error!(format!(
237-
"argument key must be an identifier, but `{}` cannot be a raw identifier",
238-
ident.name
239-
));
240-
} else {
241-
error!(format!(
242-
"argument key must be an identifier but found keyword `{}`",
243-
ident.name
244-
));
245-
}
246-
} else if !arg_strs[names.len()].starts_with(&ident.to_string()) {
247-
error!(format!(
248-
"argument key must be an identifier but found keyword `{}`, escape it using `{}`",
249-
ident.as_str(),
250-
ident
251-
));
252-
}
229+
if !ident.name.can_be_raw() {
230+
error!(format!(
231+
"argument key must be an identifier, but `{}` cannot be a raw identifier",
232+
ident.name
233+
));
253234
}
254235

255236
names.push(ident);
@@ -258,11 +239,6 @@ pub(crate) fn parse_check_cfg(dcx: DiagCtxtHandle<'_>, specs: Vec<String>) -> Ch
258239
error!("`cfg()` names cannot be after values");
259240
}
260241

261-
let lit_str = arg_strs[names.len()];
262-
if !lit_str.starts_with("r#") {
263-
error!(in arg, format!("`cfg()` names must be identifiers but found keyword `{lit_str}`, escape it using `r#{lit_str}`"));
264-
}
265-
266242
names.push(rustc_span::Ident::new(
267243
if boolean { rustc_span::kw::True } else { rustc_span::kw::False },
268244
arg.span(),

compiler/rustc_parse/src/parser/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@ impl<'a> Parser<'a> {
466466

467467
// Public for rustfmt usage.
468468
pub fn parse_ident(&mut self) -> PResult<'a, Ident> {
469-
self.parse_ident_common(true)
469+
self.parse_ident_common(self.may_recover())
470470
}
471471

472472
fn parse_ident_common(&mut self, recover: bool) -> PResult<'a, Ident> {

compiler/rustc_session/src/parse.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_ast::attr::AttrIdGenerator;
88
use rustc_ast::node_id::NodeId;
99
use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
1010
use rustc_data_structures::sync::{AppendOnlyVec, Lock};
11-
use rustc_errors::emitter::{FatalOnlyEmitter, HumanEmitter, stderr_destination};
11+
use rustc_errors::emitter::{ErrorOnlyEmitter, HumanEmitter, stderr_destination};
1212
use rustc_errors::translation::Translator;
1313
use rustc_errors::{
1414
BufferedEarlyLint, ColorConfig, DecorateDiagCompat, Diag, DiagCtxt, DiagCtxtHandle,
@@ -315,16 +315,13 @@ impl ParseSess {
315315
}
316316
}
317317

318-
pub fn with_fatal_emitter(locale_resources: Vec<&'static str>, fatal_note: String) -> Self {
318+
pub fn with_error_emitter(locale_resources: Vec<&'static str>, error_note: String) -> Self {
319319
let translator = Translator::with_fallback_bundle(locale_resources, false);
320320
let sm = Arc::new(SourceMap::new(FilePathMapping::empty()));
321-
let fatal_emitter =
321+
let emitter =
322322
Box::new(HumanEmitter::new(stderr_destination(ColorConfig::Auto), translator));
323-
let dcx = DiagCtxt::new(Box::new(FatalOnlyEmitter {
324-
fatal_emitter,
325-
fatal_note: Some(fatal_note),
326-
}))
327-
.disable_warnings();
323+
let dcx = DiagCtxt::new(Box::new(ErrorOnlyEmitter { error_emitter: emitter, error_note }))
324+
.disable_warnings();
328325
ParseSess::with_dcx(dcx, sm)
329326
}
330327

tests/run-make/multiline-args-value/cfg-frontmatter.stderr

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
error: expected identifier, found `-`
2+
|
3+
= note: this error occurred on the command line: `--cfg=---
4+
---
5+
key`
6+
17
error: invalid `--cfg` argument: `---
28
---
39
key` (expected `key` or `key="value"`)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
error: expected identifier, found `#`
2+
|
3+
= note: this error occurred on the command line: `--cfg=#!/usr/bin/shebang
4+
key`
5+
16
error: invalid `--cfg` argument: `#!/usr/bin/shebang
27
key` (expected `key` or `key="value"`)
38

tests/run-make/multiline-args-value/check-cfg-frontmatter.stderr

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
error: expected identifier, found `-`
2+
|
3+
= note: this error occurred on the command line: `--check-cfg=---
4+
---
5+
cfg(key)`
6+
17
error: invalid `--check-cfg` argument: `---
28
---
39
cfg(key)`

tests/run-make/multiline-args-value/check-cfg-shebang.stderr

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
error: expected identifier, found `#`
2+
|
3+
= note: this error occurred on the command line: `--check-cfg=#!/usr/bin/shebang
4+
cfg(key)`
5+
16
error: invalid `--check-cfg` argument: `#!/usr/bin/shebang
27
cfg(key)`
38
|
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
error: invalid `--cfg` argument: `crate` (argument key must be an identifier but found keyword `crate`)
1+
error: invalid `--cfg` argument: `crate` (argument key must be an identifier, but `crate` cannot be a raw identifier)
22

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
1-
error: invalid `--cfg` argument: `priv` (argument key must be an identifier but found keyword `priv`, escape it using `r#priv`)
1+
error: expected identifier, found reserved keyword `priv`
2+
|
3+
= note: this error occurred on the command line: `--cfg=priv`
4+
5+
error: invalid `--cfg` argument: `priv` (expected `key` or `key="value"`)
26

0 commit comments

Comments
 (0)