Skip to content

Commit 4e55a50

Browse files
Auto merge of #146978 - mu001999-contrib:fix/path-kw-as-cfg-pred, r=<try>
Emit error when using path-segment keyword as cfg pred
2 parents 4068baf + 65b32a4 commit 4e55a50

File tree

52 files changed

+947
-100
lines changed

Some content is hidden

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

52 files changed

+947
-100
lines changed

compiler/rustc_attr_parsing/src/attributes/cfg.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,8 @@ pub(crate) fn parse_cfg_entry<S: Stage>(
8383
}
8484
},
8585
a @ (ArgParser::NoArgs | ArgParser::NameValue(_)) => {
86-
let Some(name) = meta.path().word_sym() else {
86+
let Some(name) = meta.path().word_sym().filter(|s| !s.is_path_segment_keyword())
87+
else {
8788
cx.expected_identifier(meta.path().span());
8889
return None;
8990
};
@@ -160,7 +161,7 @@ fn parse_cfg_entry_target<S: Stage>(
160161
};
161162

162163
// Then, parse it as a name-value item
163-
let Some(name) = sub_item.path().word_sym() else {
164+
let Some(name) = sub_item.path().word_sym().filter(|s| !s.is_path_segment_keyword()) else {
164165
cx.expected_identifier(sub_item.path().span());
165166
return None;
166167
};

compiler/rustc_attr_parsing/src/attributes/cfg_old.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,10 @@ pub fn eval_condition(
220220
}
221221
}
222222
}
223-
MetaItemKind::Word | MetaItemKind::NameValue(..) if cfg.path.segments.len() != 1 => {
223+
MetaItemKind::Word | MetaItemKind::NameValue(..)
224+
if cfg.path.segments.len() != 1
225+
|| cfg.path.segments[0].ident.is_path_segment_keyword() =>
226+
{
224227
dcx.emit_err(session_diagnostics::CfgPredicateIdentifier { span: cfg.path.span });
225228
true
226229
}

compiler/rustc_errors/src/emitter.rs

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -534,30 +534,24 @@ 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
539-
/// 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>,
537+
/// An emitter that adds a note to each diagnostic.
538+
pub struct EmitterWithNote {
539+
pub emitter: Box<dyn Emitter + DynSend>,
540+
pub note: String,
543541
}
544542

545-
impl Emitter for FatalOnlyEmitter {
543+
impl Emitter for EmitterWithNote {
546544
fn source_map(&self) -> Option<&SourceMap> {
547545
None
548546
}
549547

550548
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);
556-
}
549+
diag.sub(Level::Note, self.note.clone(), MultiSpan::new());
550+
self.emitter.emit_diagnostic(diag, registry);
557551
}
558552

559553
fn translator(&self) -> &Translator {
560-
self.fatal_emitter.translator()
554+
self.emitter.translator()
561555
}
562556
}
563557

compiler/rustc_interface/src/interface.rs

Lines changed: 47 additions & 27 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,46 +53,57 @@ 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::emitter_with_note(
5657
vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE],
57-
format!("this error occurred on the command line: `--cfg={s}`"),
58+
format!("this occurred on the command line: `--cfg={s}`"),
5859
);
5960
let filename = FileName::cfg_spec_source_code(&s);
6061

6162
macro_rules! error {
6263
($reason: expr) => {
6364
#[allow(rustc::untranslatable_diagnostic)]
6465
#[allow(rustc::diagnostic_outside_of_impl)]
65-
dcx.fatal(format!(
66-
concat!("invalid `--cfg` argument: `{}` (", $reason, ")"),
67-
s
68-
));
66+
dcx.fatal(format!("invalid `--cfg` argument: `{}` ({})", s, $reason,));
6967
};
7068
}
7169

7270
match new_parser_from_source_str(&psess, filename, s.to_string(), StripTokens::Nothing)
7371
{
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");
72+
Ok(mut parser) => {
73+
parser = parser.recovery(Recovery::Forbidden);
74+
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");
8378
}
84-
MetaItemKind::NameValue(..) | MetaItemKind::Word => {
85-
let ident = meta_item.ident().expect("multi-segment cfg key");
86-
return (ident.name, meta_item.value_str());
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");
83+
}
84+
MetaItemKind::NameValue(..) | MetaItemKind::Word => {
85+
let ident = meta_item.ident().expect("multi-segment cfg key");
86+
87+
if !ident.name.can_be_raw() {
88+
error!(
89+
"malformed `cfg` input, expected a valid identifier"
90+
);
91+
}
92+
93+
return (ident.name, meta_item.value_str());
94+
}
8795
}
8896
}
97+
Ok(..) => {}
98+
Err(err) => {
99+
err.cancel();
100+
}
89101
}
90-
Ok(..) => {}
91-
Err(err) => err.cancel(),
92-
},
93-
Err(errs) => errs.into_iter().for_each(|err| err.cancel()),
94-
}
102+
}
103+
Err(errs) => errs.into_iter().for_each(|err| {
104+
err.cancel();
105+
}),
106+
};
95107

96108
// If the user tried to use a key="value" flag, but is missing the quotes, provide
97109
// a hint about how to resolve this.
@@ -116,9 +128,9 @@ pub(crate) fn parse_check_cfg(dcx: DiagCtxtHandle<'_>, specs: Vec<String>) -> Ch
116128
let mut check_cfg = CheckCfg { exhaustive_names, exhaustive_values, ..CheckCfg::default() };
117129

118130
for s in specs {
119-
let psess = ParseSess::with_fatal_emitter(
131+
let psess = ParseSess::emitter_with_note(
120132
vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE],
121-
format!("this error occurred on the command line: `--check-cfg={s}`"),
133+
format!("this occurred on the command line: `--check-cfg={s}`"),
122134
);
123135
let filename = FileName::cfg_spec_source_code(&s);
124136

@@ -171,9 +183,11 @@ pub(crate) fn parse_check_cfg(dcx: DiagCtxtHandle<'_>, specs: Vec<String>) -> Ch
171183
let mut parser =
172184
match new_parser_from_source_str(&psess, filename, s.to_string(), StripTokens::Nothing)
173185
{
174-
Ok(parser) => parser,
186+
Ok(parser) => parser.recovery(Recovery::Forbidden),
175187
Err(errs) => {
176-
errs.into_iter().for_each(|err| err.cancel());
188+
errs.into_iter().for_each(|err| {
189+
err.cancel();
190+
});
177191
expected_error();
178192
}
179193
};
@@ -209,11 +223,17 @@ pub(crate) fn parse_check_cfg(dcx: DiagCtxtHandle<'_>, specs: Vec<String>) -> Ch
209223
if values_specified {
210224
error!("`cfg()` names cannot be after values");
211225
}
226+
227+
if !ident.name.can_be_raw() {
228+
error!("malformed `cfg` input, expected a valid identifier");
229+
}
230+
212231
names.push(ident);
213232
} else if let Some(boolean) = arg.boolean_literal() {
214233
if values_specified {
215234
error!("`cfg()` names cannot be after values");
216235
}
236+
217237
names.push(rustc_span::Ident::new(
218238
if boolean { rustc_span::kw::True } else { rustc_span::kw::False },
219239
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: 4 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::{EmitterWithNote, HumanEmitter, stderr_destination};
1212
use rustc_errors::translation::Translator;
1313
use rustc_errors::{
1414
BufferedEarlyLint, ColorConfig, DecorateDiagCompat, Diag, DiagCtxt, DiagCtxtHandle,
@@ -315,16 +315,12 @@ impl ParseSess {
315315
}
316316
}
317317

318-
pub fn with_fatal_emitter(locale_resources: Vec<&'static str>, fatal_note: String) -> Self {
318+
pub fn emitter_with_note(locale_resources: Vec<&'static str>, 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(EmitterWithNote { emitter, note }));
328324
ParseSess::with_dcx(dcx, sm)
329325
}
330326

src/tools/clippy/tests/ui/cast_size.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
//@revisions: 32bit 64bit
2-
//@[32bit]ignore-bitwidth: 64
3-
//@[64bit]ignore-bitwidth: 32
1+
//@revisions: r32bit r64bit
2+
//@[r32bit]ignore-bitwidth: 64
3+
//@[r64bit]ignore-bitwidth: 32
44
//@no-rustfix: only some diagnostics have suggestions
55

66
#![warn(
@@ -62,7 +62,7 @@ fn main() {
6262
//~^ cast_precision_loss
6363
9_999_999_999_999_999usize as f64;
6464
//~^ cast_precision_loss
65-
//~[32bit]^^ ERROR: literal out of range for `usize`
65+
//~[r32bit]^^ ERROR: literal out of range for `usize`
6666
// 999_999_999_999_999_999_999_999_999_999u128 as f128;
6767
}
6868

0 commit comments

Comments
 (0)