Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 99f3f45

Browse files
committedOct 4, 2024
Auto merge of #131034 - Urgau:cfg-true-false, r=nnethercote
Implement RFC3695 Allow boolean literals as cfg predicates This PR implements rust-lang/rfcs#3695: allow boolean literals as cfg predicates, i.e. `cfg(true)` and `cfg(false)`. r? `@nnethercote` *(or anyone with parser knowledge)* cc `@clubby789`
2 parents 3002af6 + a3ffa1e commit 99f3f45

File tree

26 files changed

+284
-58
lines changed

26 files changed

+284
-58
lines changed
 

‎compiler/rustc_ast/src/attr/mod.rs

+10
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,16 @@ impl NestedMetaItem {
527527
}
528528
}
529529

530+
/// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem` or if it's
531+
/// `NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Bool(_), .. })`.
532+
pub fn meta_item_or_bool(&self) -> Option<&NestedMetaItem> {
533+
match self {
534+
NestedMetaItem::MetaItem(_item) => Some(self),
535+
NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Bool(_), .. }) => Some(self),
536+
_ => None,
537+
}
538+
}
539+
530540
/// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem`.
531541
pub fn meta_item(&self) -> Option<&MetaItem> {
532542
match self {

‎compiler/rustc_attr/messages.ftl

+2
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ attr_unknown_version_literal =
107107
attr_unstable_cfg_target_compact =
108108
compact `cfg(target(..))` is experimental and subject to change
109109
110+
attr_unsupported_literal_cfg_boolean =
111+
literal in `cfg` predicate value must be a boolean
110112
attr_unsupported_literal_cfg_string =
111113
literal in `cfg` predicate value must be a string
112114
attr_unsupported_literal_deprecated_kv_pair =

‎compiler/rustc_attr/src/builtin.rs

+45-12
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use rustc_session::parse::feature_err;
1818
use rustc_session::{RustcVersion, Session};
1919
use rustc_span::Span;
2020
use rustc_span::hygiene::Transparency;
21-
use rustc_span::symbol::{Symbol, sym};
21+
use rustc_span::symbol::{Symbol, kw, sym};
2222

2323
use crate::fluent_generated;
2424
use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
@@ -36,6 +36,7 @@ pub fn is_builtin_attr(attr: &Attribute) -> bool {
3636
pub(crate) enum UnsupportedLiteralReason {
3737
Generic,
3838
CfgString,
39+
CfgBoolean,
3940
DeprecatedString,
4041
DeprecatedKvPair,
4142
}
@@ -533,7 +534,7 @@ pub struct Condition {
533534

534535
/// Tests if a cfg-pattern matches the cfg set
535536
pub fn cfg_matches(
536-
cfg: &ast::MetaItem,
537+
cfg: &ast::NestedMetaItem,
537538
sess: &Session,
538539
lint_node_id: NodeId,
539540
features: Option<&Features>,
@@ -604,12 +605,43 @@ pub fn parse_version(s: Symbol) -> Option<RustcVersion> {
604605
/// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to
605606
/// evaluate individual items.
606607
pub fn eval_condition(
607-
cfg: &ast::MetaItem,
608+
cfg: &ast::NestedMetaItem,
608609
sess: &Session,
609610
features: Option<&Features>,
610611
eval: &mut impl FnMut(Condition) -> bool,
611612
) -> bool {
612613
let dcx = sess.dcx();
614+
615+
let cfg = match cfg {
616+
ast::NestedMetaItem::MetaItem(meta_item) => meta_item,
617+
ast::NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => {
618+
if let Some(features) = features {
619+
// we can't use `try_gate_cfg` as symbols don't differentiate between `r#true`
620+
// and `true`, and we want to keep the former working without feature gate
621+
gate_cfg(
622+
&((
623+
if *b { kw::True } else { kw::False },
624+
sym::cfg_boolean_literals,
625+
|features: &Features| features.cfg_boolean_literals,
626+
)),
627+
cfg.span(),
628+
sess,
629+
features,
630+
);
631+
}
632+
return *b;
633+
}
634+
_ => {
635+
dcx.emit_err(session_diagnostics::UnsupportedLiteral {
636+
span: cfg.span(),
637+
reason: UnsupportedLiteralReason::CfgBoolean,
638+
is_bytestr: false,
639+
start_point_span: sess.source_map().start_point(cfg.span()),
640+
});
641+
return false;
642+
}
643+
};
644+
613645
match &cfg.kind {
614646
ast::MetaItemKind::List(mis) if cfg.name_or_empty() == sym::version => {
615647
try_gate_cfg(sym::version, cfg.span, sess, features);
@@ -645,7 +677,7 @@ pub fn eval_condition(
645677
}
646678
ast::MetaItemKind::List(mis) => {
647679
for mi in mis.iter() {
648-
if !mi.is_meta_item() {
680+
if mi.meta_item_or_bool().is_none() {
649681
dcx.emit_err(session_diagnostics::UnsupportedLiteral {
650682
span: mi.span(),
651683
reason: UnsupportedLiteralReason::Generic,
@@ -663,23 +695,19 @@ pub fn eval_condition(
663695
.iter()
664696
// We don't use any() here, because we want to evaluate all cfg condition
665697
// as eval_condition can (and does) extra checks
666-
.fold(false, |res, mi| {
667-
res | eval_condition(mi.meta_item().unwrap(), sess, features, eval)
668-
}),
698+
.fold(false, |res, mi| res | eval_condition(mi, sess, features, eval)),
669699
sym::all => mis
670700
.iter()
671701
// We don't use all() here, because we want to evaluate all cfg condition
672702
// as eval_condition can (and does) extra checks
673-
.fold(true, |res, mi| {
674-
res & eval_condition(mi.meta_item().unwrap(), sess, features, eval)
675-
}),
703+
.fold(true, |res, mi| res & eval_condition(mi, sess, features, eval)),
676704
sym::not => {
677705
let [mi] = mis.as_slice() else {
678706
dcx.emit_err(session_diagnostics::ExpectedOneCfgPattern { span: cfg.span });
679707
return false;
680708
};
681709

682-
!eval_condition(mi.meta_item().unwrap(), sess, features, eval)
710+
!eval_condition(mi, sess, features, eval)
683711
}
684712
sym::target => {
685713
if let Some(features) = features
@@ -700,7 +728,12 @@ pub fn eval_condition(
700728
seg.ident.name = Symbol::intern(&format!("target_{}", seg.ident.name));
701729
}
702730

703-
res & eval_condition(&mi, sess, features, eval)
731+
res & eval_condition(
732+
&ast::NestedMetaItem::MetaItem(mi),
733+
sess,
734+
features,
735+
eval,
736+
)
704737
})
705738
}
706739
_ => {

‎compiler/rustc_attr/src/session_diagnostics.rs

+1
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UnsupportedLiteral {
206206
let mut diag = Diag::new(dcx, level, match self.reason {
207207
UnsupportedLiteralReason::Generic => fluent::attr_unsupported_literal_generic,
208208
UnsupportedLiteralReason::CfgString => fluent::attr_unsupported_literal_cfg_string,
209+
UnsupportedLiteralReason::CfgBoolean => fluent::attr_unsupported_literal_cfg_boolean,
209210
UnsupportedLiteralReason::DeprecatedString => {
210211
fluent::attr_unsupported_literal_deprecated_string
211212
}

‎compiler/rustc_builtin_macros/src/cfg.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ use rustc_ast::token;
66
use rustc_ast::tokenstream::TokenStream;
77
use rustc_errors::PResult;
88
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
9-
use rustc_parse::parser::attr::AllowLeadingUnsafe;
109
use rustc_span::Span;
1110
use {rustc_ast as ast, rustc_attr as attr};
1211

@@ -36,14 +35,18 @@ pub(crate) fn expand_cfg(
3635
})
3736
}
3837

39-
fn parse_cfg<'a>(cx: &ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a, ast::MetaItem> {
38+
fn parse_cfg<'a>(
39+
cx: &ExtCtxt<'a>,
40+
span: Span,
41+
tts: TokenStream,
42+
) -> PResult<'a, ast::NestedMetaItem> {
4043
let mut p = cx.new_parser_from_tts(tts);
4144

4245
if p.token == token::Eof {
4346
return Err(cx.dcx().create_err(errors::RequiresCfgPattern { span }));
4447
}
4548

46-
let cfg = p.parse_meta_item(AllowLeadingUnsafe::No)?;
49+
let cfg = p.parse_meta_item_inner()?;
4750

4851
let _ = p.eat(&token::Comma);
4952

‎compiler/rustc_codegen_ssa/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ pub struct NativeLib {
156156
pub kind: NativeLibKind,
157157
pub name: Symbol,
158158
pub filename: Option<Symbol>,
159-
pub cfg: Option<ast::MetaItem>,
159+
pub cfg: Option<ast::NestedMetaItem>,
160160
pub verbatim: bool,
161161
pub dll_imports: Vec<cstore::DllImport>,
162162
}

‎compiler/rustc_expand/src/config.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ use rustc_ast::token::{Delimiter, Token, TokenKind};
55
use rustc_ast::tokenstream::{
66
AttrTokenStream, AttrTokenTree, LazyAttrTokenStream, Spacing, TokenTree,
77
};
8-
use rustc_ast::{self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem, NodeId};
8+
use rustc_ast::{
9+
self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem, NestedMetaItem, NodeId,
10+
};
911
use rustc_attr as attr;
1012
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
1113
use rustc_feature::{
@@ -449,7 +451,7 @@ impl<'a> StripUnconfigured<'a> {
449451
}
450452
}
451453

452-
pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a MetaItem> {
454+
pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a NestedMetaItem> {
453455
let span = meta_item.span;
454456
match meta_item.meta_item_list() {
455457
None => {
@@ -464,7 +466,7 @@ pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a Meta
464466
sess.dcx().emit_err(InvalidCfg::MultiplePredicates { span: l.span() });
465467
None
466468
}
467-
Some([single]) => match single.meta_item() {
469+
Some([single]) => match single.meta_item_or_bool() {
468470
Some(meta_item) => Some(meta_item),
469471
None => {
470472
sess.dcx().emit_err(InvalidCfg::PredicateLiteral { span: single.span() });

‎compiler/rustc_feature/src/unstable.rs

+2
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,8 @@ declare_features! (
371371
(unstable, async_for_loop, "1.77.0", Some(118898)),
372372
/// Allows using C-variadics.
373373
(unstable, c_variadic, "1.34.0", Some(44930)),
374+
/// Allows the use of `#[cfg(<true/false>)]`.
375+
(unstable, cfg_boolean_literals, "CURRENT_RUSTC_VERSION", Some(131204)),
374376
/// Allows the use of `#[cfg(overflow_checks)` to check if integer overflow behaviour.
375377
(unstable, cfg_overflow_checks, "1.71.0", Some(111466)),
376378
/// Provides the relocation model information as cfg entry

‎compiler/rustc_metadata/src/native_libs.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::ops::ControlFlow;
22
use std::path::{Path, PathBuf};
33

4-
use rustc_ast::{CRATE_NODE_ID, NestedMetaItem};
4+
use rustc_ast::CRATE_NODE_ID;
55
use rustc_attr as attr;
66
use rustc_data_structures::fx::FxHashSet;
77
use rustc_middle::query::LocalCrate;
@@ -304,7 +304,12 @@ impl<'tcx> Collector<'tcx> {
304304
sess.dcx().emit_err(errors::LinkCfgForm { span: item.span() });
305305
continue;
306306
};
307-
let [NestedMetaItem::MetaItem(link_cfg)] = link_cfg else {
307+
let [link_cfg] = link_cfg else {
308+
sess.dcx()
309+
.emit_err(errors::LinkCfgSinglePredicate { span: item.span() });
310+
continue;
311+
};
312+
let Some(link_cfg) = link_cfg.meta_item_or_bool() else {
308313
sess.dcx()
309314
.emit_err(errors::LinkCfgSinglePredicate { span: item.span() });
310315
continue;

‎compiler/rustc_parse/src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use std::path::Path;
1818

1919
use rustc_ast as ast;
2020
use rustc_ast::tokenstream::TokenStream;
21-
use rustc_ast::{AttrItem, Attribute, MetaItem, token};
21+
use rustc_ast::{AttrItem, Attribute, NestedMetaItem, token};
2222
use rustc_ast_pretty::pprust;
2323
use rustc_data_structures::sync::Lrc;
2424
use rustc_errors::{Diag, FatalError, PResult};
@@ -160,7 +160,7 @@ pub fn fake_token_stream_for_crate(psess: &ParseSess, krate: &ast::Crate) -> Tok
160160
pub fn parse_cfg_attr(
161161
cfg_attr: &Attribute,
162162
psess: &ParseSess,
163-
) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> {
163+
) -> Option<(NestedMetaItem, Vec<(AttrItem, Span)>)> {
164164
const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]";
165165
const CFG_ATTR_NOTE_REF: &str = "for more information, visit \
166166
<https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>";

‎compiler/rustc_parse/src/parser/attr.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -356,8 +356,10 @@ impl<'a> Parser<'a> {
356356
}
357357

358358
/// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited.
359-
pub fn parse_cfg_attr(&mut self) -> PResult<'a, (ast::MetaItem, Vec<(ast::AttrItem, Span)>)> {
360-
let cfg_predicate = self.parse_meta_item(AllowLeadingUnsafe::No)?;
359+
pub fn parse_cfg_attr(
360+
&mut self,
361+
) -> PResult<'a, (ast::NestedMetaItem, Vec<(ast::AttrItem, Span)>)> {
362+
let cfg_predicate = self.parse_meta_item_inner()?;
361363
self.expect(&token::Comma)?;
362364

363365
// Presumably, the majority of the time there will only be one attr.
@@ -452,7 +454,7 @@ impl<'a> Parser<'a> {
452454
/// ```ebnf
453455
/// MetaItemInner = UNSUFFIXED_LIT | MetaItem ;
454456
/// ```
455-
fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> {
457+
pub fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> {
456458
match self.parse_unsuffixed_meta_item_lit() {
457459
Ok(lit) => return Ok(ast::NestedMetaItem::Lit(lit)),
458460
Err(err) => err.cancel(), // we provide a better error below

‎compiler/rustc_session/src/cstore.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ pub struct NativeLib {
7272
pub name: Symbol,
7373
/// If packed_bundled_libs enabled, actual filename of library is stored.
7474
pub filename: Option<Symbol>,
75-
pub cfg: Option<ast::MetaItem>,
75+
pub cfg: Option<ast::NestedMetaItem>,
7676
pub foreign_module: Option<DefId>,
7777
pub verbatim: Option<bool>,
7878
pub dll_imports: Vec<DllImport>,

‎compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,7 @@ symbols! {
544544
cfg_accessible,
545545
cfg_attr,
546546
cfg_attr_multi,
547+
cfg_boolean_literals,
547548
cfg_doctest,
548549
cfg_eval,
549550
cfg_fmt_debug,

‎compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::iter;
22
use std::path::PathBuf;
33

4-
use rustc_ast::{AttrArgs, AttrArgsEq, AttrKind, Attribute, MetaItem, NestedMetaItem};
4+
use rustc_ast::{AttrArgs, AttrArgsEq, AttrKind, Attribute, NestedMetaItem};
55
use rustc_data_structures::fx::FxHashMap;
66
use rustc_errors::codes::*;
77
use rustc_errors::{ErrorGuaranteed, struct_span_code_err};
@@ -282,7 +282,7 @@ pub struct OnUnimplementedFormatString {
282282

283283
#[derive(Debug)]
284284
pub struct OnUnimplementedDirective {
285-
pub condition: Option<MetaItem>,
285+
pub condition: Option<NestedMetaItem>,
286286
pub subcommands: Vec<OnUnimplementedDirective>,
287287
pub message: Option<OnUnimplementedFormatString>,
288288
pub label: Option<OnUnimplementedFormatString>,
@@ -414,7 +414,7 @@ impl<'tcx> OnUnimplementedDirective {
414414
let cond = item_iter
415415
.next()
416416
.ok_or_else(|| tcx.dcx().emit_err(EmptyOnClauseInOnUnimplemented { span }))?
417-
.meta_item()
417+
.meta_item_or_bool()
418418
.ok_or_else(|| tcx.dcx().emit_err(InvalidOnClauseInOnUnimplemented { span }))?;
419419
attr::eval_condition(cond, &tcx.sess, Some(tcx.features()), &mut |cfg| {
420420
if let Some(value) = cfg.value
@@ -558,8 +558,8 @@ impl<'tcx> OnUnimplementedDirective {
558558
IgnoredDiagnosticOption::maybe_emit_warning(
559559
tcx,
560560
item_def_id,
561-
directive.condition.as_ref().map(|i| i.span),
562-
aggr.condition.as_ref().map(|i| i.span),
561+
directive.condition.as_ref().map(|i| i.span()),
562+
aggr.condition.as_ref().map(|i| i.span()),
563563
"condition",
564564
);
565565
IgnoredDiagnosticOption::maybe_emit_warning(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# `cfg_boolean_literals`
2+
3+
The tracking issue for this feature is: [#131204]
4+
5+
[#131204]: https://github.com/rust-lang/rust/issues/131204
6+
7+
------------------------
8+
9+
The `cfg_boolean_literals` feature makes it possible to use the `true`/`false`
10+
literal as cfg predicate. They always evaluate to true/false respectively.
11+
12+
## Examples
13+
14+
```rust
15+
#![feature(cfg_boolean_literals)]
16+
17+
#[cfg(true)]
18+
const A: i32 = 5;
19+
20+
#[cfg(all(false))]
21+
const A: i32 = 58 * 89;
22+
```
There was a problem loading the remainder of the diff.

0 commit comments

Comments
 (0)
Failed to load comments.