Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion compiler/rustc_attr_parsing/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ impl<'sess> AttributeParser<'sess, Early> {
target_node_id: NodeId,
features: Option<&'sess Features>,
emit_errors: ShouldEmit,
parsing_cfg: bool,
parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser<'_>) -> Option<T>,
template: &AttributeTemplate,
) -> Option<T> {
Expand All @@ -133,7 +134,8 @@ impl<'sess> AttributeParser<'sess, Early> {
};
let parts =
normal_attr.item.path.segments.iter().map(|seg| seg.ident.name).collect::<Vec<_>>();
let meta_parser = MetaItemParser::from_attr(normal_attr, &parts, &sess.psess, emit_errors)?;
let meta_parser =
MetaItemParser::from_attr(normal_attr, &parts, &sess.psess, emit_errors, parsing_cfg)?;
let path = meta_parser.path();
let args = meta_parser.args();
let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext {
Expand Down Expand Up @@ -251,6 +253,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
&parts,
&self.sess.psess,
self.stage.should_emit(),
false,
) else {
continue;
};
Expand Down
25 changes: 22 additions & 3 deletions compiler/rustc_attr_parsing/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ impl<'a> ArgParser<'a> {
parts: &[Symbol],
psess: &'sess ParseSess,
should_emit: ShouldEmit,
parsing_cfg: bool,
) -> Option<Self> {
Some(match value {
AttrArgs::Empty => Self::NoArgs,
Expand All @@ -124,7 +125,7 @@ impl<'a> ArgParser<'a> {
return None;
}

Self::List(MetaItemListParser::new(args, psess, should_emit)?)
Self::List(MetaItemListParser::new(args, psess, should_emit, parsing_cfg)?)
}
AttrArgs::Eq { eq_span, expr } => Self::NameValue(NameValueParser {
eq_span: *eq_span,
Expand Down Expand Up @@ -248,10 +249,17 @@ impl<'a> MetaItemParser<'a> {
parts: &[Symbol],
psess: &'sess ParseSess,
should_emit: ShouldEmit,
parsing_cfg: bool,
) -> Option<Self> {
Some(Self {
path: PathParser(Cow::Borrowed(&attr.item.path)),
args: ArgParser::from_attr_args(&attr.item.args, parts, psess, should_emit)?,
args: ArgParser::from_attr_args(
&attr.item.args,
parts,
psess,
should_emit,
parsing_cfg,
)?,
})
}
}
Expand Down Expand Up @@ -425,7 +433,13 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
};
}

let path = self.parser.parse_path(PathStyle::Mod)?;
let path = if self.parser.parse_cfg_pred {
let path = self.parser.parse_path(PathStyle::CfgPred)?;
self.parser.parse_cfg_pred = false;
path
} else {
self.parser.parse_path(PathStyle::Mod)?
};

// Check style of arguments that this meta item has
let args = if self.parser.check(exp!(OpenParen)) {
Expand Down Expand Up @@ -513,8 +527,11 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
psess: &'sess ParseSess,
span: Span,
should_emit: ShouldEmit,
parsing_cfg: bool,
) -> PResult<'sess, MetaItemListParser<'static>> {
let mut parser = Parser::new(psess, tokens, None);
parser.parse_cfg_pred = parsing_cfg;

let mut this = MetaItemListParserContext { parser: &mut parser, should_emit };

// Presumably, the majority of the time there will only be one attr.
Expand Down Expand Up @@ -546,12 +563,14 @@ impl<'a> MetaItemListParser<'a> {
delim: &'a DelimArgs,
psess: &'sess ParseSess,
should_emit: ShouldEmit,
parsing_cfg: bool,
) -> Option<Self> {
match MetaItemListParserContext::parse(
delim.tokens.clone(),
psess,
delim.dspan.entire(),
should_emit,
parsing_cfg,
) {
Ok(s) => Some(s),
Err(e) => {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_builtin_macros/src/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ fn parse_cfg<'a>(
tts: TokenStream,
) -> PResult<'a, ast::MetaItemInner> {
let mut p = cx.new_parser_from_tts(tts);
p.parse_cfg_pred = true;

if p.token == token::Eof {
return Err(cx.dcx().create_err(errors::RequiresCfgPattern { span }));
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_expand/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,7 @@ impl<'a> StripUnconfigured<'a> {
node,
self.features,
emit_errors,
true,
parse_cfg_attr,
&CFG_TEMPLATE,
) else {
Expand Down
55 changes: 52 additions & 3 deletions compiler/rustc_interface/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ pub(crate) fn parse_cfg(dcx: DiagCtxtHandle<'_>, cfgs: Vec<String>) -> Cfg {
#[allow(rustc::untranslatable_diagnostic)]
#[allow(rustc::diagnostic_outside_of_impl)]
dcx.fatal(format!(
concat!("invalid `--cfg` argument: `{}` (", $reason, ")"),
s
concat!("invalid `--cfg` argument: `{}` ({})"),
s, $reason,
));
};
}
Expand All @@ -83,6 +83,19 @@ pub(crate) fn parse_cfg(dcx: DiagCtxtHandle<'_>, cfgs: Vec<String>) -> Cfg {
}
MetaItemKind::NameValue(..) | MetaItemKind::Word => {
let ident = meta_item.ident().expect("multi-segment cfg key");

if ident.is_reserved() {
if !ident.name.can_be_raw() {
if s.trim().starts_with(&format!("r#{}", ident.as_str())) {
error!(format!("argument key must be an identifier, but `{}` cannot be a raw identifier", ident.name));
} else {
error!(format!("argument key must be an identifier but found keyword `{}`", ident.name));
}
} else if !s.trim().starts_with(&ident.to_string()) {
error!(format!("argument key must be an identifier but found keyword `{}`, escape it using `{}`", ident.as_str(), ident));
}
}

return (ident.name, meta_item.value_str());
}
}
Expand All @@ -91,7 +104,7 @@ pub(crate) fn parse_cfg(dcx: DiagCtxtHandle<'_>, cfgs: Vec<String>) -> Cfg {
Err(err) => err.cancel(),
},
Err(errs) => errs.into_iter().for_each(|err| err.cancel()),
}
};

// If the user tried to use a key="value" flag, but is missing the quotes, provide
// a hint about how to resolve this.
Expand Down Expand Up @@ -202,18 +215,54 @@ pub(crate) fn parse_check_cfg(dcx: DiagCtxtHandle<'_>, specs: Vec<String>) -> Ch
let mut values_specified = false;
let mut values_any_specified = false;

let arg_strs = s
.trim()
.trim_start_matches("cfg(")
.trim_end_matches(')')
.split(',')
.collect::<Vec<_>>();

for arg in args {
if arg.is_word()
&& let Some(ident) = arg.ident()
{
if values_specified {
error!("`cfg()` names cannot be after values");
}

if ident.is_reserved() {
if !ident.name.can_be_raw() {
if arg_strs[names.len()].starts_with(&format!("r#{}", ident.as_str())) {
error!(format!(
"argument key must be an identifier, but `{}` cannot be a raw identifier",
ident.name
));
} else {
error!(format!(
"argument key must be an identifier but found keyword `{}`",
ident.name
));
}
} else if !arg_strs[names.len()].starts_with(&ident.to_string()) {
error!(format!(
"argument key must be an identifier but found keyword `{}`, escape it using `{}`",
ident.as_str(),
ident
));
}
}

names.push(ident);
} else if let Some(boolean) = arg.boolean_literal() {
if values_specified {
error!("`cfg()` names cannot be after values");
}

let lit_str = arg_strs[names.len()];
if !lit_str.starts_with("r#") {
error!(in arg, format!("`cfg()` names must be identifiers but found keyword `{lit_str}`, escape it using `r#{lit_str}`"));
}

names.push(rustc_span::Ident::new(
if boolean { rustc_span::kw::True } else { rustc_span::kw::False },
arg.span(),
Expand Down
10 changes: 9 additions & 1 deletion compiler/rustc_parse/src/parser/attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,7 @@ impl<'a> Parser<'a> {
pub fn parse_cfg_attr(
&mut self,
) -> PResult<'a, (ast::MetaItemInner, Vec<(ast::AttrItem, Span)>)> {
self.parse_cfg_pred = true;
let cfg_predicate = self.parse_meta_item_inner()?;
self.expect(exp!(Comma))?;

Expand Down Expand Up @@ -449,7 +450,14 @@ impl<'a> Parser<'a> {
ast::Safety::Default
};

let path = self.parse_path(PathStyle::Mod)?;
let path = if self.parse_cfg_pred {
let path = self.parse_path(PathStyle::CfgPred)?;
self.parse_cfg_pred = false;
path
} else {
self.parse_path(PathStyle::Mod)?
};

let kind = self.parse_meta_item_kind()?;
if is_unsafe {
self.expect(exp!(CloseParen))?;
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_parse/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ pub struct Parser<'a> {
/// The previous token.
pub prev_token: Token,
pub capture_cfg: bool,
pub parse_cfg_pred: bool,
restrictions: Restrictions,
expected_token_types: TokenTypeSet,
token_cursor: TokenCursor,
Expand Down Expand Up @@ -372,6 +373,7 @@ impl<'a> Parser<'a> {
},
current_closure: None,
recovery: Recovery::Allowed,
parse_cfg_pred: false,
};

// Make parser point to the first token.
Expand Down
9 changes: 8 additions & 1 deletion compiler/rustc_parse/src/parser/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ pub enum PathStyle {
/// anyway, due to macros), but it is used to avoid weird suggestions about expected
/// tokens when something goes wrong.
Mod,
/// Disallow path segment keywords when parsing cfg preds
CfgPred,
}

impl PathStyle {
Expand Down Expand Up @@ -299,7 +301,12 @@ impl<'a> Parser<'a> {
style: PathStyle,
ty_generics: Option<&Generics>,
) -> PResult<'a, PathSegment> {
let ident = self.parse_path_segment_ident()?;
let ident = if style == PathStyle::CfgPred {
self.parse_ident()?
} else {
self.parse_path_segment_ident()?
};

let is_args_start = |token: &Token| {
matches!(token.kind, token::Lt | token::Shl | token::OpenParen | token::LArrow)
};
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3048,7 +3048,7 @@ impl Symbol {
self == kw::True || self == kw::False
}

/// Returns `true` if this symbol can be a raw identifier.
/// Returns `true` if this symbol can be a raw identifier in path segment.
pub fn can_be_raw(self) -> bool {
self != sym::empty && self != kw::Underscore && !self.is_path_segment_keyword()
}
Expand Down
10 changes: 5 additions & 5 deletions tests/codegen-llvm/cf-protection.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// Test that the correct module flags are emitted with different control-flow protection flags.

//@ add-core-stubs
//@ revisions: undefined none branch return full
//@ revisions: undefined none branch return_ full
//@ needs-llvm-components: x86
// [undefined] no extra compile-flags
//@ [none] compile-flags: -Z cf-protection=none
//@ [branch] compile-flags: -Z cf-protection=branch
//@ [return] compile-flags: -Z cf-protection=return
//@ [return_] compile-flags: -Z cf-protection=return
//@ [full] compile-flags: -Z cf-protection=full
//@ compile-flags: --target x86_64-unknown-linux-gnu

Expand All @@ -30,9 +30,9 @@ pub fn test() {}
// branch: !"cf-protection-branch", i32 1
// branch-NOT: !"cf-protection-return"

// return-NOT: !"cf-protection-branch"
// return: !"cf-protection-return", i32 1
// return-NOT: !"cf-protection-branch"
// return_-NOT: !"cf-protection-branch"
// return_: !"cf-protection-return", i32 1
// return_-NOT: !"cf-protection-branch"

// full: !"cf-protection-branch", i32 1
// full: !"cf-protection-return", i32 1
2 changes: 1 addition & 1 deletion tests/ui/cfg/cmdline-false.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/// Test that `--cfg false` doesn't cause `cfg(false)` to evaluate to `true`
//@ compile-flags: --cfg false
//@ compile-flags: --cfg r#false

#[cfg(false)]
fn foo() {}
Expand Down
2 changes: 2 additions & 0 deletions tests/ui/cfg/path-kw-as-cfg-pred-cli-cfg.cfg_async.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: invalid `--cfg` argument: `async` (argument key must be an identifier but found keyword `async`, escape it using `r#async`)

2 changes: 2 additions & 0 deletions tests/ui/cfg/path-kw-as-cfg-pred-cli-cfg.cfg_crate.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: invalid `--cfg` argument: `crate` (argument key must be an identifier but found keyword `crate`)

2 changes: 2 additions & 0 deletions tests/ui/cfg/path-kw-as-cfg-pred-cli-cfg.cfg_enum.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: invalid `--cfg` argument: `enum` (argument key must be an identifier but found keyword `enum`, escape it using `r#enum`)

2 changes: 2 additions & 0 deletions tests/ui/cfg/path-kw-as-cfg-pred-cli-cfg.cfg_impl.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: invalid `--cfg` argument: `impl` (argument key must be an identifier but found keyword `impl`, escape it using `r#impl`)

2 changes: 2 additions & 0 deletions tests/ui/cfg/path-kw-as-cfg-pred-cli-cfg.cfg_raw_crate.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: invalid `--cfg` argument: `r#crate` (argument key must be an identifier, but `crate` cannot be a raw identifier)

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: invalid `--cfg` argument: `r#self` (argument key must be an identifier, but `self` cannot be a raw identifier)

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: invalid `--cfg` argument: `r#Self` (argument key must be an identifier, but `Self` cannot be a raw identifier)

2 changes: 2 additions & 0 deletions tests/ui/cfg/path-kw-as-cfg-pred-cli-cfg.cfg_raw_super.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: invalid `--cfg` argument: `r#super` (argument key must be an identifier, but `super` cannot be a raw identifier)

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: invalid `--cfg` argument: `self` (argument key must be an identifier but found keyword `self`)

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: invalid `--cfg` argument: `Self` (argument key must be an identifier but found keyword `Self`)

2 changes: 2 additions & 0 deletions tests/ui/cfg/path-kw-as-cfg-pred-cli-cfg.cfg_struct.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: invalid `--cfg` argument: `struct` (argument key must be an identifier but found keyword `struct`, escape it using `r#struct`)

2 changes: 2 additions & 0 deletions tests/ui/cfg/path-kw-as-cfg-pred-cli-cfg.cfg_super.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: invalid `--cfg` argument: `super` (argument key must be an identifier but found keyword `super`)

2 changes: 2 additions & 0 deletions tests/ui/cfg/path-kw-as-cfg-pred-cli-cfg.cfg_trait.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: invalid `--cfg` argument: `trait` (argument key must be an identifier but found keyword `trait`, escape it using `r#trait`)

26 changes: 26 additions & 0 deletions tests/ui/cfg/path-kw-as-cfg-pred-cli-cfg.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//@ edition: 2024
//@ check-fail

//@ revisions: cfg_crate cfg_super cfg_self_lower cfg_self_upper
//@ revisions: cfg_struct cfg_enum cfg_async cfg_impl cfg_trait
//@ revisions: cfg_raw_crate cfg_raw_super cfg_raw_self_lower cfg_raw_self_upper

//@ [cfg_crate]compile-flags: --cfg crate
//@ [cfg_super]compile-flags: --cfg super
//@ [cfg_self_lower]compile-flags: --cfg self
//@ [cfg_self_upper]compile-flags: --cfg Self

//@ [cfg_struct]compile-flags: --cfg struct
//@ [cfg_enum]compile-flags: --cfg enum
//@ [cfg_async]compile-flags: --cfg async
//@ [cfg_impl]compile-flags: --cfg impl
//@ [cfg_trait]compile-flags: --cfg trait

//@ [cfg_raw_crate]compile-flags: --cfg r#crate
//@ [cfg_raw_super]compile-flags: --cfg r#super
//@ [cfg_raw_self_lower]compile-flags: --cfg r#self
//@ [cfg_raw_self_upper]compile-flags: --cfg r#Self

fn main() {}

//~? ERROR invalid `--cfg` argument
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
error: invalid `--check-cfg` argument: `cfg(async)`
|
= note: argument key must be an identifier but found keyword `async`, escape it using `r#async`
= note: visit <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more details

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
error: invalid `--check-cfg` argument: `cfg(crate)`
|
= note: argument key must be an identifier but found keyword `crate`
= note: visit <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more details

Loading
Loading