about summary refs log tree commit diff
path: root/compiler/rustc_builtin_macros
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_builtin_macros')
-rw-r--r--compiler/rustc_builtin_macros/messages.ftl6
-rw-r--r--compiler/rustc_builtin_macros/src/cfg_select.rs63
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/errors.rs18
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/source_util.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/test.rs9
7 files changed, 94 insertions, 10 deletions
diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl
index 3594c7ec210..ae186d744c4 100644
--- a/compiler/rustc_builtin_macros/messages.ftl
+++ b/compiler/rustc_builtin_macros/messages.ftl
@@ -81,6 +81,12 @@ builtin_macros_cfg_accessible_literal_path = `cfg_accessible` path cannot be a l
 builtin_macros_cfg_accessible_multiple_paths = multiple `cfg_accessible` paths are specified
 builtin_macros_cfg_accessible_unspecified_path = `cfg_accessible` path is not specified
 
+builtin_macros_cfg_select_no_matches = none of the predicates in this `cfg_select` evaluated to true
+
+builtin_macros_cfg_select_unreachable = unreachable predicate
+    .label = always matches
+    .label2 = this predicate is never reached
+
 builtin_macros_coerce_pointee_requires_maybe_sized = `derive(CoercePointee)` requires `{$name}` to be marked `?Sized`
 
 builtin_macros_coerce_pointee_requires_one_field = `CoercePointee` can only be derived on `struct`s with at least one field
diff --git a/compiler/rustc_builtin_macros/src/cfg_select.rs b/compiler/rustc_builtin_macros/src/cfg_select.rs
new file mode 100644
index 00000000000..f22d5f255c2
--- /dev/null
+++ b/compiler/rustc_builtin_macros/src/cfg_select.rs
@@ -0,0 +1,63 @@
+use rustc_ast::tokenstream::TokenStream;
+use rustc_attr_parsing as attr;
+use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
+use rustc_parse::parser::cfg_select::{CfgSelectBranches, CfgSelectPredicate, parse_cfg_select};
+use rustc_span::{Ident, Span, sym};
+
+use crate::errors::{CfgSelectNoMatches, CfgSelectUnreachable};
+
+/// Selects the first arm whose predicate evaluates to true.
+fn select_arm(ecx: &ExtCtxt<'_>, branches: CfgSelectBranches) -> Option<(TokenStream, Span)> {
+    for (cfg, tt, arm_span) in branches.reachable {
+        if attr::cfg_matches(
+            &cfg,
+            &ecx.sess,
+            ecx.current_expansion.lint_node_id,
+            Some(ecx.ecfg.features),
+        ) {
+            return Some((tt, arm_span));
+        }
+    }
+
+    branches.wildcard.map(|(_, tt, span)| (tt, span))
+}
+
+pub(super) fn expand_cfg_select<'cx>(
+    ecx: &'cx mut ExtCtxt<'_>,
+    sp: Span,
+    tts: TokenStream,
+) -> MacroExpanderResult<'cx> {
+    ExpandResult::Ready(match parse_cfg_select(&mut ecx.new_parser_from_tts(tts)) {
+        Ok(branches) => {
+            if let Some((underscore, _, _)) = branches.wildcard {
+                // Warn for every unreachable predicate. We store the fully parsed branch for rustfmt.
+                for (predicate, _, _) in &branches.unreachable {
+                    let span = match predicate {
+                        CfgSelectPredicate::Wildcard(underscore) => underscore.span,
+                        CfgSelectPredicate::Cfg(cfg) => cfg.span(),
+                    };
+                    let err = CfgSelectUnreachable { span, wildcard_span: underscore.span };
+                    ecx.dcx().emit_warn(err);
+                }
+            }
+
+            if let Some((tts, arm_span)) = select_arm(ecx, branches) {
+                return ExpandResult::from_tts(
+                    ecx,
+                    tts,
+                    sp,
+                    arm_span,
+                    Ident::with_dummy_span(sym::cfg_select),
+                );
+            } else {
+                // Emit a compiler error when none of the predicates matched.
+                let guar = ecx.dcx().emit_err(CfgSelectNoMatches { span: sp });
+                DummyResult::any(sp, guar)
+            }
+        }
+        Err(err) => {
+            let guar = err.emit();
+            DummyResult::any(sp, guar)
+        }
+    })
+}
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 8c3093acea4..c55a9e73e38 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -484,7 +484,7 @@ impl<'a> TraitDef<'a> {
         match item {
             Annotatable::Item(item) => {
                 let is_packed = matches!(
-                    AttributeParser::parse_limited(cx.sess, &item.attrs, sym::repr, item.span, item.id),
+                    AttributeParser::parse_limited(cx.sess, &item.attrs, sym::repr, item.span, item.id, None),
                     Some(Attribute::Parsed(AttributeKind::Repr { reprs, .. })) if reprs.iter().any(|(x, _)| matches!(x, ReprPacked(..)))
                 );
 
diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs
index a5ee7349fc6..6bcf4d3e0a2 100644
--- a/compiler/rustc_builtin_macros/src/errors.rs
+++ b/compiler/rustc_builtin_macros/src/errors.rs
@@ -954,3 +954,21 @@ pub(crate) struct AsmExpectedOther {
     pub(crate) span: Span,
     pub(crate) is_inline_asm: bool,
 }
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_cfg_select_no_matches)]
+pub(crate) struct CfgSelectNoMatches {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_cfg_select_unreachable)]
+pub(crate) struct CfgSelectUnreachable {
+    #[primary_span]
+    #[label(builtin_macros_label2)]
+    pub span: Span,
+
+    #[label]
+    pub wildcard_span: Span,
+}
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index 6bf590df5c9..7bc448a9acb 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -33,6 +33,7 @@ mod autodiff;
 mod cfg;
 mod cfg_accessible;
 mod cfg_eval;
+mod cfg_select;
 mod compile_error;
 mod concat;
 mod concat_bytes;
@@ -79,6 +80,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
         asm: asm::expand_asm,
         assert: assert::expand_assert,
         cfg: cfg::expand_cfg,
+        cfg_select: cfg_select::expand_cfg_select,
         column: source_util::expand_column,
         compile_error: compile_error::expand_compile_error,
         concat: concat::expand_concat,
diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs
index cebfffa1e16..ecfd46a84ec 100644
--- a/compiler/rustc_builtin_macros/src/source_util.rs
+++ b/compiler/rustc_builtin_macros/src/source_util.rs
@@ -4,8 +4,8 @@ use std::sync::Arc;
 
 use rustc_ast as ast;
 use rustc_ast::ptr::P;
-use rustc_ast::token;
 use rustc_ast::tokenstream::TokenStream;
+use rustc_ast::{join_path_idents, token};
 use rustc_ast_pretty::pprust;
 use rustc_expand::base::{
     DummyResult, ExpandResult, ExtCtxt, MacEager, MacResult, MacroExpanderResult, resolve_path,
@@ -100,7 +100,7 @@ pub(crate) fn expand_mod(
     let sp = cx.with_def_site_ctxt(sp);
     check_zero_tts(cx, sp, tts, "module_path!");
     let mod_path = &cx.current_expansion.module.mod_path;
-    let string = mod_path.iter().map(|x| x.to_string()).collect::<Vec<String>>().join("::");
+    let string = join_path_idents(mod_path);
 
     ExpandResult::Ready(MacEager::expr(cx.expr_str(sp, Symbol::intern(&string))))
 }
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index b067578794b..ba3d8368b2a 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -5,7 +5,7 @@ use std::assert_matches::assert_matches;
 use std::iter;
 
 use rustc_ast::ptr::P;
-use rustc_ast::{self as ast, GenericParamKind, attr};
+use rustc_ast::{self as ast, GenericParamKind, attr, join_path_idents};
 use rustc_ast_pretty::pprust;
 use rustc_errors::{Applicability, Diag, Level};
 use rustc_expand::base::*;
@@ -446,12 +446,7 @@ fn get_location_info(cx: &ExtCtxt<'_>, fn_: &ast::Fn) -> (Symbol, usize, usize,
 }
 
 fn item_path(mod_path: &[Ident], item_ident: &Ident) -> String {
-    mod_path
-        .iter()
-        .chain(iter::once(item_ident))
-        .map(|x| x.to_string())
-        .collect::<Vec<String>>()
-        .join("::")
+    join_path_idents(mod_path.iter().chain(iter::once(item_ident)))
 }
 
 enum ShouldPanic {