]> git.lizzy.rs Git - rust.git/commitdiff
Introduce `ExprKind::IncludedBytes`
authorclubby789 <jamie@hill-daniel.co.uk>
Mon, 31 Oct 2022 18:30:09 +0000 (18:30 +0000)
committerclubby789 <jamie@hill-daniel.co.uk>
Fri, 11 Nov 2022 16:31:32 +0000 (16:31 +0000)
19 files changed:
compiler/rustc_ast/src/ast.rs
compiler/rustc_ast/src/mut_visit.rs
compiler/rustc_ast/src/util/literal.rs
compiler/rustc_ast/src/visit.rs
compiler/rustc_ast_lowering/src/expr.rs
compiler/rustc_ast_lowering/src/pat.rs
compiler/rustc_ast_pretty/src/pprust/state/expr.rs
compiler/rustc_builtin_macros/src/assert/context.rs
compiler/rustc_builtin_macros/src/concat.rs
compiler/rustc_builtin_macros/src/concat_bytes.rs
compiler/rustc_builtin_macros/src/source_util.rs
compiler/rustc_expand/src/proc_macro_server.rs
compiler/rustc_parse/src/parser/path.rs
compiler/rustc_passes/src/hir_stats.rs
src/test/ui/proc-macro/expand-expr.rs
src/test/ui/proc-macro/expand-expr.stderr
src/tools/clippy/clippy_utils/src/sugg.rs
src/tools/rustfmt/src/expr.rs
src/tools/rustfmt/src/utils.rs

index 4ef43735a62c8eac79b0499268553cfd223e91d3..c999b06b0ab2d5b3cc247bb63c94f1596bc061b9 100644 (file)
@@ -1208,7 +1208,7 @@ pub fn precedence(&self) -> ExprPrecedence {
             ExprKind::Tup(_) => ExprPrecedence::Tup,
             ExprKind::Binary(op, ..) => ExprPrecedence::Binary(op.node),
             ExprKind::Unary(..) => ExprPrecedence::Unary,
-            ExprKind::Lit(_) => ExprPrecedence::Lit,
+            ExprKind::Lit(_) | ExprKind::IncludedBytes(..) => ExprPrecedence::Lit,
             ExprKind::Type(..) | ExprKind::Cast(..) => ExprPrecedence::Cast,
             ExprKind::Let(..) => ExprPrecedence::Let,
             ExprKind::If(..) => ExprPrecedence::If,
@@ -1446,6 +1446,12 @@ pub enum ExprKind {
     /// with an optional value to be returned.
     Yeet(Option<P<Expr>>),
 
+    /// Bytes included via `include_bytes!`
+    /// Added for optimization purposes to avoid the need to escape
+    /// large binary blobs - should always behave like [`ExprKind::Lit`]
+    /// with a `ByteStr` literal.
+    IncludedBytes(Lrc<[u8]>),
+
     /// Placeholder for an expression that wasn't syntactically well formed in some way.
     Err,
 }
index b970e57e0173c444a5dddef1862087d6036c35d9..3ab8267263d116506ba99ab75cc0e7096675dfc6 100644 (file)
@@ -1428,7 +1428,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
         }
         ExprKind::Try(expr) => vis.visit_expr(expr),
         ExprKind::TryBlock(body) => vis.visit_block(body),
-        ExprKind::Lit(_) | ExprKind::Err => {}
+        ExprKind::Lit(_) | ExprKind::IncludedBytes(..) | ExprKind::Err => {}
     }
     vis.visit_id(id);
     vis.visit_span(span);
index 8f342175f7d37133f67b288b672b1eaa9e3bfaec..e267f8cd10027d349f8dacb4a8d808cc88df76f9 100644 (file)
@@ -2,6 +2,7 @@
 
 use crate::ast::{self, Lit, LitKind};
 use crate::token::{self, Token};
+use rustc_data_structures::sync::Lrc;
 use rustc_lexer::unescape::{byte_from_char, unescape_byte, unescape_char, unescape_literal, Mode};
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::Span;
@@ -231,6 +232,13 @@ pub fn from_lit_kind(kind: LitKind, span: Span) -> Lit {
         Lit { token_lit: kind.to_token_lit(), kind, span }
     }
 
+    /// Recovers an AST literal from a string of bytes produced by `include_bytes!`.
+    /// This requires ASCII-escaping the string, which can result in poor performance
+    /// for very large strings of bytes.
+    pub fn from_included_bytes(bytes: &Lrc<[u8]>, span: Span) -> Lit {
+        Self::from_lit_kind(LitKind::ByteStr(bytes.clone()), span)
+    }
+
     /// Losslessly convert an AST literal into a token.
     pub fn to_token(&self) -> Token {
         let kind = match self.token_lit.kind {
index 6f56c1ef0e8daa6ff4e5fad425bd1171a51cc4f6..9053a5a1d64aa0344a330bbf2d847762f9d9a8b1 100644 (file)
@@ -901,7 +901,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
         }
         ExprKind::Try(ref subexpression) => visitor.visit_expr(subexpression),
         ExprKind::TryBlock(ref body) => visitor.visit_block(body),
-        ExprKind::Lit(_) | ExprKind::Err => {}
+        ExprKind::Lit(_) | ExprKind::IncludedBytes(..) | ExprKind::Err => {}
     }
 
     visitor.visit_expr_post(expression)
index ec9c3935020566aee76eeef1bf82fc9092125762..a4ae493af86bf6a23fc3b0df42d6138c6454e85d 100644 (file)
@@ -87,6 +87,10 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
                 ExprKind::Lit(ref l) => {
                     hir::ExprKind::Lit(respan(self.lower_span(l.span), l.kind.clone()))
                 }
+                ExprKind::IncludedBytes(ref bytes) => hir::ExprKind::Lit(respan(
+                    self.lower_span(e.span),
+                    LitKind::ByteStr(bytes.clone()),
+                )),
                 ExprKind::Cast(ref expr, ref ty) => {
                     let expr = self.lower_expr(expr);
                     let ty =
index 1af1633b5244badd53899e8002d189de5a4bfda3..7fdfc79164b48fba2142824f1b829ace1af07094 100644 (file)
@@ -323,7 +323,10 @@ fn lower_range_end(&mut self, e: &RangeEnd, has_end: bool) -> hir::RangeEnd {
     // ```
     fn lower_expr_within_pat(&mut self, expr: &Expr, allow_paths: bool) -> &'hir hir::Expr<'hir> {
         match expr.kind {
-            ExprKind::Lit(..) | ExprKind::ConstBlock(..) | ExprKind::Err => {}
+            ExprKind::Lit(..)
+            | ExprKind::ConstBlock(..)
+            | ExprKind::IncludedBytes(..)
+            | ExprKind::Err => {}
             ExprKind::Path(..) if allow_paths => {}
             ExprKind::Unary(UnOp::Neg, ref inner) if matches!(inner.kind, ExprKind::Lit(_)) => {}
             _ => {
index bcefa8ce0b9ce6ca8ff078b10e3fb3cc8d722a0d..930276242c3c361f9e72f525348ff09335ba5031 100644 (file)
@@ -322,6 +322,10 @@ pub(super) fn print_expr_outer_attr_style(&mut self, expr: &ast::Expr, is_inline
             ast::ExprKind::Lit(ref lit) => {
                 self.print_literal(lit);
             }
+            ast::ExprKind::IncludedBytes(ref bytes) => {
+                let lit = ast::Lit::from_included_bytes(bytes, expr.span);
+                self.print_literal(&lit)
+            }
             ast::ExprKind::Cast(ref expr, ref ty) => {
                 let prec = AssocOp::As.precedence() as i8;
                 self.print_expr_maybe_paren(expr, prec);
index bb6839360262af885d807408c1a2d7ed4cdb78d5..f72cd14bea0436e574a7a0f90ee26af58552fe72 100644 (file)
@@ -303,6 +303,7 @@ fn manage_cond_expr(&mut self, expr: &mut P<Expr>) {
             | ExprKind::Field(_, _)
             | ExprKind::ForLoop(_, _, _, _)
             | ExprKind::If(_, _, _)
+            | ExprKind::IncludedBytes(..)
             | ExprKind::InlineAsm(_)
             | ExprKind::Let(_, _, _)
             | ExprKind::Lit(_)
index 41f4e8c234d5adc004c8a44710e238fb89494cdd..01454d0e98e699cc14096654cc5c50ebd780f0d9 100644 (file)
@@ -43,6 +43,9 @@ pub fn expand_concat(
                     has_errors = true;
                 }
             },
+            ast::ExprKind::IncludedBytes(..) => {
+                cx.span_err(e.span, "cannot concatenate a byte string literal")
+            }
             ast::ExprKind::Err => {
                 has_errors = true;
             }
index 66e86bf2182672e0453f24aa3837623ea1a43b72..4886ca786a588bc5de61de819a1f49e4884bb25e 100644 (file)
@@ -108,6 +108,16 @@ fn handle_array_element(
                 None
             }
         },
+        ast::ExprKind::IncludedBytes(..) => {
+            if !*has_errors {
+                cx.struct_span_err(expr.span, "cannot concatenate doubly nested array")
+                    .note("byte strings are treated as arrays of bytes")
+                    .help("try flattening the array")
+                    .emit();
+            }
+            *has_errors = true;
+            None
+        }
         _ => {
             missing_literals.push(expr.span);
             None
@@ -167,6 +177,9 @@ pub fn expand_concat_bytes(
                     has_errors = true;
                 }
             },
+            ast::ExprKind::IncludedBytes(ref bytes) => {
+                accumulator.extend_from_slice(bytes);
+            }
             ast::ExprKind::Err => {
                 has_errors = true;
             }
index d78bbc3c932269c401400588536325cf2084c95a..3411bd40c9de553ec6e192aafb8350f0d55f6282 100644 (file)
@@ -216,7 +216,10 @@ pub fn expand_include_bytes(
         }
     };
     match cx.source_map().load_binary_file(&file) {
-        Ok(bytes) => base::MacEager::expr(cx.expr_byte_str(sp, bytes)),
+        Ok(bytes) => {
+            let expr = cx.expr(sp, ast::ExprKind::IncludedBytes(bytes.into()));
+            base::MacEager::expr(expr)
+        }
         Err(e) => {
             cx.span_err(sp, &format!("couldn't read {}: {}", file.display(), e));
             DummyResult::any(sp)
index cc2858d3f73a17d80a95147a4353501ca82cc5b4..a929f6cb0a5df6d6db89b433c8f133412711e260 100644 (file)
@@ -525,6 +525,13 @@ fn expand_expr(&mut self, stream: &Self::TokenStream) -> Result<Self::TokenStrea
             ast::ExprKind::Lit(l) => {
                 Ok(tokenstream::TokenStream::token_alone(token::Literal(l.token_lit), l.span))
             }
+            ast::ExprKind::IncludedBytes(bytes) => {
+                let lit = ast::Lit::from_included_bytes(bytes, expr.span);
+                Ok(tokenstream::TokenStream::token_alone(
+                    token::TokenKind::Literal(lit.token_lit),
+                    expr.span,
+                ))
+            }
             ast::ExprKind::Unary(ast::UnOp::Neg, e) => match &e.kind {
                 ast::ExprKind::Lit(l) => match l.token_lit {
                     token::Lit { kind: token::Integer | token::Float, .. } => {
index fdc1af27f82e4206e3e7d95eec13f6ffb59a4a92..d46565dea893119d48736a56d5ac8190ac79285a 100644 (file)
@@ -631,7 +631,9 @@ fn parse_assoc_equality_term(
     /// - A single-segment path.
     pub(super) fn expr_is_valid_const_arg(&self, expr: &P<rustc_ast::Expr>) -> bool {
         match &expr.kind {
-            ast::ExprKind::Block(_, _) | ast::ExprKind::Lit(_) => true,
+            ast::ExprKind::Block(_, _)
+            | ast::ExprKind::Lit(_)
+            | ast::ExprKind::IncludedBytes(..) => true,
             ast::ExprKind::Unary(ast::UnOp::Neg, expr) => {
                 matches!(expr.kind, ast::ExprKind::Lit(_))
             }
index 33220fd2b395dd0c32de941878104d5728d91f50..140f02c046a66c3b48d82f9a3f28acc42b3e24a5 100644 (file)
@@ -560,13 +560,14 @@ fn visit_pat(&mut self, p: &'v ast::Pat) {
     }
 
     fn visit_expr(&mut self, e: &'v ast::Expr) {
+        #[rustfmt::skip]
         record_variants!(
             (self, e, e.kind, Id::None, ast, Expr, ExprKind),
             [
                 Box, Array, ConstBlock, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, Let,
                 If, While, ForLoop, Loop, Match, Closure, Block, Async, Await, TryBlock, Assign,
                 AssignOp, Field, Index, Range, Underscore, Path, AddrOf, Break, Continue, Ret,
-                InlineAsm, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet, Err
+                InlineAsm, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet, IncludedBytes, Err
             ]
         );
         ast_visit::walk_expr(self, e)
index d1146d970306264b1485cfc6f243bd51134a62f4..8d51b7e17185b585411384795256ef5c84bae9b0 100644 (file)
@@ -1,5 +1,5 @@
 // aux-build:expand-expr.rs
-
+#![feature(concat_bytes)]
 extern crate expand_expr;
 
 use expand_expr::{
     concat!("contents: ", include_str!("auxiliary/included-file.txt"))
 );
 
+expand_expr_is!(
+    b"contents: Included file contents\n",
+    concat_bytes!(b"contents: ", include_bytes!("auxiliary/included-file.txt"))
+);
+
 // Correct value is checked for multiple sources.
 check_expand_expr_file!(file!());
 
index 8dc2d0cfc2f8505d3aaf50d0827c2afeea04befa..c6c4695fd9c43ee3093272a895cd3ff6f70b74af 100644 (file)
@@ -1,29 +1,29 @@
 error: expected one of `.`, `?`, or an operator, found `;`
-  --> $DIR/expand-expr.rs:101:27
+  --> $DIR/expand-expr.rs:106:27
    |
 LL | expand_expr_fail!("string"; hello);
    |                           ^ expected one of `.`, `?`, or an operator
 
 error: expected expression, found `$`
-  --> $DIR/expand-expr.rs:104:19
+  --> $DIR/expand-expr.rs:109:19
    |
 LL | expand_expr_fail!($);
    |                   ^ expected expression
 
 error: expected expression, found `$`
-  --> $DIR/expand-expr.rs:33:23
+  --> $DIR/expand-expr.rs:38:23
    |
 LL |     ($($t:tt)*) => { $($t)* };
    |                       ^^^^ expected expression
 
 error: expected expression, found `$`
-  --> $DIR/expand-expr.rs:106:28
+  --> $DIR/expand-expr.rs:111:28
    |
 LL | expand_expr_fail!(echo_pm!($));
    |                            ^ expected expression
 
 error: macro expansion ignores token `hello` and any following
-  --> $DIR/expand-expr.rs:110:47
+  --> $DIR/expand-expr.rs:115:47
    |
 LL | expand_expr_is!("string", echo_tts!("string"; hello));
    |                           --------------------^^^^^-- help: you might be missing a semicolon here: `;`
@@ -33,7 +33,7 @@ LL | expand_expr_is!("string", echo_tts!("string"; hello));
    = note: the usage of `echo_tts!` is likely invalid in expression context
 
 error: macro expansion ignores token `;` and any following
-  --> $DIR/expand-expr.rs:111:44
+  --> $DIR/expand-expr.rs:116:44
    |
 LL | expand_expr_is!("string", echo_pm!("string"; hello));
    |                           -----------------^-------- help: you might be missing a semicolon here: `;`
@@ -43,7 +43,7 @@ LL | expand_expr_is!("string", echo_pm!("string"; hello));
    = note: the usage of `echo_pm!` is likely invalid in expression context
 
 error: recursion limit reached while expanding `recursive_expand!`
-  --> $DIR/expand-expr.rs:119:16
+  --> $DIR/expand-expr.rs:124:16
    |
 LL | const _: u32 = recursive_expand!();
    |                ^^^^^^^^^^^^^^^^^^^
index aad7da61a8a54626530ef1821d3874df997ea72f..eefba8cd29c41268c3abb3dcb252e7f0b426ae10 100644 (file)
@@ -207,6 +207,7 @@ pub fn ast(cx: &EarlyContext<'_>, expr: &ast::Expr, default: &'a str) -> Self {
             | ast::ExprKind::InlineAsm(..)
             | ast::ExprKind::ConstBlock(..)
             | ast::ExprKind::Lit(..)
+            | ast::ExprKind::IncludedBytes(..)
             | ast::ExprKind::Loop(..)
             | ast::ExprKind::MacCall(..)
             | ast::ExprKind::MethodCall(..)
index 3105882e2d308085a6e0f8ab2269e47594a0d8b2..7750df0fff3afb124e133f245d22e8dbf635ee44 100644 (file)
@@ -399,6 +399,7 @@ fn needs_space_after_range(rhs: &ast::Expr) -> bool {
             }
         }
         ast::ExprKind::Underscore => Some("_".to_owned()),
+        ast::ExprKind::IncludedBytes(..) => unreachable!(),
         ast::ExprKind::Err => None,
     };
 
index cd852855602e867ad5027be306810cdb69adb3cd..c47b3b314dd4b31873405c3875aec1b698881032 100644 (file)
@@ -496,6 +496,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr
         | ast::ExprKind::Continue(..)
         | ast::ExprKind::Err
         | ast::ExprKind::Field(..)
+        | ast::ExprKind::IncludedBytes(..)
         | ast::ExprKind::InlineAsm(..)
         | ast::ExprKind::Let(..)
         | ast::ExprKind::Path(..)