about summary refs log tree commit diff
path: root/compiler/rustc_builtin_macros/src/iter.rs
diff options
context:
space:
mode:
authorOli Scherer <github333195615777966@oli-obk.de>2025-02-27 09:51:23 +0000
committerEric Holk <ericholk@microsoft.com>2025-06-03 10:52:32 -0700
commit5fbdfc3e1018072e0c272d19308d72ac5165f01a (patch)
treeb8b697529f74f05d2d0636f5387e600ed449b822 /compiler/rustc_builtin_macros/src/iter.rs
parentaae43c4532690153af7465227816c93036bb1604 (diff)
downloadrust-5fbdfc3e1018072e0c272d19308d72ac5165f01a.tar.gz
rust-5fbdfc3e1018072e0c272d19308d72ac5165f01a.zip
Add `iter` macro
This adds an `iter!` macro that can be used to create movable
generators.

This also adds a yield_expr feature so the `yield` keyword can be used
within iter! macro bodies. This was needed because several unstable
features each need `yield` expressions, so this allows us to stabilize
them separately from any individual feature.

Co-authored-by: Oli Scherer <github35764891676564198441@oli-obk.de>
Co-authored-by: Jieyou Xu <jieyouxu@outlook.com>
Co-authored-by: Travis Cross <tc@traviscross.com>
Diffstat (limited to 'compiler/rustc_builtin_macros/src/iter.rs')
-rw-r--r--compiler/rustc_builtin_macros/src/iter.rs53
1 files changed, 53 insertions, 0 deletions
diff --git a/compiler/rustc_builtin_macros/src/iter.rs b/compiler/rustc_builtin_macros/src/iter.rs
new file mode 100644
index 00000000000..7ad83903a1b
--- /dev/null
+++ b/compiler/rustc_builtin_macros/src/iter.rs
@@ -0,0 +1,53 @@
+use rustc_ast::ptr::P;
+use rustc_ast::tokenstream::TokenStream;
+use rustc_ast::{CoroutineKind, DUMMY_NODE_ID, Expr, ast, token};
+use rustc_errors::PResult;
+use rustc_expand::base::{self, DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
+use rustc_span::Span;
+
+pub(crate) fn expand<'cx>(
+    cx: &'cx mut ExtCtxt<'_>,
+    sp: Span,
+    tts: TokenStream,
+) -> MacroExpanderResult<'cx> {
+    let closure = match parse_closure(cx, sp, tts) {
+        Ok(parsed) => parsed,
+        Err(err) => {
+            return ExpandResult::Ready(DummyResult::any(sp, err.emit()));
+        }
+    };
+
+    ExpandResult::Ready(base::MacEager::expr(closure))
+}
+
+fn parse_closure<'a>(
+    cx: &mut ExtCtxt<'a>,
+    span: Span,
+    stream: TokenStream,
+) -> PResult<'a, P<Expr>> {
+    let mut closure_parser = cx.new_parser_from_tts(stream);
+
+    let coroutine_kind = Some(CoroutineKind::Gen {
+        span,
+        closure_id: DUMMY_NODE_ID,
+        return_impl_trait_id: DUMMY_NODE_ID,
+    });
+
+    let mut closure = closure_parser.parse_expr()?;
+    match &mut closure.kind {
+        ast::ExprKind::Closure(c) => {
+            if let Some(kind) = c.coroutine_kind {
+                cx.dcx().span_err(kind.span(), "only plain closures allowed in `iter!`");
+            }
+            c.coroutine_kind = coroutine_kind;
+            if closure_parser.token != token::Eof {
+                closure_parser.unexpected()?;
+            }
+            Ok(closure)
+        }
+        _ => {
+            cx.dcx().span_err(closure.span, "`iter!` body must be a closure");
+            Err(closure_parser.unexpected().unwrap_err())
+        }
+    }
+}