about summary refs log tree commit diff
path: root/compiler/rustc_builtin_macros/src
diff options
context:
space:
mode:
authorDrMeepster <19316085+DrMeepster@users.noreply.github.com>2022-09-11 00:37:49 -0700
committerDrMeepster <19316085+DrMeepster@users.noreply.github.com>2023-04-21 02:14:02 -0700
commit511e457c4ba88097ee46ef07b7ef80ce4dd4a3c5 (patch)
tree9aed1b0210cfd3c784a7c5cc89646b8d9dad5427 /compiler/rustc_builtin_macros/src
parentb92a41c6760801a7128ca0ec69ba4ba9c9194054 (diff)
downloadrust-511e457c4ba88097ee46ef07b7ef80ce4dd4a3c5.tar.gz
rust-511e457c4ba88097ee46ef07b7ef80ce4dd4a3c5.zip
offset_of
Diffstat (limited to 'compiler/rustc_builtin_macros/src')
-rw-r--r--compiler/rustc_builtin_macros/src/assert/context.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/offset_of.rs99
3 files changed, 102 insertions, 0 deletions
diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs
index c9e3cd486f8..090e00616fb 100644
--- a/compiler/rustc_builtin_macros/src/assert/context.rs
+++ b/compiler/rustc_builtin_macros/src/assert/context.rs
@@ -301,6 +301,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
             | ExprKind::If(_, _, _)
             | ExprKind::IncludedBytes(..)
             | ExprKind::InlineAsm(_)
+            | ExprKind::OffsetOf(_, _)
             | ExprKind::Let(_, _, _)
             | ExprKind::Lit(_)
             | ExprKind::Loop(_, _, _)
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index 134d64ce9cc..8f86ef44aa3 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -45,6 +45,7 @@ mod format;
 mod format_foreign;
 mod global_allocator;
 mod log_syntax;
+mod offset_of;
 mod source_util;
 mod test;
 mod trace_macros;
@@ -92,6 +93,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
         line: source_util::expand_line,
         log_syntax: log_syntax::expand_log_syntax,
         module_path: source_util::expand_mod,
+        offset_of: offset_of::expand_offset_of,
         option_env: env::expand_option_env,
         core_panic: edition_panic::expand_panic,
         std_panic: edition_panic::expand_panic,
diff --git a/compiler/rustc_builtin_macros/src/offset_of.rs b/compiler/rustc_builtin_macros/src/offset_of.rs
new file mode 100644
index 00000000000..f5c04015340
--- /dev/null
+++ b/compiler/rustc_builtin_macros/src/offset_of.rs
@@ -0,0 +1,99 @@
+use rustc_ast as ast;
+use rustc_ast::ptr::P;
+use rustc_ast::token;
+use rustc_ast::tokenstream::TokenStream;
+use rustc_errors::PResult;
+use rustc_expand::base::{self, *};
+use rustc_macros::Diagnostic;
+use rustc_parse::parser::Parser;
+use rustc_span::{symbol::Ident, Span};
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_offset_of_expected_field)]
+struct ExpectedField {
+    #[primary_span]
+    span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_offset_of_expected_two_args)]
+struct ExpectedTwoArgs {
+    #[primary_span]
+    span: Span,
+}
+
+fn parse_field<'a>(cx: &ExtCtxt<'a>, p: &mut Parser<'a>) -> PResult<'a, Ident> {
+    let token = p.token.uninterpolate();
+    let field = match token.kind {
+        token::Ident(name, _) => Ident::new(name, token.span),
+        token::Literal(token::Lit { kind: token::Integer, symbol, suffix: None }) => {
+            Ident::new(symbol, token.span)
+        }
+        _ => return Err(cx.create_err(ExpectedField { span: p.token.span })),
+    };
+
+    p.bump();
+
+    Ok(field)
+}
+
+fn parse_args<'a>(
+    cx: &mut ExtCtxt<'a>,
+    sp: Span,
+    tts: TokenStream,
+) -> PResult<'a, (P<ast::Ty>, Vec<Ident>)> {
+    let mut p = cx.new_parser_from_tts(tts);
+
+    let container = p.parse_ty()?;
+
+    p.expect(&token::Comma)?;
+
+    if p.eat(&token::Eof) {
+        return Err(cx.create_err(ExpectedTwoArgs { span: sp }));
+    }
+
+    let mut fields = Vec::new();
+
+    loop {
+        let field = parse_field(cx, &mut p)?;
+        fields.push(field);
+
+        if p.eat(&token::Dot) {
+            continue;
+        }
+
+        p.eat(&token::Comma);
+
+        if !p.eat(&token::Eof) {
+            return Err(cx.create_err(ExpectedTwoArgs { span: sp }));
+        }
+
+        break;
+    }
+
+    Ok((container, fields))
+}
+
+pub fn expand_offset_of<'cx>(
+    cx: &'cx mut ExtCtxt<'_>,
+    sp: Span,
+    tts: TokenStream,
+) -> Box<dyn base::MacResult + 'cx> {
+    match parse_args(cx, sp, tts) {
+        Ok((container, fields)) => {
+            let expr = P(ast::Expr {
+                id: ast::DUMMY_NODE_ID,
+                kind: ast::ExprKind::OffsetOf(container, fields),
+                span: sp,
+                attrs: ast::AttrVec::new(),
+                tokens: None,
+            });
+
+            MacEager::expr(expr)
+        }
+        Err(mut err) => {
+            err.emit();
+            DummyResult::any(sp)
+        }
+    }
+}