Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 8ef2485

Browse files
committed
Auto merge of rust-lang#103812 - clubby789:improve-include-bytes, r=petrochenkov
Delay `include_bytes` to AST lowering Hopefully addresses rust-lang#65818. This PR introduces a new `ExprKind::IncludedBytes` which stores the path and bytes of a file included with `include_bytes!()`. We can then create a literal from the bytes during AST lowering, which means we don't need to escape the bytes into valid UTF8 which is the cause of most of the overhead of embedding large binary blobs.
2 parents aa05f99 + b2da155 commit 8ef2485

File tree

19 files changed

+78
-15
lines changed

19 files changed

+78
-15
lines changed

compiler/rustc_ast/src/ast.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1208,7 +1208,7 @@ impl Expr {
12081208
ExprKind::Tup(_) => ExprPrecedence::Tup,
12091209
ExprKind::Binary(op, ..) => ExprPrecedence::Binary(op.node),
12101210
ExprKind::Unary(..) => ExprPrecedence::Unary,
1211-
ExprKind::Lit(_) => ExprPrecedence::Lit,
1211+
ExprKind::Lit(_) | ExprKind::IncludedBytes(..) => ExprPrecedence::Lit,
12121212
ExprKind::Type(..) | ExprKind::Cast(..) => ExprPrecedence::Cast,
12131213
ExprKind::Let(..) => ExprPrecedence::Let,
12141214
ExprKind::If(..) => ExprPrecedence::If,
@@ -1446,6 +1446,12 @@ pub enum ExprKind {
14461446
/// with an optional value to be returned.
14471447
Yeet(Option<P<Expr>>),
14481448

1449+
/// Bytes included via `include_bytes!`
1450+
/// Added for optimization purposes to avoid the need to escape
1451+
/// large binary blobs - should always behave like [`ExprKind::Lit`]
1452+
/// with a `ByteStr` literal.
1453+
IncludedBytes(Lrc<[u8]>),
1454+
14491455
/// Placeholder for an expression that wasn't syntactically well formed in some way.
14501456
Err,
14511457
}

compiler/rustc_ast/src/mut_visit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1428,7 +1428,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
14281428
}
14291429
ExprKind::Try(expr) => vis.visit_expr(expr),
14301430
ExprKind::TryBlock(body) => vis.visit_block(body),
1431-
ExprKind::Lit(_) | ExprKind::Err => {}
1431+
ExprKind::Lit(_) | ExprKind::IncludedBytes(..) | ExprKind::Err => {}
14321432
}
14331433
vis.visit_id(id);
14341434
vis.visit_span(span);

compiler/rustc_ast/src/util/literal.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
use crate::ast::{self, Lit, LitKind};
44
use crate::token::{self, Token};
5+
use rustc_data_structures::sync::Lrc;
56
use rustc_lexer::unescape::{byte_from_char, unescape_byte, unescape_char, unescape_literal, Mode};
67
use rustc_span::symbol::{kw, sym, Symbol};
78
use rustc_span::Span;
@@ -231,6 +232,13 @@ impl Lit {
231232
Lit { token_lit: kind.to_token_lit(), kind, span }
232233
}
233234

235+
/// Recovers an AST literal from a string of bytes produced by `include_bytes!`.
236+
/// This requires ASCII-escaping the string, which can result in poor performance
237+
/// for very large strings of bytes.
238+
pub fn from_included_bytes(bytes: &Lrc<[u8]>, span: Span) -> Lit {
239+
Self::from_lit_kind(LitKind::ByteStr(bytes.clone()), span)
240+
}
241+
234242
/// Losslessly convert an AST literal into a token.
235243
pub fn to_token(&self) -> Token {
236244
let kind = match self.token_lit.kind {

compiler/rustc_ast/src/visit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -901,7 +901,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
901901
}
902902
ExprKind::Try(ref subexpression) => visitor.visit_expr(subexpression),
903903
ExprKind::TryBlock(ref body) => visitor.visit_block(body),
904-
ExprKind::Lit(_) | ExprKind::Err => {}
904+
ExprKind::Lit(_) | ExprKind::IncludedBytes(..) | ExprKind::Err => {}
905905
}
906906

907907
visitor.visit_expr_post(expression)

compiler/rustc_ast_lowering/src/expr.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
8787
ExprKind::Lit(ref l) => {
8888
hir::ExprKind::Lit(respan(self.lower_span(l.span), l.kind.clone()))
8989
}
90+
ExprKind::IncludedBytes(ref bytes) => hir::ExprKind::Lit(respan(
91+
self.lower_span(e.span),
92+
LitKind::ByteStr(bytes.clone()),
93+
)),
9094
ExprKind::Cast(ref expr, ref ty) => {
9195
let expr = self.lower_expr(expr);
9296
let ty =

compiler/rustc_ast_lowering/src/pat.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
323323
// ```
324324
fn lower_expr_within_pat(&mut self, expr: &Expr, allow_paths: bool) -> &'hir hir::Expr<'hir> {
325325
match expr.kind {
326-
ExprKind::Lit(..) | ExprKind::ConstBlock(..) | ExprKind::Err => {}
326+
ExprKind::Lit(..)
327+
| ExprKind::ConstBlock(..)
328+
| ExprKind::IncludedBytes(..)
329+
| ExprKind::Err => {}
327330
ExprKind::Path(..) if allow_paths => {}
328331
ExprKind::Unary(UnOp::Neg, ref inner) if matches!(inner.kind, ExprKind::Lit(_)) => {}
329332
_ => {

compiler/rustc_ast_pretty/src/pprust/state/expr.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,10 @@ impl<'a> State<'a> {
322322
ast::ExprKind::Lit(ref lit) => {
323323
self.print_literal(lit);
324324
}
325+
ast::ExprKind::IncludedBytes(ref bytes) => {
326+
let lit = ast::Lit::from_included_bytes(bytes, expr.span);
327+
self.print_literal(&lit)
328+
}
325329
ast::ExprKind::Cast(ref expr, ref ty) => {
326330
let prec = AssocOp::As.precedence() as i8;
327331
self.print_expr_maybe_paren(expr, prec);

compiler/rustc_builtin_macros/src/assert/context.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
303303
| ExprKind::Field(_, _)
304304
| ExprKind::ForLoop(_, _, _, _)
305305
| ExprKind::If(_, _, _)
306+
| ExprKind::IncludedBytes(..)
306307
| ExprKind::InlineAsm(_)
307308
| ExprKind::Let(_, _, _)
308309
| ExprKind::Lit(_)

compiler/rustc_builtin_macros/src/concat.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ pub fn expand_concat(
4343
has_errors = true;
4444
}
4545
},
46+
ast::ExprKind::IncludedBytes(..) => {
47+
cx.span_err(e.span, "cannot concatenate a byte string literal")
48+
}
4649
ast::ExprKind::Err => {
4750
has_errors = true;
4851
}

compiler/rustc_builtin_macros/src/concat_bytes.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,16 @@ fn handle_array_element(
108108
None
109109
}
110110
},
111+
ast::ExprKind::IncludedBytes(..) => {
112+
if !*has_errors {
113+
cx.struct_span_err(expr.span, "cannot concatenate doubly nested array")
114+
.note("byte strings are treated as arrays of bytes")
115+
.help("try flattening the array")
116+
.emit();
117+
}
118+
*has_errors = true;
119+
None
120+
}
111121
_ => {
112122
missing_literals.push(expr.span);
113123
None
@@ -167,6 +177,9 @@ pub fn expand_concat_bytes(
167177
has_errors = true;
168178
}
169179
},
180+
ast::ExprKind::IncludedBytes(ref bytes) => {
181+
accumulator.extend_from_slice(bytes);
182+
}
170183
ast::ExprKind::Err => {
171184
has_errors = true;
172185
}

0 commit comments

Comments
 (0)