about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-09-05 12:10:31 +0000
committerbors <bors@rust-lang.org>2023-09-05 12:10:31 +0000
commitcaeea45999c0f34bf996220051082c07ce3c72a0 (patch)
tree68cf692a3612188eb63e082c18f5f63b95d29780
parent2df30e1e07eafc1de0359566423f471920693a34 (diff)
parent3431d586e5c61c8387e07972a4a19781ac785223 (diff)
downloadrust-caeea45999c0f34bf996220051082c07ce3c72a0.tar.gz
rust-caeea45999c0f34bf996220051082c07ce3c72a0.zip
Auto merge of #15557 - Veykril:builtin-syntax, r=Veykril
Parse builtin# syntax and add typechecking for builtin#offset_of expression

Also removes box syntax, fixes https://github.com/rust-lang/rust-analyzer/issues/14504

cc https://github.com/rust-lang/compiler-team/issues/580 https://github.com/rust-lang/rust-analyzer/issues/15082
-rw-r--r--crates/hir-def/src/body/lower.rs20
-rw-r--r--crates/hir-def/src/body/pretty.rs11
-rw-r--r--crates/hir-def/src/hir.rs16
-rw-r--r--crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs39
-rw-r--r--crates/hir-expand/src/builtin_fn_macro.rs12
-rw-r--r--crates/hir-ty/src/infer/closure.rs3
-rw-r--r--crates/hir-ty/src/infer/expr.rs5
-rw-r--r--crates/hir-ty/src/infer/mutability.rs2
-rw-r--r--crates/hir-ty/src/mir/lower.rs6
-rw-r--r--crates/hir-ty/src/tests/simple.rs89
-rw-r--r--crates/hir-ty/src/tests/traits.rs28
-rw-r--r--crates/ide-assists/src/handlers/convert_bool_then.rs1
-rw-r--r--crates/ide-assists/src/handlers/promote_local_to_const.rs3
-rw-r--r--crates/ide-assists/src/handlers/remove_dbg.rs5
-rw-r--r--crates/ide-assists/src/utils/suggest_name.rs1
-rw-r--r--crates/ide-db/src/syntax_helpers/node_ext.rs6
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_strings.html10
-rw-r--r--crates/ide/src/syntax_highlighting/tests.rs10
-rw-r--r--crates/parser/src/grammar/expressions/atom.rs70
-rw-r--r--crates/parser/src/lexed_str.rs1
-rw-r--r--crates/parser/src/syntax_kind/generated.rs18
-rw-r--r--crates/parser/test_data/parser/inline/ok/0132_box_expr.rast90
-rw-r--r--crates/parser/test_data/parser/inline/ok/0132_box_expr.rs5
-rw-r--r--crates/parser/test_data/parser/inline/ok/0207_builtin_expr.rast62
-rw-r--r--crates/parser/test_data/parser/inline/ok/0207_builtin_expr.rs5
-rw-r--r--crates/syntax/rust.ungram16
-rw-r--r--crates/syntax/src/ast/generated/nodes.rs139
-rw-r--r--crates/syntax/src/ast/prec.rs19
-rw-r--r--crates/syntax/src/tests/ast_src.rs18
-rw-r--r--crates/syntax/src/tests/sourcegen_ast.rs20
30 files changed, 465 insertions, 265 deletions
diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs
index 6a2ac15465f..038032e05d8 100644
--- a/crates/hir-def/src/body/lower.rs
+++ b/crates/hir-def/src/body/lower.rs
@@ -30,8 +30,8 @@ use crate::{
     expander::Expander,
     hir::{
         dummy_expr_id, Array, Binding, BindingAnnotation, BindingId, BindingProblems, CaptureBy,
-        ClosureKind, Expr, ExprId, Label, LabelId, Literal, LiteralOrConst, MatchArm, Movability,
-        Pat, PatId, RecordFieldPat, RecordLitField, Statement,
+        ClosureKind, Expr, ExprId, InlineAsm, Label, LabelId, Literal, LiteralOrConst, MatchArm,
+        Movability, OffsetOf, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
     },
     item_scope::BuiltinShadowMode,
     lang_item::LangItem,
@@ -579,11 +579,6 @@ impl ExprCollector<'_> {
                     syntax_ptr,
                 )
             }
-            ast::Expr::BoxExpr(e) => {
-                let expr = self.collect_expr_opt(e.expr());
-                self.alloc_expr(Expr::Box { expr }, syntax_ptr)
-            }
-
             ast::Expr::ArrayExpr(e) => {
                 let kind = e.kind();
 
@@ -653,6 +648,16 @@ impl ExprCollector<'_> {
                 }
             }
             ast::Expr::UnderscoreExpr(_) => self.alloc_expr(Expr::Underscore, syntax_ptr),
+            ast::Expr::AsmExpr(e) => {
+                let expr = Expr::InlineAsm(InlineAsm { e: self.collect_expr_opt(e.expr()) });
+                self.alloc_expr(expr, syntax_ptr)
+            }
+            ast::Expr::OffsetOfExpr(e) => {
+                let container = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty()));
+                let fields = e.fields().map(|it| it.as_name()).collect();
+                self.alloc_expr(Expr::OffsetOf(OffsetOf { container, fields }), syntax_ptr)
+            }
+            ast::Expr::FormatArgsExpr(_) => self.missing_expr(),
         })
     }
 
@@ -663,6 +668,7 @@ impl ExprCollector<'_> {
         let result_expr_id = self.alloc_expr(Expr::Missing, syntax_ptr);
         let prev_binding_owner = self.current_binding_owner.take();
         self.current_binding_owner = Some(result_expr_id);
+
         (result_expr_id, prev_binding_owner)
     }
 
diff --git a/crates/hir-def/src/body/pretty.rs b/crates/hir-def/src/body/pretty.rs
index 5d71abe37cc..602a7983c7c 100644
--- a/crates/hir-def/src/body/pretty.rs
+++ b/crates/hir-def/src/body/pretty.rs
@@ -3,6 +3,7 @@
 use std::fmt::{self, Write};
 
 use hir_expand::db::ExpandDatabase;
+use itertools::Itertools;
 use syntax::ast::HasName;
 
 use crate::{
@@ -154,6 +155,16 @@ impl Printer<'_> {
         match expr {
             Expr::Missing => w!(self, "�"),
             Expr::Underscore => w!(self, "_"),
+            Expr::InlineAsm(_) => w!(self, "builtin#asm(_)"),
+            Expr::OffsetOf(offset_of) => {
+                w!(self, "builtin#offset_of(");
+                self.print_type_ref(&offset_of.container);
+                w!(
+                    self,
+                    ", {})",
+                    offset_of.fields.iter().format_with(".", |field, f| f(&field.display(self.db)))
+                );
+            }
             Expr::Path(path) => self.print_path(path),
             Expr::If { condition, then_branch, else_branch } => {
                 w!(self, "if ");
diff --git a/crates/hir-def/src/hir.rs b/crates/hir-def/src/hir.rs
index 6591c92ac62..1c86af456d1 100644
--- a/crates/hir-def/src/hir.rs
+++ b/crates/hir-def/src/hir.rs
@@ -281,6 +281,19 @@ pub enum Expr {
     Array(Array),
     Literal(Literal),
     Underscore,
+    OffsetOf(OffsetOf),
+    InlineAsm(InlineAsm),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct OffsetOf {
+    pub container: Interned<TypeRef>,
+    pub fields: Box<[Name]>,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct InlineAsm {
+    pub e: ExprId,
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -341,7 +354,8 @@ impl Expr {
     pub fn walk_child_exprs(&self, mut f: impl FnMut(ExprId)) {
         match self {
             Expr::Missing => {}
-            Expr::Path(_) => {}
+            Expr::Path(_) | Expr::OffsetOf(_) => {}
+            Expr::InlineAsm(e) => f(e.e),
             Expr::If { condition, then_branch, else_branch } => {
                 f(*condition);
                 f(*then_branch);
diff --git a/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
index b232651db96..a350511c7a1 100644
--- a/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
+++ b/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
@@ -23,6 +23,45 @@ fn main() { 0 as u32; }
 }
 
 #[test]
+fn test_asm_expand() {
+    check(
+        r#"
+#[rustc_builtin_macro]
+macro_rules! asm {() => {}}
+
+fn main() {
+    let i: u64 = 3;
+    let o: u64;
+    unsafe {
+        asm!(
+            "mov {0}, {1}",
+            "add {0}, 5",
+            out(reg) o,
+            in(reg) i,
+        );
+    }
+}
+"#,
+        expect![[r##"
+#[rustc_builtin_macro]
+macro_rules! asm {() => {}}
+
+fn main() {
+    let i: u64 = 3;
+    let o: u64;
+    unsafe {
+        builtin #asm ( {
+            $crate::format_args!("mov {0}, {1}");
+            $crate::format_args!("add {0}, 5");
+        }
+        );
+    }
+}
+"##]],
+    );
+}
+
+#[test]
 fn test_line_expand() {
     check(
         r#"
diff --git a/crates/hir-expand/src/builtin_fn_macro.rs b/crates/hir-expand/src/builtin_fn_macro.rs
index 6a48acef963..00ee5e8b9d0 100644
--- a/crates/hir-expand/src/builtin_fn_macro.rs
+++ b/crates/hir-expand/src/builtin_fn_macro.rs
@@ -399,6 +399,8 @@ fn asm_expand(
     _id: MacroCallId,
     tt: &tt::Subtree,
 ) -> ExpandResult<tt::Subtree> {
+    // FIXME: parse asm here
+
     // We expand all assembly snippets to `format_args!` invocations to get format syntax
     // highlighting for them.
 
@@ -415,10 +417,12 @@ fn asm_expand(
         }
     }
 
-    let expanded = quote! {{
-        ##literals
-        loop {}
-    }};
+    let pound = quote! {@PUNCT '#'};
+    let expanded = quote! {
+        builtin #pound asm (
+            {##literals}
+        )
+    };
     ExpandResult::ok(expanded)
 }
 
diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs
index 23efe616f4f..1f040393f1f 100644
--- a/crates/hir-ty/src/infer/closure.rs
+++ b/crates/hir-ty/src/infer/closure.rs
@@ -452,6 +452,8 @@ impl InferenceContext<'_> {
 
     fn walk_expr_without_adjust(&mut self, tgt_expr: ExprId) {
         match &self.body[tgt_expr] {
+            Expr::OffsetOf(_) => (),
+            Expr::InlineAsm(e) => self.walk_expr_without_adjust(e.e),
             Expr::If { condition, then_branch, else_branch } => {
                 self.consume_expr(*condition);
                 self.consume_expr(*then_branch);
@@ -620,6 +622,7 @@ impl InferenceContext<'_> {
             | Expr::Tuple { exprs, is_assignee_expr: _ } => {
                 self.consume_exprs(exprs.iter().copied())
             }
+
             Expr::Missing
             | Expr::Continue { .. }
             | Expr::Path(_)
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index 8b352141084..555a9fae48e 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -843,6 +843,11 @@ impl InferenceContext<'_> {
                 });
                 expected
             }
+            Expr::OffsetOf(_) => TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner),
+            Expr::InlineAsm(it) => {
+                self.infer_expr_no_expect(it.e);
+                self.result.standard_types.unit.clone()
+            }
         };
         // use a new type variable if we got unknown here
         let ty = self.insert_type_vars_shallow(ty);
diff --git a/crates/hir-ty/src/infer/mutability.rs b/crates/hir-ty/src/infer/mutability.rs
index 396ca0044ff..b8a1af96fba 100644
--- a/crates/hir-ty/src/infer/mutability.rs
+++ b/crates/hir-ty/src/infer/mutability.rs
@@ -35,6 +35,8 @@ impl InferenceContext<'_> {
     fn infer_mut_expr_without_adjust(&mut self, tgt_expr: ExprId, mutability: Mutability) {
         match &self.body[tgt_expr] {
             Expr::Missing => (),
+            Expr::InlineAsm(e) => self.infer_mut_expr_without_adjust(e.e, Mutability::Not),
+            Expr::OffsetOf(_) => (),
             &Expr::If { condition, then_branch, else_branch } => {
                 self.infer_mut_expr(condition, Mutability::Not);
                 self.infer_mut_expr(then_branch, Mutability::Not);
diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs
index 7c15aa42fd2..b6408cea502 100644
--- a/crates/hir-ty/src/mir/lower.rs
+++ b/crates/hir-ty/src/mir/lower.rs
@@ -370,6 +370,12 @@ impl<'ctx> MirLowerCtx<'ctx> {
         mut current: BasicBlockId,
     ) -> Result<Option<BasicBlockId>> {
         match &self.body.exprs[expr_id] {
+            Expr::OffsetOf(_) => {
+                not_supported!("builtin#offset_of")
+            }
+            Expr::InlineAsm(_) => {
+                not_supported!("builtin#asm")
+            }
             Expr::Missing => {
                 if let DefWithBodyId::FunctionId(f) = self.owner {
                     let assoc = f.lookup(self.db.upcast());
diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs
index 2ad7946c8ac..e7cb7cd4174 100644
--- a/crates/hir-ty/src/tests/simple.rs
+++ b/crates/hir-ty/src/tests/simple.rs
@@ -3,55 +3,6 @@ use expect_test::expect;
 use super::{check, check_infer, check_no_mismatches, check_types};
 
 #[test]
-fn infer_box() {
-    check_types(
-        r#"
-//- /main.rs crate:main deps:std
-fn test() {
-    let x = box 1;
-    let t = (x, box x, box &1, box [1]);
-    t;
-} //^ (Box<i32>, Box<Box<i32>>, Box<&i32>, Box<[i32; 1]>)
-
-//- /std.rs crate:std
-#[prelude_import] use prelude::*;
-mod prelude {}
-
-mod boxed {
-    #[lang = "owned_box"]
-    pub struct Box<T: ?Sized> {
-        inner: *mut T,
-    }
-}
-"#,
-    );
-}
-
-#[test]
-fn infer_box_with_allocator() {
-    check_types(
-        r#"
-//- /main.rs crate:main deps:std
-fn test() {
-    let x = box 1;
-    let t = (x, box x, box &1, box [1]);
-    t;
-} //^ (Box<i32, {unknown}>, Box<Box<i32, {unknown}>, {unknown}>, Box<&i32, {unknown}>, Box<[i32; 1], {unknown}>)
-
-//- /std.rs crate:std
-#[prelude_import] use prelude::*;
-mod boxed {
-    #[lang = "owned_box"]
-    pub struct Box<T: ?Sized, A: Allocator> {
-        inner: *mut T,
-        allocator: A,
-    }
-}
-"#,
-    );
-}
-
-#[test]
 fn infer_adt_self() {
     check_types(
         r#"
@@ -2763,8 +2714,8 @@ impl<T> [T] {
 }
 
 fn test() {
-    let vec = <[_]>::into_vec(box [1i32]);
-    let v: Vec<Box<dyn B>> = <[_]> :: into_vec(box [box Astruct]);
+    let vec = <[_]>::into_vec(#[rustc_box] Box::new([1i32]));
+    let v: Vec<Box<dyn B>> = <[_]> :: into_vec(#[rustc_box] Box::new([#[rustc_box] Box::new(Astruct)]));
 }
 
 trait B{}
@@ -2774,20 +2725,20 @@ impl B for Astruct {}
         expect![[r#"
             604..608 'self': Box<[T], A>
             637..669 '{     ...     }': Vec<T, A>
-            683..796 '{     ...t]); }': ()
+            683..853 '{     ...])); }': ()
             693..696 'vec': Vec<i32, Global>
             699..714 '<[_]>::into_vec': fn into_vec<i32, Global>(Box<[i32], Global>) -> Vec<i32, Global>
-            699..726 '<[_]>:...1i32])': Vec<i32, Global>
-            715..725 'box [1i32]': Box<[i32; 1], Global>
-            719..725 '[1i32]': [i32; 1]
-            720..724 '1i32': i32
-            736..737 'v': Vec<Box<dyn B, Global>, Global>
-            757..774 '<[_]> ...to_vec': fn into_vec<Box<dyn B, Global>, Global>(Box<[Box<dyn B, Global>], Global>) -> Vec<Box<dyn B, Global>, Global>
-            757..793 '<[_]> ...ruct])': Vec<Box<dyn B, Global>, Global>
-            775..792 'box [b...truct]': Box<[Box<dyn B, Global>; 1], Global>
-            779..792 '[box Astruct]': [Box<dyn B, Global>; 1]
-            780..791 'box Astruct': Box<Astruct, Global>
-            784..791 'Astruct': Astruct
+            699..745 '<[_]>:...i32]))': Vec<i32, Global>
+            715..744 '#[rust...1i32])': Box<[i32; 1], Global>
+            737..743 '[1i32]': [i32; 1]
+            738..742 '1i32': i32
+            755..756 'v': Vec<Box<dyn B, Global>, Global>
+            776..793 '<[_]> ...to_vec': fn into_vec<Box<dyn B, Global>, Global>(Box<[Box<dyn B, Global>], Global>) -> Vec<Box<dyn B, Global>, Global>
+            776..850 '<[_]> ...ct)]))': Vec<Box<dyn B, Global>, Global>
+            794..849 '#[rust...uct)])': Box<[Box<dyn B, Global>; 1], Global>
+            816..848 '[#[rus...ruct)]': [Box<dyn B, Global>; 1]
+            817..847 '#[rust...truct)': Box<Astruct, Global>
+            839..846 'Astruct': Astruct
         "#]],
     )
 }
@@ -3649,3 +3600,15 @@ fn main() {
 "#,
     );
 }
+
+#[test]
+fn offset_of() {
+    check_types(
+        r#"
+fn main() {
+    builtin#offset_of((,), 0);
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^ usize
+}
+"#,
+    );
+}
diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs
index 542df8b3468..d36b885ec14 100644
--- a/crates/hir-ty/src/tests/traits.rs
+++ b/crates/hir-ty/src/tests/traits.rs
@@ -162,16 +162,16 @@ unsafe impl Allocator for Global {}
 
 #[lang = "owned_box"]
 #[fundamental]
-pub struct Box<T: ?Sized, A: Allocator = Global>;
+pub struct Box<T: ?Sized, A: Allocator = Global>(T);
 
 impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Box<U, A>> for Box<T, A> {}
 
 fn send() ->  Box<dyn Future<Output = ()> + Send + 'static>{
-    box async move {}
+    Box(async move {})
 }
 
 fn not_send() -> Box<dyn Future<Output = ()> + 'static> {
-    box async move {}
+    Box(async move {})
 }
     "#,
     );
@@ -3057,7 +3057,7 @@ impl<T: ?Sized> core::ops::Deref for Box<T> {
 
 fn foo() {
     let s = None;
-    let f: Box<dyn FnOnce(&Option<i32>)> = box (|ps| {});
+    let f: Box<dyn FnOnce(&Option<i32>)> = Box { inner: &mut (|ps| {}) };
     f(&s);
 }"#,
         expect![[r#"
@@ -3068,19 +3068,19 @@ fn foo() {
             186..197 '*self.inner': T
             187..191 'self': &Box<T>
             187..197 'self.inner': *mut T
-            218..308 '{     ...&s); }': ()
+            218..324 '{     ...&s); }': ()
             228..229 's': Option<i32>
             232..236 'None': Option<i32>
             246..247 'f': Box<dyn FnOnce(&Option<i32>)>
-            281..294 'box (|ps| {})': Box<impl Fn(&Option<i32>)>
-            286..293 '|ps| {}': impl Fn(&Option<i32>)
-            287..289 'ps': &Option<i32>
-            291..293 '{}': ()
-            300..301 'f': Box<dyn FnOnce(&Option<i32>)>
-            300..305 'f(&s)': ()
-            302..304 '&s': &Option<i32>
-            303..304 's': Option<i32>
-            281..294: expected Box<dyn FnOnce(&Option<i32>)>, got Box<impl Fn(&Option<i32>)>
+            281..310 'Box { ... {}) }': Box<dyn FnOnce(&Option<i32>)>
+            294..308 '&mut (|ps| {})': &mut impl Fn(&Option<i32>)
+            300..307 '|ps| {}': impl Fn(&Option<i32>)
+            301..303 'ps': &Option<i32>
+            305..307 '{}': ()
+            316..317 'f': Box<dyn FnOnce(&Option<i32>)>
+            316..321 'f(&s)': ()
+            318..320 '&s': &Option<i32>
+            319..320 's': Option<i32>
         "#]],
     );
 }
diff --git a/crates/ide-assists/src/handlers/convert_bool_then.rs b/crates/ide-assists/src/handlers/convert_bool_then.rs
index 1af52c59218..d231708c55b 100644
--- a/crates/ide-assists/src/handlers/convert_bool_then.rs
+++ b/crates/ide-assists/src/handlers/convert_bool_then.rs
@@ -103,7 +103,6 @@ pub(crate) fn convert_if_to_bool_then(acc: &mut Assists, ctx: &AssistContext<'_>
                 cond,
                 ast::Expr::BinExpr(_)
                     | ast::Expr::BlockExpr(_)
-                    | ast::Expr::BoxExpr(_)
                     | ast::Expr::BreakExpr(_)
                     | ast::Expr::CastExpr(_)
                     | ast::Expr::ClosureExpr(_)
diff --git a/crates/ide-assists/src/handlers/promote_local_to_const.rs b/crates/ide-assists/src/handlers/promote_local_to_const.rs
index 5cc110cf12b..6fc2aa49974 100644
--- a/crates/ide-assists/src/handlers/promote_local_to_const.rs
+++ b/crates/ide-assists/src/handlers/promote_local_to_const.rs
@@ -120,8 +120,7 @@ fn is_body_const(sema: &Semantics<'_, RootDatabase>, expr: &ast::Expr) -> bool {
                 is_const &=
                     sema.resolve_method_call(&call).map(|it| it.is_const(sema.db)).unwrap_or(true)
             }
-            ast::Expr::BoxExpr(_)
-            | ast::Expr::ForExpr(_)
+            ast::Expr::ForExpr(_)
             | ast::Expr::ReturnExpr(_)
             | ast::Expr::TryExpr(_)
             | ast::Expr::YieldExpr(_)
diff --git a/crates/ide-assists/src/handlers/remove_dbg.rs b/crates/ide-assists/src/handlers/remove_dbg.rs
index e2b82223289..cffa3f55c90 100644
--- a/crates/ide-assists/src/handlers/remove_dbg.rs
+++ b/crates/ide-assists/src/handlers/remove_dbg.rs
@@ -113,10 +113,7 @@ fn compute_dbg_replacement(macro_expr: ast::MacroExpr) -> Option<(TextRange, Opt
                 Some(parent) => match (expr, parent) {
                     (ast::Expr::CastExpr(_), ast::Expr::CastExpr(_)) => false,
                     (
-                        ast::Expr::BoxExpr(_)
-                        | ast::Expr::PrefixExpr(_)
-                        | ast::Expr::RefExpr(_)
-                        | ast::Expr::MacroExpr(_),
+                        ast::Expr::PrefixExpr(_) | ast::Expr::RefExpr(_) | ast::Expr::MacroExpr(_),
                         ast::Expr::AwaitExpr(_)
                         | ast::Expr::CallExpr(_)
                         | ast::Expr::CastExpr(_)
diff --git a/crates/ide-assists/src/utils/suggest_name.rs b/crates/ide-assists/src/utils/suggest_name.rs
index f74ebfae02c..16704d598ef 100644
--- a/crates/ide-assists/src/utils/suggest_name.rs
+++ b/crates/ide-assists/src/utils/suggest_name.rs
@@ -103,7 +103,6 @@ pub(crate) fn for_variable(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>)
 
         match expr {
             ast::Expr::RefExpr(inner) => next_expr = inner.expr(),
-            ast::Expr::BoxExpr(inner) => next_expr = inner.expr(),
             ast::Expr::AwaitExpr(inner) => next_expr = inner.expr(),
             // ast::Expr::BlockExpr(block) => expr = block.tail_expr(),
             ast::Expr::CastExpr(inner) => next_expr = inner.expr(),
diff --git a/crates/ide-db/src/syntax_helpers/node_ext.rs b/crates/ide-db/src/syntax_helpers/node_ext.rs
index 22ced69d81e..e4e735cecd8 100644
--- a/crates/ide-db/src/syntax_helpers/node_ext.rs
+++ b/crates/ide-db/src/syntax_helpers/node_ext.rs
@@ -312,7 +312,6 @@ pub fn for_each_tail_expr(expr: &ast::Expr, cb: &mut dyn FnMut(&ast::Expr)) {
         ast::Expr::ArrayExpr(_)
         | ast::Expr::AwaitExpr(_)
         | ast::Expr::BinExpr(_)
-        | ast::Expr::BoxExpr(_)
         | ast::Expr::BreakExpr(_)
         | ast::Expr::CallExpr(_)
         | ast::Expr::CastExpr(_)
@@ -335,7 +334,10 @@ pub fn for_each_tail_expr(expr: &ast::Expr, cb: &mut dyn FnMut(&ast::Expr)) {
         | ast::Expr::LetExpr(_)
         | ast::Expr::UnderscoreExpr(_)
         | ast::Expr::YieldExpr(_)
-        | ast::Expr::YeetExpr(_) => cb(expr),
+        | ast::Expr::YeetExpr(_)
+        | ast::Expr::OffsetOfExpr(_)
+        | ast::Expr::FormatArgsExpr(_)
+        | ast::Expr::AsmExpr(_) => cb(expr),
     }
 }
 
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
index 3ac8aa9cc9d..9c5c6d50ea7 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
@@ -176,7 +176,15 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="macro">assert</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="bool_literal macro">true</span><span class="comma macro">,</span> <span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
     <span class="macro">assert</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="bool_literal macro">true</span><span class="comma macro">,</span> <span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> asdasd"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
     <span class="macro">toho</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">fmt"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro unsafe">asm</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"mov eax, </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="keyword">let</span> <span class="variable declaration">i</span><span class="colon">:</span> <span class="builtin_type">u64</span> <span class="operator">=</span> <span class="numeric_literal">3</span><span class="semicolon">;</span>
+    <span class="keyword">let</span> <span class="variable declaration">o</span><span class="colon">:</span> <span class="builtin_type">u64</span><span class="semicolon">;</span>
+    <span class="macro unsafe">asm</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span>
+        <span class="string_literal macro">"mov </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal macro">, </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span>
+        <span class="string_literal macro">"add </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal macro">, 5"</span><span class="comma macro">,</span>
+        <span class="none macro">out</span><span class="parenthesis macro">(</span><span class="none macro">reg</span><span class="parenthesis macro">)</span> <span class="none macro">o</span><span class="comma macro">,</span>
+        <span class="keyword control macro">in</span><span class="parenthesis macro">(</span><span class="none macro">reg</span><span class="parenthesis macro">)</span> <span class="none macro">i</span><span class="comma macro">,</span>
+    <span class="parenthesis macro">)</span><span class="semicolon">;</span>
+
     <span class="macro">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">concat</span><span class="punctuation macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="string_literal macro">"{}"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
     <span class="macro">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable macro reference">backslash</span><span class="comma macro">,</span> <span class="none macro">format_args</span><span class="punctuation macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="unresolved_reference macro">foo</span><span class="comma macro">,</span> <span class="string_literal macro">"bar"</span><span class="comma macro">,</span> <span class="none macro">toho</span><span class="punctuation macro">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="variable macro reference">backslash</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
 <span class="brace">}</span></code></pre>
\ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index 8749d355c85..aacd57af589 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -534,7 +534,15 @@ fn main() {
     assert!(true, "{}", 1);
     assert!(true, "{} asdasd", 1);
     toho!("{}fmt", 0);
-    asm!("mov eax, {0}");
+    let i: u64 = 3;
+    let o: u64;
+    asm!(
+        "mov {0}, {1}",
+        "add {0}, 5",
+        out(reg) o,
+        in(reg) i,
+    );
+
     format_args!(concat!("{}"), "{}");
     format_args!("{} {} {} {} {} {}", backslash, format_args!("{}", 0), foo, "bar", toho!(), backslash);
 }"#,
diff --git a/crates/parser/src/grammar/expressions/atom.rs b/crates/parser/src/grammar/expressions/atom.rs
index d8553d3f953..e13284d1b7a 100644
--- a/crates/parser/src/grammar/expressions/atom.rs
+++ b/crates/parser/src/grammar/expressions/atom.rs
@@ -1,3 +1,5 @@
+use crate::grammar::types::type_;
+
 use super::*;
 
 // test expr_literals
@@ -73,6 +75,9 @@ pub(super) fn atom_expr(
     if let Some(m) = literal(p) {
         return Some((m, BlockLike::NotBlock));
     }
+    if p.at_contextual_kw(T![builtin]) && p.nth_at(1, T![#]) {
+        return Some((builtin_expr(p)?, BlockLike::NotBlock));
+    }
     if paths::is_path_start(p) {
         return Some(path_expr(p, r));
     }
@@ -93,7 +98,6 @@ pub(super) fn atom_expr(
             m.complete(p, UNDERSCORE_EXPR)
         }
         T![loop] => loop_expr(p, None),
-        T![box] => box_expr(p, None),
         T![while] => while_expr(p, None),
         T![try] => try_block_expr(p, None),
         T![match] => match_expr(p),
@@ -212,6 +216,54 @@ fn tuple_expr(p: &mut Parser<'_>) -> CompletedMarker {
     m.complete(p, if saw_expr && !saw_comma { PAREN_EXPR } else { TUPLE_EXPR })
 }
 
+// test builtin_expr
+// fn foo() {
+//     builtin#asm(0);
+//     builtin#format_args(0);
+//     builtin#offset_of(Foo, bar.baz.0);
+// }
+fn builtin_expr(p: &mut Parser<'_>) -> Option<CompletedMarker> {
+    let m = p.start();
+    p.bump_remap(T![builtin]);
+    p.bump(T![#]);
+    if p.at_contextual_kw(T![offset_of]) {
+        p.bump_remap(T![offset_of]);
+        p.expect(T!['(']);
+        type_(p);
+        p.expect(T![,]);
+        while !p.at(EOF) && !p.at(T![')']) {
+            if p.at(IDENT) || p.at(INT_NUMBER) {
+                name_ref_or_index(p);
+            // } else if p.at(FLOAT_NUMBER) {
+            // FIXME: needs float hack
+            } else {
+                p.err_and_bump("expected field name or number");
+            }
+            if !p.at(T![')']) {
+                p.expect(T![.]);
+            }
+        }
+        p.expect(T![')']);
+        Some(m.complete(p, OFFSET_OF_EXPR))
+    } else if p.at_contextual_kw(T![format_args]) {
+        p.bump_remap(T![format_args]);
+        p.expect(T!['(']);
+        expr(p);
+        p.expect(T![')']);
+        Some(m.complete(p, FORMAT_ARGS_EXPR))
+    } else if p.at_contextual_kw(T![asm]) {
+        p.bump_remap(T![asm]);
+        p.expect(T!['(']);
+        // FIXME: We just put expression here so highlighting kind of keeps working
+        expr(p);
+        p.expect(T![')']);
+        Some(m.complete(p, ASM_EXPR))
+    } else {
+        m.abandon(p);
+        None
+    }
+}
+
 // test array_expr
 // fn foo() {
 //     [];
@@ -662,19 +714,3 @@ fn try_block_expr(p: &mut Parser<'_>, m: Option<Marker>) -> CompletedMarker {
     }
     m.complete(p, BLOCK_EXPR)
 }
-
-// test box_expr
-// fn foo() {
-//     let x = box 1i32;
-//     let y = (box 1i32, box 2i32);
-//     let z = Foo(box 1i32, box 2i32);
-// }
-fn box_expr(p: &mut Parser<'_>, m: Option<Marker>) -> CompletedMarker {
-    assert!(p.at(T![box]));
-    let m = m.unwrap_or_else(|| p.start());
-    p.bump(T![box]);
-    if p.at_ts(EXPR_FIRST) {
-        expr(p);
-    }
-    m.complete(p, BOX_EXPR)
-}
diff --git a/crates/parser/src/lexed_str.rs b/crates/parser/src/lexed_str.rs
index e4dce21f32a..36c52953a02 100644
--- a/crates/parser/src/lexed_str.rs
+++ b/crates/parser/src/lexed_str.rs
@@ -221,6 +221,7 @@ impl<'a> Converter<'a> {
                 rustc_lexer::TokenKind::Caret => T![^],
                 rustc_lexer::TokenKind::Percent => T![%],
                 rustc_lexer::TokenKind::Unknown => ERROR,
+                rustc_lexer::TokenKind::UnknownPrefix if token_text == "builtin" => IDENT,
                 rustc_lexer::TokenKind::UnknownPrefix => {
                     err = "unknown literal prefix";
                     IDENT
diff --git a/crates/parser/src/syntax_kind/generated.rs b/crates/parser/src/syntax_kind/generated.rs
index 48f407623d8..3e31e4628bd 100644
--- a/crates/parser/src/syntax_kind/generated.rs
+++ b/crates/parser/src/syntax_kind/generated.rs
@@ -105,12 +105,16 @@ pub enum SyntaxKind {
     WHILE_KW,
     YIELD_KW,
     AUTO_KW,
+    BUILTIN_KW,
     DEFAULT_KW,
     EXISTENTIAL_KW,
     UNION_KW,
     RAW_KW,
     MACRO_RULES_KW,
     YEET_KW,
+    OFFSET_OF_KW,
+    ASM_KW,
+    FORMAT_ARGS_KW,
     INT_NUMBER,
     FLOAT_NUMBER,
     CHAR,
@@ -203,7 +207,9 @@ pub enum SyntaxKind {
     RECORD_EXPR,
     RECORD_EXPR_FIELD_LIST,
     RECORD_EXPR_FIELD,
-    BOX_EXPR,
+    OFFSET_OF_EXPR,
+    ASM_EXPR,
+    FORMAT_ARGS_EXPR,
     CALL_EXPR,
     INDEX_EXPR,
     METHOD_CALL_EXPR,
@@ -315,12 +321,16 @@ impl SyntaxKind {
                 | WHILE_KW
                 | YIELD_KW
                 | AUTO_KW
+                | BUILTIN_KW
                 | DEFAULT_KW
                 | EXISTENTIAL_KW
                 | UNION_KW
                 | RAW_KW
                 | MACRO_RULES_KW
                 | YEET_KW
+                | OFFSET_OF_KW
+                | ASM_KW
+                | FORMAT_ARGS_KW
         )
     }
     pub fn is_punct(self) -> bool {
@@ -435,12 +445,16 @@ impl SyntaxKind {
     pub fn from_contextual_keyword(ident: &str) -> Option<SyntaxKind> {
         let kw = match ident {
             "auto" => AUTO_KW,
+            "builtin" => BUILTIN_KW,
             "default" => DEFAULT_KW,
             "existential" => EXISTENTIAL_KW,
             "union" => UNION_KW,
             "raw" => RAW_KW,
             "macro_rules" => MACRO_RULES_KW,
             "yeet" => YEET_KW,
+            "offset_of" => OFFSET_OF_KW,
+            "asm" => ASM_KW,
+            "format_args" => FORMAT_ARGS_KW,
             _ => return None,
         };
         Some(kw)
@@ -481,5 +495,5 @@ impl SyntaxKind {
     }
 }
 #[macro_export]
-macro_rules ! T { [;] => { $ crate :: SyntaxKind :: SEMICOLON } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: SyntaxKind :: R_CURLY } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; [<] => { $ crate :: SyntaxKind :: L_ANGLE } ; [>] => { $ crate :: SyntaxKind :: R_ANGLE } ; [@] => { $ crate :: SyntaxKind :: AT } ; [#] => { $ crate :: SyntaxKind :: POUND } ; [~] => { $ crate :: SyntaxKind :: TILDE } ; [?] => { $ crate :: SyntaxKind :: QUESTION } ; [$] => { $ crate :: SyntaxKind :: DOLLAR } ; [&] => { $ crate :: SyntaxKind :: AMP } ; [|] => { $ crate :: SyntaxKind :: PIPE } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [*] => { $ crate :: SyntaxKind :: STAR } ; [/] => { $ crate :: SyntaxKind :: SLASH } ; [^] => { $ crate :: SyntaxKind :: CARET } ; [%] => { $ crate :: SyntaxKind :: PERCENT } ; [_] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [..] => { $ crate :: SyntaxKind :: DOT2 } ; [...] => { $ crate :: SyntaxKind :: DOT3 } ; [..=] => { $ crate :: SyntaxKind :: DOT2EQ } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLON2 } ; [=] => { $ crate :: SyntaxKind :: EQ } ; [==] => { $ crate :: SyntaxKind :: EQ2 } ; [=>] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: SyntaxKind :: BANG } ; [!=] => { $ crate :: SyntaxKind :: NEQ } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [->] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [<=] => { $ crate :: SyntaxKind :: LTEQ } ; [>=] => { $ crate :: SyntaxKind :: GTEQ } ; [+=] => { $ crate :: SyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: SyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: SyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: SyntaxKind :: AMPEQ } ; [^=] => { $ crate :: SyntaxKind :: CARETEQ } ; [/=] => { $ crate :: SyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: SyntaxKind :: STAREQ } ; [%=] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: SyntaxKind :: AMP2 } ; [||] => { $ crate :: SyntaxKind :: PIPE2 } ; [<<] => { $ crate :: SyntaxKind :: SHL } ; [>>] => { $ crate :: SyntaxKind :: SHR } ; [<<=] => { $ crate :: SyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: SyntaxKind :: SHREQ } ; [as] => { $ crate :: SyntaxKind :: AS_KW } ; [async] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [box] => { $ crate :: SyntaxKind :: BOX_KW } ; [break] => { $ crate :: SyntaxKind :: BREAK_KW } ; [const] => { $ crate :: SyntaxKind :: CONST_KW } ; [continue] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [crate] => { $ crate :: SyntaxKind :: CRATE_KW } ; [do] => { $ crate :: SyntaxKind :: DO_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: SyntaxKind :: ENUM_KW } ; [extern] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [fn] => { $ crate :: SyntaxKind :: FN_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [impl] => { $ crate :: SyntaxKind :: IMPL_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [let] => { $ crate :: SyntaxKind :: LET_KW } ; [loop] => { $ crate :: SyntaxKind :: LOOP_KW } ; [macro] => { $ crate :: SyntaxKind :: MACRO_KW } ; [match] => { $ crate :: SyntaxKind :: MATCH_KW } ; [mod] => { $ crate :: SyntaxKind :: MOD_KW } ; [move] => { $ crate :: SyntaxKind :: MOVE_KW } ; [mut] => { $ crate :: SyntaxKind :: MUT_KW } ; [pub] => { $ crate :: SyntaxKind :: PUB_KW } ; [ref] => { $ crate :: SyntaxKind :: REF_KW } ; [return] => { $ crate :: SyntaxKind :: RETURN_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [Self] => { $ crate :: SyntaxKind :: SELF_TYPE_KW } ; [static] => { $ crate :: SyntaxKind :: STATIC_KW } ; [struct] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [trait] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [try] => { $ crate :: SyntaxKind :: TRY_KW } ; [type] => { $ crate :: SyntaxKind :: TYPE_KW } ; [unsafe] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [use] => { $ crate :: SyntaxKind :: USE_KW } ; [where] => { $ crate :: SyntaxKind :: WHERE_KW } ; [while] => { $ crate :: SyntaxKind :: WHILE_KW } ; [yield] => { $ crate :: SyntaxKind :: YIELD_KW } ; [auto] => { $ crate :: SyntaxKind :: AUTO_KW } ; [default] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [existential] => { $ crate :: SyntaxKind :: EXISTENTIAL_KW } ; [union] => { $ crate :: SyntaxKind :: UNION_KW } ; [raw] => { $ crate :: SyntaxKind :: RAW_KW } ; [macro_rules] => { $ crate :: SyntaxKind :: MACRO_RULES_KW } ; [yeet] => { $ crate :: SyntaxKind :: YEET_KW } ; [lifetime_ident] => { $ crate :: SyntaxKind :: LIFETIME_IDENT } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; }
+macro_rules ! T { [;] => { $ crate :: SyntaxKind :: SEMICOLON } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: SyntaxKind :: R_CURLY } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; [<] => { $ crate :: SyntaxKind :: L_ANGLE } ; [>] => { $ crate :: SyntaxKind :: R_ANGLE } ; [@] => { $ crate :: SyntaxKind :: AT } ; [#] => { $ crate :: SyntaxKind :: POUND } ; [~] => { $ crate :: SyntaxKind :: TILDE } ; [?] => { $ crate :: SyntaxKind :: QUESTION } ; [$] => { $ crate :: SyntaxKind :: DOLLAR } ; [&] => { $ crate :: SyntaxKind :: AMP } ; [|] => { $ crate :: SyntaxKind :: PIPE } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [*] => { $ crate :: SyntaxKind :: STAR } ; [/] => { $ crate :: SyntaxKind :: SLASH } ; [^] => { $ crate :: SyntaxKind :: CARET } ; [%] => { $ crate :: SyntaxKind :: PERCENT } ; [_] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [..] => { $ crate :: SyntaxKind :: DOT2 } ; [...] => { $ crate :: SyntaxKind :: DOT3 } ; [..=] => { $ crate :: SyntaxKind :: DOT2EQ } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLON2 } ; [=] => { $ crate :: SyntaxKind :: EQ } ; [==] => { $ crate :: SyntaxKind :: EQ2 } ; [=>] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: SyntaxKind :: BANG } ; [!=] => { $ crate :: SyntaxKind :: NEQ } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [->] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [<=] => { $ crate :: SyntaxKind :: LTEQ } ; [>=] => { $ crate :: SyntaxKind :: GTEQ } ; [+=] => { $ crate :: SyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: SyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: SyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: SyntaxKind :: AMPEQ } ; [^=] => { $ crate :: SyntaxKind :: CARETEQ } ; [/=] => { $ crate :: SyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: SyntaxKind :: STAREQ } ; [%=] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: SyntaxKind :: AMP2 } ; [||] => { $ crate :: SyntaxKind :: PIPE2 } ; [<<] => { $ crate :: SyntaxKind :: SHL } ; [>>] => { $ crate :: SyntaxKind :: SHR } ; [<<=] => { $ crate :: SyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: SyntaxKind :: SHREQ } ; [as] => { $ crate :: SyntaxKind :: AS_KW } ; [async] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [box] => { $ crate :: SyntaxKind :: BOX_KW } ; [break] => { $ crate :: SyntaxKind :: BREAK_KW } ; [const] => { $ crate :: SyntaxKind :: CONST_KW } ; [continue] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [crate] => { $ crate :: SyntaxKind :: CRATE_KW } ; [do] => { $ crate :: SyntaxKind :: DO_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: SyntaxKind :: ENUM_KW } ; [extern] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [fn] => { $ crate :: SyntaxKind :: FN_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [impl] => { $ crate :: SyntaxKind :: IMPL_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [let] => { $ crate :: SyntaxKind :: LET_KW } ; [loop] => { $ crate :: SyntaxKind :: LOOP_KW } ; [macro] => { $ crate :: SyntaxKind :: MACRO_KW } ; [match] => { $ crate :: SyntaxKind :: MATCH_KW } ; [mod] => { $ crate :: SyntaxKind :: MOD_KW } ; [move] => { $ crate :: SyntaxKind :: MOVE_KW } ; [mut] => { $ crate :: SyntaxKind :: MUT_KW } ; [pub] => { $ crate :: SyntaxKind :: PUB_KW } ; [ref] => { $ crate :: SyntaxKind :: REF_KW } ; [return] => { $ crate :: SyntaxKind :: RETURN_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [Self] => { $ crate :: SyntaxKind :: SELF_TYPE_KW } ; [static] => { $ crate :: SyntaxKind :: STATIC_KW } ; [struct] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [trait] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [try] => { $ crate :: SyntaxKind :: TRY_KW } ; [type] => { $ crate :: SyntaxKind :: TYPE_KW } ; [unsafe] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [use] => { $ crate :: SyntaxKind :: USE_KW } ; [where] => { $ crate :: SyntaxKind :: WHERE_KW } ; [while] => { $ crate :: SyntaxKind :: WHILE_KW } ; [yield] => { $ crate :: SyntaxKind :: YIELD_KW } ; [auto] => { $ crate :: SyntaxKind :: AUTO_KW } ; [builtin] => { $ crate :: SyntaxKind :: BUILTIN_KW } ; [default] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [existential] => { $ crate :: SyntaxKind :: EXISTENTIAL_KW } ; [union] => { $ crate :: SyntaxKind :: UNION_KW } ; [raw] => { $ crate :: SyntaxKind :: RAW_KW } ; [macro_rules] => { $ crate :: SyntaxKind :: MACRO_RULES_KW } ; [yeet] => { $ crate :: SyntaxKind :: YEET_KW } ; [offset_of] => { $ crate :: SyntaxKind :: OFFSET_OF_KW } ; [asm] => { $ crate :: SyntaxKind :: ASM_KW } ; [format_args] => { $ crate :: SyntaxKind :: FORMAT_ARGS_KW } ; [lifetime_ident] => { $ crate :: SyntaxKind :: LIFETIME_IDENT } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; }
 pub use T;
diff --git a/crates/parser/test_data/parser/inline/ok/0132_box_expr.rast b/crates/parser/test_data/parser/inline/ok/0132_box_expr.rast
deleted file mode 100644
index b21f37cd85a..00000000000
--- a/crates/parser/test_data/parser/inline/ok/0132_box_expr.rast
+++ /dev/null
@@ -1,90 +0,0 @@
-SOURCE_FILE
-  FN
-    FN_KW "fn"
-    WHITESPACE " "
-    NAME
-      IDENT "foo"
-    PARAM_LIST
-      L_PAREN "("
-      R_PAREN ")"
-    WHITESPACE " "
-    BLOCK_EXPR
-      STMT_LIST
-        L_CURLY "{"
-        WHITESPACE "\n    "
-        LET_STMT
-          LET_KW "let"
-          WHITESPACE " "
-          IDENT_PAT
-            NAME
-              IDENT "x"
-          WHITESPACE " "
-          EQ "="
-          WHITESPACE " "
-          BOX_EXPR
-            BOX_KW "box"
-            WHITESPACE " "
-            LITERAL
-              INT_NUMBER "1i32"
-          SEMICOLON ";"
-        WHITESPACE "\n    "
-        LET_STMT
-          LET_KW "let"
-          WHITESPACE " "
-          IDENT_PAT
-            NAME
-              IDENT "y"
-          WHITESPACE " "
-          EQ "="
-          WHITESPACE " "
-          TUPLE_EXPR
-            L_PAREN "("
-            BOX_EXPR
-              BOX_KW "box"
-              WHITESPACE " "
-              LITERAL
-                INT_NUMBER "1i32"
-            COMMA ","
-            WHITESPACE " "
-            BOX_EXPR
-              BOX_KW "box"
-              WHITESPACE " "
-              LITERAL
-                INT_NUMBER "2i32"
-            R_PAREN ")"
-          SEMICOLON ";"
-        WHITESPACE "\n    "
-        LET_STMT
-          LET_KW "let"
-          WHITESPACE " "
-          IDENT_PAT
-            NAME
-              IDENT "z"
-          WHITESPACE " "
-          EQ "="
-          WHITESPACE " "
-          CALL_EXPR
-            PATH_EXPR
-              PATH
-                PATH_SEGMENT
-                  NAME_REF
-                    IDENT "Foo"
-            ARG_LIST
-              L_PAREN "("
-              BOX_EXPR
-                BOX_KW "box"
-                WHITESPACE " "
-                LITERAL
-                  INT_NUMBER "1i32"
-              COMMA ","
-              WHITESPACE " "
-              BOX_EXPR
-                BOX_KW "box"
-                WHITESPACE " "
-                LITERAL
-                  INT_NUMBER "2i32"
-              R_PAREN ")"
-          SEMICOLON ";"
-        WHITESPACE "\n"
-        R_CURLY "}"
-  WHITESPACE "\n"
diff --git a/crates/parser/test_data/parser/inline/ok/0132_box_expr.rs b/crates/parser/test_data/parser/inline/ok/0132_box_expr.rs
deleted file mode 100644
index fc9923b7137..00000000000
--- a/crates/parser/test_data/parser/inline/ok/0132_box_expr.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-fn foo() {
-    let x = box 1i32;
-    let y = (box 1i32, box 2i32);
-    let z = Foo(box 1i32, box 2i32);
-}
diff --git a/crates/parser/test_data/parser/inline/ok/0207_builtin_expr.rast b/crates/parser/test_data/parser/inline/ok/0207_builtin_expr.rast
new file mode 100644
index 00000000000..f127b3e8c89
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/0207_builtin_expr.rast
@@ -0,0 +1,62 @@
+SOURCE_FILE
+  FN
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "foo"
+    PARAM_LIST
+      L_PAREN "("
+      R_PAREN ")"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        WHITESPACE "\n    "
+        EXPR_STMT
+          ASM_EXPR
+            BUILTIN_KW "builtin"
+            POUND "#"
+            ASM_KW "asm"
+            L_PAREN "("
+            LITERAL
+              INT_NUMBER "0"
+            R_PAREN ")"
+          SEMICOLON ";"
+        WHITESPACE "\n    "
+        EXPR_STMT
+          FORMAT_ARGS_EXPR
+            BUILTIN_KW "builtin"
+            POUND "#"
+            FORMAT_ARGS_KW "format_args"
+            L_PAREN "("
+            LITERAL
+              INT_NUMBER "0"
+            R_PAREN ")"
+          SEMICOLON ";"
+        WHITESPACE "\n    "
+        EXPR_STMT
+          OFFSET_OF_EXPR
+            BUILTIN_KW "builtin"
+            POUND "#"
+            OFFSET_OF_KW "offset_of"
+            L_PAREN "("
+            PATH_TYPE
+              PATH
+                PATH_SEGMENT
+                  NAME_REF
+                    IDENT "Foo"
+            COMMA ","
+            WHITESPACE " "
+            NAME_REF
+              IDENT "bar"
+            DOT "."
+            NAME_REF
+              IDENT "baz"
+            DOT "."
+            NAME_REF
+              INT_NUMBER "0"
+            R_PAREN ")"
+          SEMICOLON ";"
+        WHITESPACE "\n"
+        R_CURLY "}"
+  WHITESPACE "\n"
diff --git a/crates/parser/test_data/parser/inline/ok/0207_builtin_expr.rs b/crates/parser/test_data/parser/inline/ok/0207_builtin_expr.rs
new file mode 100644
index 00000000000..dbad0a91df9
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/0207_builtin_expr.rs
@@ -0,0 +1,5 @@
+fn foo() {
+    builtin#asm(0);
+    builtin#format_args(0);
+    builtin#offset_of(Foo, bar.baz.0);
+}
diff --git a/crates/syntax/rust.ungram b/crates/syntax/rust.ungram
index ea7ebd85b33..2ce609b97a6 100644
--- a/crates/syntax/rust.ungram
+++ b/crates/syntax/rust.ungram
@@ -340,10 +340,10 @@ ExprStmt =
 
 Expr =
   ArrayExpr
+| AsmExpr
 | AwaitExpr
 | BinExpr
 | BlockExpr
-| BoxExpr
 | BreakExpr
 | CallExpr
 | CastExpr
@@ -351,6 +351,7 @@ Expr =
 | ContinueExpr
 | FieldExpr
 | ForExpr
+| FormatArgsExpr
 | IfExpr
 | IndexExpr
 | Literal
@@ -358,6 +359,7 @@ Expr =
 | MacroExpr
 | MatchExpr
 | MethodCallExpr
+| OffsetOfExpr
 | ParenExpr
 | PathExpr
 | PrefixExpr
@@ -373,6 +375,15 @@ Expr =
 | LetExpr
 | UnderscoreExpr
 
+OffsetOfExpr =
+  Attr* 'builtin' '#' 'offset_of' '(' Type ',' fields:(NameRef ('.' NameRef)* ) ')'
+
+AsmExpr =
+  Attr* 'builtin' '#' 'asm' '(' Expr ')'
+
+FormatArgsExpr =
+  Attr* 'builtin' '#' 'format_args' '(' ')'
+
 MacroExpr =
   MacroCall
 
@@ -526,9 +537,6 @@ UnderscoreExpr =
 AwaitExpr =
   Attr* Expr '.' 'await'
 
-BoxExpr =
-  Attr* 'box' Expr
-
 //*************************//
 //          Types          //
 //*************************//
diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs
index 16448db04f8..1c5e2282ecb 100644
--- a/crates/syntax/src/ast/generated/nodes.rs
+++ b/crates/syntax/src/ast/generated/nodes.rs
@@ -805,6 +805,20 @@ impl ArrayExpr {
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct AsmExpr {
+    pub(crate) syntax: SyntaxNode,
+}
+impl ast::HasAttrs for AsmExpr {}
+impl AsmExpr {
+    pub fn builtin_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![builtin]) }
+    pub fn pound_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![#]) }
+    pub fn asm_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![asm]) }
+    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
+    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct AwaitExpr {
     pub(crate) syntax: SyntaxNode,
 }
@@ -823,16 +837,6 @@ impl ast::HasAttrs for BinExpr {}
 impl BinExpr {}
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct BoxExpr {
-    pub(crate) syntax: SyntaxNode,
-}
-impl ast::HasAttrs for BoxExpr {}
-impl BoxExpr {
-    pub fn box_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![box]) }
-    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct BreakExpr {
     pub(crate) syntax: SyntaxNode,
 }
@@ -916,6 +920,21 @@ impl ForExpr {
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct FormatArgsExpr {
+    pub(crate) syntax: SyntaxNode,
+}
+impl ast::HasAttrs for FormatArgsExpr {}
+impl FormatArgsExpr {
+    pub fn builtin_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![builtin]) }
+    pub fn pound_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![#]) }
+    pub fn format_args_token(&self) -> Option<SyntaxToken> {
+        support::token(&self.syntax, T![format_args])
+    }
+    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
+    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct IfExpr {
     pub(crate) syntax: SyntaxNode,
 }
@@ -985,6 +1004,24 @@ impl MethodCallExpr {
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct OffsetOfExpr {
+    pub(crate) syntax: SyntaxNode,
+}
+impl ast::HasAttrs for OffsetOfExpr {}
+impl OffsetOfExpr {
+    pub fn builtin_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![builtin]) }
+    pub fn pound_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![#]) }
+    pub fn offset_of_token(&self) -> Option<SyntaxToken> {
+        support::token(&self.syntax, T![offset_of])
+    }
+    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
+    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
+    pub fn comma_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![,]) }
+    pub fn fields(&self) -> AstChildren<NameRef> { support::children(&self.syntax) }
+    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct ParenExpr {
     pub(crate) syntax: SyntaxNode,
 }
@@ -1555,10 +1592,10 @@ pub enum Type {
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub enum Expr {
     ArrayExpr(ArrayExpr),
+    AsmExpr(AsmExpr),
     AwaitExpr(AwaitExpr),
     BinExpr(BinExpr),
     BlockExpr(BlockExpr),
-    BoxExpr(BoxExpr),
     BreakExpr(BreakExpr),
     CallExpr(CallExpr),
     CastExpr(CastExpr),
@@ -1566,6 +1603,7 @@ pub enum Expr {
     ContinueExpr(ContinueExpr),
     FieldExpr(FieldExpr),
     ForExpr(ForExpr),
+    FormatArgsExpr(FormatArgsExpr),
     IfExpr(IfExpr),
     IndexExpr(IndexExpr),
     Literal(Literal),
@@ -1573,6 +1611,7 @@ pub enum Expr {
     MacroExpr(MacroExpr),
     MatchExpr(MatchExpr),
     MethodCallExpr(MethodCallExpr),
+    OffsetOfExpr(OffsetOfExpr),
     ParenExpr(ParenExpr),
     PathExpr(PathExpr),
     PrefixExpr(PrefixExpr),
@@ -2453,8 +2492,8 @@ impl AstNode for ArrayExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for AwaitExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == AWAIT_EXPR }
+impl AstNode for AsmExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2464,8 +2503,8 @@ impl AstNode for AwaitExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for BinExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == BIN_EXPR }
+impl AstNode for AwaitExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == AWAIT_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2475,8 +2514,8 @@ impl AstNode for BinExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for BoxExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == BOX_EXPR }
+impl AstNode for BinExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == BIN_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2563,6 +2602,17 @@ impl AstNode for ForExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
+impl AstNode for FormatArgsExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == FORMAT_ARGS_EXPR }
+    fn cast(syntax: SyntaxNode) -> Option<Self> {
+        if Self::can_cast(syntax.kind()) {
+            Some(Self { syntax })
+        } else {
+            None
+        }
+    }
+    fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
 impl AstNode for IfExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == IF_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2640,6 +2690,17 @@ impl AstNode for MethodCallExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
+impl AstNode for OffsetOfExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == OFFSET_OF_EXPR }
+    fn cast(syntax: SyntaxNode) -> Option<Self> {
+        if Self::can_cast(syntax.kind()) {
+            Some(Self { syntax })
+        } else {
+            None
+        }
+    }
+    fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
 impl AstNode for ParenExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == PAREN_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3373,6 +3434,9 @@ impl AstNode for Type {
 impl From<ArrayExpr> for Expr {
     fn from(node: ArrayExpr) -> Expr { Expr::ArrayExpr(node) }
 }
+impl From<AsmExpr> for Expr {
+    fn from(node: AsmExpr) -> Expr { Expr::AsmExpr(node) }
+}
 impl From<AwaitExpr> for Expr {
     fn from(node: AwaitExpr) -> Expr { Expr::AwaitExpr(node) }
 }
@@ -3382,9 +3446,6 @@ impl From<BinExpr> for Expr {
 impl From<BlockExpr> for Expr {
     fn from(node: BlockExpr) -> Expr { Expr::BlockExpr(node) }
 }
-impl From<BoxExpr> for Expr {
-    fn from(node: BoxExpr) -> Expr { Expr::BoxExpr(node) }
-}
 impl From<BreakExpr> for Expr {
     fn from(node: BreakExpr) -> Expr { Expr::BreakExpr(node) }
 }
@@ -3406,6 +3467,9 @@ impl From<FieldExpr> for Expr {
 impl From<ForExpr> for Expr {
     fn from(node: ForExpr) -> Expr { Expr::ForExpr(node) }
 }
+impl From<FormatArgsExpr> for Expr {
+    fn from(node: FormatArgsExpr) -> Expr { Expr::FormatArgsExpr(node) }
+}
 impl From<IfExpr> for Expr {
     fn from(node: IfExpr) -> Expr { Expr::IfExpr(node) }
 }
@@ -3427,6 +3491,9 @@ impl From<MatchExpr> for Expr {
 impl From<MethodCallExpr> for Expr {
     fn from(node: MethodCallExpr) -> Expr { Expr::MethodCallExpr(node) }
 }
+impl From<OffsetOfExpr> for Expr {
+    fn from(node: OffsetOfExpr) -> Expr { Expr::OffsetOfExpr(node) }
+}
 impl From<ParenExpr> for Expr {
     fn from(node: ParenExpr) -> Expr { Expr::ParenExpr(node) }
 }
@@ -3474,10 +3541,10 @@ impl AstNode for Expr {
         matches!(
             kind,
             ARRAY_EXPR
+                | ASM_EXPR
                 | AWAIT_EXPR
                 | BIN_EXPR
                 | BLOCK_EXPR
-                | BOX_EXPR
                 | BREAK_EXPR
                 | CALL_EXPR
                 | CAST_EXPR
@@ -3485,6 +3552,7 @@ impl AstNode for Expr {
                 | CONTINUE_EXPR
                 | FIELD_EXPR
                 | FOR_EXPR
+                | FORMAT_ARGS_EXPR
                 | IF_EXPR
                 | INDEX_EXPR
                 | LITERAL
@@ -3492,6 +3560,7 @@ impl AstNode for Expr {
                 | MACRO_EXPR
                 | MATCH_EXPR
                 | METHOD_CALL_EXPR
+                | OFFSET_OF_EXPR
                 | PAREN_EXPR
                 | PATH_EXPR
                 | PREFIX_EXPR
@@ -3511,10 +3580,10 @@ impl AstNode for Expr {
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         let res = match syntax.kind() {
             ARRAY_EXPR => Expr::ArrayExpr(ArrayExpr { syntax }),
+            ASM_EXPR => Expr::AsmExpr(AsmExpr { syntax }),
             AWAIT_EXPR => Expr::AwaitExpr(AwaitExpr { syntax }),
             BIN_EXPR => Expr::BinExpr(BinExpr { syntax }),
             BLOCK_EXPR => Expr::BlockExpr(BlockExpr { syntax }),
-            BOX_EXPR => Expr::BoxExpr(BoxExpr { syntax }),
             BREAK_EXPR => Expr::BreakExpr(BreakExpr { syntax }),
             CALL_EXPR => Expr::CallExpr(CallExpr { syntax }),
             CAST_EXPR => Expr::CastExpr(CastExpr { syntax }),
@@ -3522,6 +3591,7 @@ impl AstNode for Expr {
             CONTINUE_EXPR => Expr::ContinueExpr(ContinueExpr { syntax }),
             FIELD_EXPR => Expr::FieldExpr(FieldExpr { syntax }),
             FOR_EXPR => Expr::ForExpr(ForExpr { syntax }),
+            FORMAT_ARGS_EXPR => Expr::FormatArgsExpr(FormatArgsExpr { syntax }),
             IF_EXPR => Expr::IfExpr(IfExpr { syntax }),
             INDEX_EXPR => Expr::IndexExpr(IndexExpr { syntax }),
             LITERAL => Expr::Literal(Literal { syntax }),
@@ -3529,6 +3599,7 @@ impl AstNode for Expr {
             MACRO_EXPR => Expr::MacroExpr(MacroExpr { syntax }),
             MATCH_EXPR => Expr::MatchExpr(MatchExpr { syntax }),
             METHOD_CALL_EXPR => Expr::MethodCallExpr(MethodCallExpr { syntax }),
+            OFFSET_OF_EXPR => Expr::OffsetOfExpr(OffsetOfExpr { syntax }),
             PAREN_EXPR => Expr::ParenExpr(ParenExpr { syntax }),
             PATH_EXPR => Expr::PathExpr(PathExpr { syntax }),
             PREFIX_EXPR => Expr::PrefixExpr(PrefixExpr { syntax }),
@@ -3550,10 +3621,10 @@ impl AstNode for Expr {
     fn syntax(&self) -> &SyntaxNode {
         match self {
             Expr::ArrayExpr(it) => &it.syntax,
+            Expr::AsmExpr(it) => &it.syntax,
             Expr::AwaitExpr(it) => &it.syntax,
             Expr::BinExpr(it) => &it.syntax,
             Expr::BlockExpr(it) => &it.syntax,
-            Expr::BoxExpr(it) => &it.syntax,
             Expr::BreakExpr(it) => &it.syntax,
             Expr::CallExpr(it) => &it.syntax,
             Expr::CastExpr(it) => &it.syntax,
@@ -3561,6 +3632,7 @@ impl AstNode for Expr {
             Expr::ContinueExpr(it) => &it.syntax,
             Expr::FieldExpr(it) => &it.syntax,
             Expr::ForExpr(it) => &it.syntax,
+            Expr::FormatArgsExpr(it) => &it.syntax,
             Expr::IfExpr(it) => &it.syntax,
             Expr::IndexExpr(it) => &it.syntax,
             Expr::Literal(it) => &it.syntax,
@@ -3568,6 +3640,7 @@ impl AstNode for Expr {
             Expr::MacroExpr(it) => &it.syntax,
             Expr::MatchExpr(it) => &it.syntax,
             Expr::MethodCallExpr(it) => &it.syntax,
+            Expr::OffsetOfExpr(it) => &it.syntax,
             Expr::ParenExpr(it) => &it.syntax,
             Expr::PathExpr(it) => &it.syntax,
             Expr::PrefixExpr(it) => &it.syntax,
@@ -4028,9 +4101,9 @@ impl AstNode for AnyHasAttrs {
                 | TYPE_PARAM
                 | LET_STMT
                 | ARRAY_EXPR
+                | ASM_EXPR
                 | AWAIT_EXPR
                 | BIN_EXPR
-                | BOX_EXPR
                 | BREAK_EXPR
                 | CALL_EXPR
                 | CAST_EXPR
@@ -4038,12 +4111,14 @@ impl AstNode for AnyHasAttrs {
                 | CONTINUE_EXPR
                 | FIELD_EXPR
                 | FOR_EXPR
+                | FORMAT_ARGS_EXPR
                 | IF_EXPR
                 | INDEX_EXPR
                 | LITERAL
                 | LOOP_EXPR
                 | MATCH_EXPR
                 | METHOD_CALL_EXPR
+                | OFFSET_OF_EXPR
                 | PAREN_EXPR
                 | PATH_EXPR
                 | PREFIX_EXPR
@@ -4620,17 +4695,17 @@ impl std::fmt::Display for ArrayExpr {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for AwaitExpr {
+impl std::fmt::Display for AsmExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for BinExpr {
+impl std::fmt::Display for AwaitExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for BoxExpr {
+impl std::fmt::Display for BinExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
@@ -4670,6 +4745,11 @@ impl std::fmt::Display for ForExpr {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
+impl std::fmt::Display for FormatArgsExpr {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        std::fmt::Display::fmt(self.syntax(), f)
+    }
+}
 impl std::fmt::Display for IfExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
@@ -4705,6 +4785,11 @@ impl std::fmt::Display for MethodCallExpr {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
+impl std::fmt::Display for OffsetOfExpr {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        std::fmt::Display::fmt(self.syntax(), f)
+    }
+}
 impl std::fmt::Display for ParenExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
diff --git a/crates/syntax/src/ast/prec.rs b/crates/syntax/src/ast/prec.rs
index 4ec388914e6..8e04ab8bedc 100644
--- a/crates/syntax/src/ast/prec.rs
+++ b/crates/syntax/src/ast/prec.rs
@@ -130,7 +130,8 @@ impl Expr {
             //
             ContinueExpr(_) => (0, 0),
 
-            ClosureExpr(_) | ReturnExpr(_) | YieldExpr(_) | YeetExpr(_) | BreakExpr(_) => (0, 1),
+            ClosureExpr(_) | ReturnExpr(_) | YieldExpr(_) | YeetExpr(_) | BreakExpr(_)
+            | OffsetOfExpr(_) | FormatArgsExpr(_) | AsmExpr(_) => (0, 1),
 
             RangeExpr(_) => (5, 5),
 
@@ -160,7 +161,7 @@ impl Expr {
 
             CastExpr(_) => (25, 26),
 
-            BoxExpr(_) | RefExpr(_) | LetExpr(_) | PrefixExpr(_) => (0, 27),
+            RefExpr(_) | LetExpr(_) | PrefixExpr(_) => (0, 27),
 
             AwaitExpr(_) | CallExpr(_) | MethodCallExpr(_) | IndexExpr(_) | TryExpr(_)
             | MacroExpr(_) => (29, 0),
@@ -202,7 +203,6 @@ impl Expr {
             let rhs = match self {
                 RefExpr(e) => e.expr(),
                 BinExpr(e) => e.rhs(),
-                BoxExpr(e) => e.expr(),
                 BreakExpr(e) => e.expr(),
                 LetExpr(e) => e.expr(),
                 RangeExpr(e) => e.end(),
@@ -279,7 +279,6 @@ impl Expr {
                 CastExpr(e) => e.as_token(),
                 FieldExpr(e) => e.dot_token(),
                 AwaitExpr(e) => e.dot_token(),
-                BoxExpr(e) => e.box_token(),
                 BreakExpr(e) => e.break_token(),
                 CallExpr(e) => e.arg_list().and_then(|args| args.l_paren_token()),
                 ClosureExpr(e) => e.param_list().and_then(|params| params.l_paren_token()),
@@ -293,7 +292,9 @@ impl Expr {
                 YieldExpr(e) => e.yield_token(),
                 YeetExpr(e) => e.do_token(),
                 LetExpr(e) => e.let_token(),
-
+                OffsetOfExpr(e) => e.builtin_token(),
+                FormatArgsExpr(e) => e.builtin_token(),
+                AsmExpr(e) => e.builtin_token(),
                 ArrayExpr(_) | TupleExpr(_) | Literal(_) | PathExpr(_) | ParenExpr(_)
                 | IfExpr(_) | WhileExpr(_) | ForExpr(_) | LoopExpr(_) | MatchExpr(_)
                 | BlockExpr(_) | RecordExpr(_) | UnderscoreExpr(_) | MacroExpr(_) => None,
@@ -310,12 +311,12 @@ impl Expr {
             ArrayExpr(_) | AwaitExpr(_) | BlockExpr(_) | CallExpr(_) | CastExpr(_)
             | ClosureExpr(_) | FieldExpr(_) | IndexExpr(_) | Literal(_) | LoopExpr(_)
             | MacroExpr(_) | MethodCallExpr(_) | ParenExpr(_) | PathExpr(_) | RecordExpr(_)
-            | TryExpr(_) | TupleExpr(_) | UnderscoreExpr(_) => false,
+            | TryExpr(_) | TupleExpr(_) | UnderscoreExpr(_) | OffsetOfExpr(_)
+            | FormatArgsExpr(_) | AsmExpr(_) => false,
 
             // For BinExpr and RangeExpr this is technically wrong -- the child can be on the left...
-            BinExpr(_) | RangeExpr(_) | BoxExpr(_) | BreakExpr(_) | ContinueExpr(_)
-            | PrefixExpr(_) | RefExpr(_) | ReturnExpr(_) | YieldExpr(_) | YeetExpr(_)
-            | LetExpr(_) => self
+            BinExpr(_) | RangeExpr(_) | BreakExpr(_) | ContinueExpr(_) | PrefixExpr(_)
+            | RefExpr(_) | ReturnExpr(_) | YieldExpr(_) | YeetExpr(_) | LetExpr(_) => self
                 .syntax()
                 .parent()
                 .and_then(Expr::cast)
diff --git a/crates/syntax/src/tests/ast_src.rs b/crates/syntax/src/tests/ast_src.rs
index e4db33f1c69..2c1d832d1e5 100644
--- a/crates/syntax/src/tests/ast_src.rs
+++ b/crates/syntax/src/tests/ast_src.rs
@@ -70,7 +70,19 @@ pub(crate) const KINDS_SRC: KindsSrc<'_> = KindsSrc {
         "match", "mod", "move", "mut", "pub", "ref", "return", "self", "Self", "static", "struct",
         "super", "trait", "true", "try", "type", "unsafe", "use", "where", "while", "yield",
     ],
-    contextual_keywords: &["auto", "default", "existential", "union", "raw", "macro_rules", "yeet"],
+    contextual_keywords: &[
+        "auto",
+        "builtin",
+        "default",
+        "existential",
+        "union",
+        "raw",
+        "macro_rules",
+        "yeet",
+        "offset_of",
+        "asm",
+        "format_args",
+    ],
     literals: &["INT_NUMBER", "FLOAT_NUMBER", "CHAR", "BYTE", "STRING", "BYTE_STRING", "C_STRING"],
     tokens: &["ERROR", "IDENT", "WHITESPACE", "LIFETIME_IDENT", "COMMENT", "SHEBANG"],
     nodes: &[
@@ -154,7 +166,9 @@ pub(crate) const KINDS_SRC: KindsSrc<'_> = KindsSrc {
         "RECORD_EXPR",
         "RECORD_EXPR_FIELD_LIST",
         "RECORD_EXPR_FIELD",
-        "BOX_EXPR",
+        "OFFSET_OF_EXPR",
+        "ASM_EXPR",
+        "FORMAT_ARGS_EXPR",
         // postfix
         "CALL_EXPR",
         "INDEX_EXPR",
diff --git a/crates/syntax/src/tests/sourcegen_ast.rs b/crates/syntax/src/tests/sourcegen_ast.rs
index c49c5fa108b..56227fce9b5 100644
--- a/crates/syntax/src/tests/sourcegen_ast.rs
+++ b/crates/syntax/src/tests/sourcegen_ast.rs
@@ -623,7 +623,7 @@ fn lower_enum(grammar: &Grammar, rule: &Rule) -> Option<Vec<String>> {
 }
 
 fn lower_rule(acc: &mut Vec<Field>, grammar: &Grammar, label: Option<&String>, rule: &Rule) {
-    if lower_comma_list(acc, grammar, label, rule) {
+    if lower_seperated_list(acc, grammar, label, rule) {
         return;
     }
 
@@ -689,7 +689,7 @@ fn lower_rule(acc: &mut Vec<Field>, grammar: &Grammar, label: Option<&String>, r
 }
 
 // (T (',' T)* ','?)
-fn lower_comma_list(
+fn lower_seperated_list(
     acc: &mut Vec<Field>,
     grammar: &Grammar,
     label: Option<&String>,
@@ -699,19 +699,23 @@ fn lower_comma_list(
         Rule::Seq(it) => it,
         _ => return false,
     };
-    let (node, repeat, trailing_comma) = match rule.as_slice() {
-        [Rule::Node(node), Rule::Rep(repeat), Rule::Opt(trailing_comma)] => {
-            (node, repeat, trailing_comma)
+    let (node, repeat, trailing_sep) = match rule.as_slice() {
+        [Rule::Node(node), Rule::Rep(repeat), Rule::Opt(trailing_sep)] => {
+            (node, repeat, Some(trailing_sep))
         }
+        [Rule::Node(node), Rule::Rep(repeat)] => (node, repeat, None),
         _ => return false,
     };
     let repeat = match &**repeat {
         Rule::Seq(it) => it,
         _ => return false,
     };
-    match repeat.as_slice() {
-        [comma, Rule::Node(n)] if comma == &**trailing_comma && n == node => (),
-        _ => return false,
+    if !matches!(
+        repeat.as_slice(),
+        [comma, Rule::Node(n)]
+            if trailing_sep.map_or(true, |it| comma == &**it) && n == node
+    ) {
+        return false;
     }
     let ty = grammar[*node].name.clone();
     let name = label.cloned().unwrap_or_else(|| pluralize(&to_lower_snake_case(&ty)));