Skip to content

Commit 3b3e3bc

Browse files
authored
Rollup merge of rust-lang#146978 - mu001999-contrib:fix/path-kw-as-cfg-pred, r=petrochenkov
Emit error when using path-segment keyword as cfg pred Fixes rust-lang#146968 Emit error `CfgPredicateIdentifier` if the word is path-segment keyword. Detailed change description - rust-lang#146978 (comment). r? petrochenkov
2 parents 2286e5d + 5d70446 commit 3b3e3bc

File tree

52 files changed

+988
-99
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

+988
-99
lines changed

compiler/rustc_attr_parsing/src/attributes/cfg.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ pub fn parse_cfg_entry<S: Stage>(
8282
}
8383
},
8484
a @ (ArgParser::NoArgs | ArgParser::NameValue(_)) => {
85-
let Some(name) = meta.path().word_sym() else {
85+
let Some(name) = meta.path().word_sym().filter(|s| !s.is_path_segment_keyword())
86+
else {
8687
return Err(cx.expected_identifier(meta.path().span()));
8788
};
8889
parse_name_value(name, meta.path().span(), a.name_value(), meta.span(), cx)?
@@ -158,7 +159,7 @@ fn parse_cfg_entry_target<S: Stage>(
158159
};
159160

160161
// Then, parse it as a name-value item
161-
let Some(name) = sub_item.path().word_sym() else {
162+
let Some(name) = sub_item.path().word_sym().filter(|s| !s.is_path_segment_keyword()) else {
162163
return Err(cx.expected_identifier(sub_item.path().span()));
163164
};
164165
let name = Symbol::intern(&format!("target_{name}"));

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
@@ -532,30 +532,24 @@ impl Emitter for HumanEmitter {
532532
}
533533
}
534534

535-
/// An emitter that does nothing when emitting a non-fatal diagnostic.
536-
/// Fatal diagnostics are forwarded to `fatal_emitter` to avoid silent
537-
/// failures of rustc, as witnessed e.g. in issue #89358.
538-
pub struct FatalOnlyEmitter {
539-
pub fatal_emitter: Box<dyn Emitter + DynSend>,
540-
pub fatal_note: Option<String>,
535+
/// An emitter that adds a note to each diagnostic.
536+
pub struct EmitterWithNote {
537+
pub emitter: Box<dyn Emitter + DynSend>,
538+
pub note: String,
541539
}
542540

543-
impl Emitter for FatalOnlyEmitter {
541+
impl Emitter for EmitterWithNote {
544542
fn source_map(&self) -> Option<&SourceMap> {
545543
None
546544
}
547545

548546
fn emit_diagnostic(&mut self, mut diag: DiagInner, registry: &Registry) {
549-
if diag.level == Level::Fatal {
550-
if let Some(fatal_note) = &self.fatal_note {
551-
diag.sub(Level::Note, fatal_note.clone(), MultiSpan::new());
552-
}
553-
self.fatal_emitter.emit_diagnostic(diag, registry);
554-
}
547+
diag.sub(Level::Note, self.note.clone(), MultiSpan::new());
548+
self.emitter.emit_diagnostic(diag, registry);
555549
}
556550

557551
fn translator(&self) -> &Translator {
558-
self.fatal_emitter.translator()
552+
self.emitter.translator()
559553
}
560554
}
561555

compiler/rustc_interface/src/interface.rs

Lines changed: 44 additions & 26 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,56 @@ 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)
76+
if parser.token == token::Eof
77+
&& parser.dcx().has_errors().is_none() =>
78+
{
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");
86-
return (ident.name, meta_item.value_str());
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");
89+
90+
if ident.is_path_segment_keyword() {
91+
error!(
92+
"malformed `cfg` input, expected a valid identifier"
93+
);
94+
}
95+
96+
return (ident.name, meta_item.value_str());
97+
}
8798
}
8899
}
100+
Ok(..) => {}
101+
Err(err) => err.cancel(),
89102
}
90-
Ok(..) => {}
91-
Err(err) => err.cancel(),
92-
},
103+
}
93104
Err(errs) => errs.into_iter().for_each(|err| err.cancel()),
94-
}
105+
};
95106

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

118129
for s in specs {
119-
let psess = ParseSess::with_fatal_emitter(
130+
let psess = ParseSess::emitter_with_note(
120131
vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE],
121-
format!("this error occurred on the command line: `--check-cfg={s}`"),
132+
format!("this occurred on the command line: `--check-cfg={s}`"),
122133
);
123134
let filename = FileName::cfg_spec_source_code(&s);
124135

@@ -171,15 +182,17 @@ pub(crate) fn parse_check_cfg(dcx: DiagCtxtHandle<'_>, specs: Vec<String>) -> Ch
171182
let mut parser =
172183
match new_parser_from_source_str(&psess, filename, s.to_string(), StripTokens::Nothing)
173184
{
174-
Ok(parser) => parser,
185+
Ok(parser) => parser.recovery(Recovery::Forbidden),
175186
Err(errs) => {
176187
errs.into_iter().for_each(|err| err.cancel());
177188
expected_error();
178189
}
179190
};
180191

181192
let meta_item = match parser.parse_meta_item(AllowLeadingUnsafe::No) {
182-
Ok(meta_item) if parser.token == token::Eof => meta_item,
193+
Ok(meta_item) if parser.token == token::Eof && parser.dcx().has_errors().is_none() => {
194+
meta_item
195+
}
183196
Ok(..) => expected_error(),
184197
Err(err) => {
185198
err.cancel();
@@ -209,6 +222,11 @@ pub(crate) fn parse_check_cfg(dcx: DiagCtxtHandle<'_>, specs: Vec<String>) -> Ch
209222
if values_specified {
210223
error!("`cfg()` names cannot be after values");
211224
}
225+
226+
if ident.is_path_segment_keyword() {
227+
error!("malformed `cfg` input, expected a valid identifier");
228+
}
229+
212230
names.push(ident);
213231
} else if let Some(boolean) = arg.boolean_literal() {
214232
if values_specified {

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)