Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 70 additions & 7 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,19 @@
//! - [`UnOp`], [`BinOp`], and [`BinOpKind`]: Unary and binary operators.

use std::borrow::{Borrow, Cow};
use std::fmt::Formatter;
use std::{cmp, fmt};

pub use GenericArgs::*;
pub use UnsafeSource::*;
pub use rustc_ast_ir::{FloatTy, IntTy, Movability, Mutability, Pinnedness, UintTy};
use rustc_data_structures::packed::Pu128;
use rustc_data_structures::stable_hash::{StableHash, StableHashCtxt, StableHasher};
use rustc_data_structures::tagged_ptr::Tag;
use rustc_macros::{Decodable, Encodable, StableHash, Walkable};
pub use rustc_span::AttrId;
use rustc_span::{
ByteSymbol, DUMMY_SP, ErrorGuaranteed, Ident, LocalExpnId, Span, Spanned, Symbol, kw, respan,
sym,
sym, with_session_globals,
};
use thin_vec::{ThinVec, thin_vec};

Expand Down Expand Up @@ -2276,7 +2276,7 @@ pub enum LitKind {
/// A character literal (`'a'`).
Char(char),
/// An integer literal (`1`).
Int(Pu128, LitIntType),
Int(CompressedIntLiteral, LitIntType),
/// A float literal (`1.0`, `1f64` or `1E10f64`). The pre-suffix part is
/// stored as a symbol rather than `f64` so that `LitKind` can impl `Eq`
/// and `Hash`.
Expand Down Expand Up @@ -2336,6 +2336,69 @@ impl LitKind {
}
}

const MAX_INLINE_INT_LITERAL_VALUE: u32 = 0b01111111111111111111111111111111;

/// 128-bit integer literal that is either:
/// - Stored inline, if its value is < 2^31
/// - Stored as an index into a global interned table, if it is larger.
///
/// The highest bit of the value is set to 1 if it is interned.
///
/// The motivation for this optimization is to reduce the size of the LitKind AST node.
#[derive(Clone, Copy, Encodable, Decodable, Debug, Hash, Eq, PartialEq, StableHash)]
pub struct CompressedIntLiteral(u32);

impl CompressedIntLiteral {
pub fn from_u128(value: u128) -> Self {
// Store inline
if value <= MAX_INLINE_INT_LITERAL_VALUE as u128 {
Self(value as u32)
} else {
// Store interned
let index = with_session_globals(|session| {
session.int_literal_interner.with_lock(|interner| interner.intern(value))
});
assert!(index <= MAX_INLINE_INT_LITERAL_VALUE);
let index = (1 << 31) | index;
Self(index)
}
}

#[inline]
pub fn as_u8(&self) -> Result<u8, std::num::TryFromIntError> {
self.as_u128().try_into()
}

#[inline]
pub fn as_u32(&self) -> Result<u32, std::num::TryFromIntError> {
self.as_u128().try_into()
}

#[inline]
pub fn as_u64(&self) -> Result<u64, std::num::TryFromIntError> {
self.as_u128().try_into()
}

#[inline]
pub fn as_u128(&self) -> u128 {
let is_inline = self.0 <= MAX_INLINE_INT_LITERAL_VALUE;
if is_inline {
self.0 as u128
} else {
let key = self.0 & MAX_INLINE_INT_LITERAL_VALUE;
with_session_globals(|session| {
session.int_literal_interner.with_lock(|interner| interner.get(key))
})
}
}
}

impl std::fmt::Display for CompressedIntLiteral {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
self.as_u128().fmt(f)
}
}

/// Represents a function's signature in a trait declaration,
/// trait implementation, or free function.
#[derive(Clone, Encodable, Decodable, Debug)]
Expand Down Expand Up @@ -4480,11 +4543,11 @@ mod size_asserts {
static_assert_size!(Item, 144);
static_assert_size!(ItemKind, 88);
static_assert_size!(Lifetime, 16);
static_assert_size!(LitKind, 24);
static_assert_size!(LitKind, 8);
static_assert_size!(Local, 96);
static_assert_size!(MetaItem, 80);
static_assert_size!(MetaItemKind, 40);
static_assert_size!(MetaItemLit, 40);
static_assert_size!(MetaItem, 64);
static_assert_size!(MetaItemKind, 24);
static_assert_size!(MetaItemLit, 24);
static_assert_size!(NormalAttr, 80);
static_assert_size!(Param, 40);
static_assert_size!(Pat, 64);
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_ast/src/util/literal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use rustc_literal_escaper::{
use rustc_span::{ByteSymbol, Span, Symbol, kw, sym};
use tracing::debug;

use crate::CompressedIntLiteral;
use crate::ast::{self, LitKind, MetaItemLit, StrStyle};
use crate::token::{self, Token};

Expand Down Expand Up @@ -363,6 +364,6 @@ fn integer_lit(symbol: Symbol, suffix: Option<Symbol>) -> Result<LitKind, LitErr

let s = &s[if base != 10 { 2 } else { 0 }..];
u128::from_str_radix(s, base)
.map(|i| LitKind::Int(i.into(), ty))
.map(|i| LitKind::Int(CompressedIntLiteral::from_u128(i), ty))
.map_err(|_| LitError::IntTooLarge(base))
}
1 change: 1 addition & 0 deletions compiler/rustc_ast_lowering/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
match LitKind::from_token_lit(lit) {
Ok(LitKind::Str(s, _)) => Some(s),
Ok(LitKind::Int(n, ty)) => {
let n = n.as_u128();
match ty {
// unsuffixed integer literals are assumed to be i32's
LitIntType::Unsuffixed => {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_attr_parsing/src/attributes/autodiff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ impl SingleAttributeParser for RustcAutodiffParser {
let width = if let Some(width) = items.peek()
&& let MetaItemOrLitParser::Lit(width) = width
&& let LitKind::Int(width, _) = width.kind
&& let Ok(width) = width.0.try_into()
&& let Ok(width) = width.as_u32()
{
_ = items.next();
width
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -890,7 +890,7 @@ impl SingleAttributeParser for PatchableFunctionEntryParser {
return None;
};

let Ok(val) = val.get().try_into() else {
let Ok(val) = val.as_u8() else {
cx.adcx().expected_integer_literal_in_range(
value.value_span,
u8::MIN as isize,
Expand Down
5 changes: 2 additions & 3 deletions compiler/rustc_attr_parsing/src/attributes/repr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,13 +250,12 @@ fn parse_alignment(node: &LitKind, cx: &AcceptContext<'_, '_>) -> Result<Align,

// `Align::from_bytes` accepts 0 as a valid input,
// so we check if its a power of two first
if !literal.get().is_power_of_two() {
if !literal.as_u128().is_power_of_two() {
return Err("not a power of two".to_string());
}
// lit must be < 2^29
let align = literal
.get()
.try_into()
.as_u64()
.ok()
.and_then(|a| Align::from_bytes(a).ok())
.ok_or("larger than 2^29".to_string())?;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ impl SingleAttributeParser for RustcLegacyConstGenericsParser {
..
}) = possible_index
{
parsed_indexes.push((index.0 as usize, possible_index.span()));
parsed_indexes.push((index.as_u128() as usize, possible_index.span()));
} else {
cx.adcx().expected_integer_literal(possible_index.span());
errored = true;
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_attr_parsing/src/attributes/unroll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ impl SingleAttributeParser for UnrollParser {
if let Some(lit) = l.as_lit()
&& let LitKind::Int(val, LitIntType::Unsuffixed) = lit.kind
{
if let Ok(val) = u32::try_from(val.get()) {
if let Ok(val) = val.as_u32() {
return Some(AttributeKind::Unroll(UnrollAttr::Count(val)));
} else {
cx.adcx().expected_integer_literal_in_range(l.span(), 0, u32::MAX as isize);
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_attr_parsing/src/attributes/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub(crate) fn parse_single_integer(
cx.adcx().expected_integer_literal(single.span());
return None;
};
Some(num.0)
Some(num.as_u128())
}

impl AcceptContext<'_, '_> {
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_builtin_macros/src/autodiff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ mod llvm_enzyme {
match l.kind {
ast::LitKind::Int(val, _) => {
// get an Ident from a lit
return rustc_span::Ident::from_str(val.get().to_string().as_str());
return rustc_span::Ident::from_str(val.as_u128().to_string().as_str());
}
_ => {}
}
Expand All @@ -66,7 +66,7 @@ mod llvm_enzyme {
fn width(x: &MetaItemInner) -> Option<u128> {
let lit = x.lit()?;
match lit.kind {
ast::LitKind::Int(x, _) => Some(x.get()),
ast::LitKind::Int(x, _) => Some(x.as_u128()),
_ => None,
}
}
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_builtin_macros/src/concat_bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ fn invalid_type_err(
dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "numeric", sugg, cs_note: None })
}
Ok(LitKind::Int(val, LitIntType::Unsuffixed | LitIntType::Unsigned(UintTy::U8))) => {
assert!(val.get() > u8::MAX.into()); // must be an error
assert!(val.as_u128() > u8::MAX.into()); // must be an error
dcx.emit_err(ConcatBytesOob { span })
}
Ok(LitKind::Int(_, _)) => dcx.emit_err(ConcatBytesNonU8 { span }),
Expand Down Expand Up @@ -99,7 +99,7 @@ fn handle_array_element(
Ok(LitKind::Int(
val,
LitIntType::Unsuffixed | LitIntType::Unsigned(UintTy::U8),
)) if let Ok(val) = u8::try_from(val.get()) => {
)) if let Ok(val) = val.as_u8() => {
return Some(val);
}
Ok(LitKind::Byte(val)) => return Some(val),
Expand Down Expand Up @@ -165,7 +165,7 @@ pub(crate) fn expand_concat_bytes(
if let Some(elem) =
handle_array_element(cx, &mut guar, &mut missing_literals, expr)
{
for _ in 0..count_val.get() {
for _ in 0..count_val.as_u128() {
accumulator.push(elem);
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_expand/src/mbe/metavar_expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ fn parse_depth<'psess>(
};
if let Ok(lit_kind) = LitKind::from_token_lit(*lit)
&& let LitKind::Int(n_u128, LitIntType::Unsuffixed) = lit_kind
&& let Ok(n_usize) = usize::try_from(n_u128.get())
&& let Ok(n_usize) = usize::try_from(n_u128.as_u128())
{
Ok(n_usize)
} else {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2015,7 +2015,7 @@ fn detect_discriminant_duplicate<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
tcx.hir_node_by_def_id(discr_def_id.expect_local())
&& let hir::ExprKind::Lit(lit) = &tcx.hir_body(expr.body).value.kind
&& let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node
&& *lit_value != dis.val
&& lit_value.as_u128() != dis.val
{
(tcx.def_span(discr_def_id), format!("`{dis}` (overflowed from `{lit_value}`)"))
} else {
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_hir_typeck/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3476,7 +3476,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// If index is an unsuffixed integer, show the fixed expression:
if let ExprKind::Lit(lit) = idx.kind
&& let ast::LitKind::Int(i, ast::LitIntType::Unsuffixed) = lit.node
&& i.get() < types.len().try_into().expect("tuple length fits in u128")
&& i.as_u128()
< types.len().try_into().expect("tuple length fits in u128")
{
err.span_suggestion(
brackets_span,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1038,7 +1038,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

match layout.backend_repr {
rustc_abi::BackendRepr::Scalar(scalar) => {
scalar.valid_range(&tcx).contains(u128::from(i.get())).then_some(ty)
scalar.valid_range(&tcx).contains(i.as_u128()).then_some(ty)
}
_ => unreachable!(),
}
Expand Down
10 changes: 6 additions & 4 deletions compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use hir::def_id::LocalDefId;
use itertools::Itertools;
use rustc_ast::util::parser::ExprPrecedence;
use rustc_attr_ir::lang_items::LangItem;
use rustc_data_structures::packed::Pu128;
use rustc_errors::{Applicability, Diag, MultiSpan, listify, msg};
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
use rustc_hir::intravisit::Visitor;
Expand Down Expand Up @@ -1887,8 +1886,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
let (_, suffix) = snippet.split_at(snippet.len() - 3);
let value = match suffix {
"f32" => (lit.get() - 0xf32) / (16 * 16 * 16),
"f64" => (lit.get() - 0xf64) / (16 * 16 * 16),
"f32" => (lit.as_u128() - 0xf32) / (16 * 16 * 16),
"f64" => (lit.as_u128() - 0xf64) / (16 * 16 * 16),
_ => return false,
};
err.span_suggestions(
Expand Down Expand Up @@ -1918,10 +1917,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};

// Provided expression needs to be a literal `0`.
let ExprKind::Lit(Spanned { node: rustc_ast::LitKind::Int(Pu128(0), _), span }) = expr.kind
let ExprKind::Lit(Spanned { node: rustc_ast::LitKind::Int(int, _), span }) = expr.kind
else {
return false;
};
if int.as_u128() != 0 {
return false;
}

// We need to find a null pointer symbol to suggest
let null_sym = match mutbl {
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir_typeck/src/op.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
//! Code related to processing overloaded binary and unary operators.

use rustc_ast::{self as ast, AssignOp, BinOp};
use rustc_data_structures::packed::Pu128;
use rustc_data_structures::thin_vec::{ThinVec, thin_vec};
use rustc_errors::codes::*;
use rustc_errors::{Applicability, Diag, struct_span_code_err};
Expand Down Expand Up @@ -1032,12 +1031,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Expr {
kind:
ExprKind::Lit(Spanned {
node: ast::LitKind::Int(Pu128(1), _),
node: ast::LitKind::Int(int, _),
..
}),
..
},
) = ex.kind
&& int.as_u128() == 1
{
let span = if let hir::Node::Expr(parent) =
self.tcx.parent_hir_node(ex.hir_id)
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_lint/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2346,7 +2346,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
match &expr.kind {
Lit(lit) => {
if let Int(i, _) = lit.node {
i == 0
i.as_u128() == 0
} else {
false
}
Expand Down Expand Up @@ -2674,7 +2674,7 @@ impl<'tcx> LateLintPass<'tcx> for DerefNullPtr {
match &expr.kind {
hir::ExprKind::Lit(lit) => {
if let LitKind::Int(a, _) = lit.node {
return a == 0;
return a.as_u128() == 0;
}
}
_ => {}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_lint/src/invalid_from_utf8.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidFromUtf8 {
.map(|e| match &e.kind {
ExprKind::Lit(Spanned { node: lit, .. }) => match lit {
LitKind::Byte(b) => Some(*b),
LitKind::Int(b, _) => Some(b.get() as u8),
LitKind::Int(b, _) => Some(b.as_u128() as u8),
_ => None,
},
_ => None,
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_lint/src/ptr_nulls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ fn is_null_ptr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<Spa
} else if let ExprKind::Lit(spanned) = expr.kind
&& let LitKind::Int(v, _) = spanned.node
{
(v == 0).then_some(expr.span)
(v.as_u128() == 0).then_some(expr.span)
} else {
None
}
Expand Down Expand Up @@ -233,7 +233,7 @@ impl<'tcx> LateLintPass<'tcx> for PtrNullChecks {
ExprKind::Cast(cast_expr, _)
if let ExprKind::Lit(spanned) = cast_expr.kind
&& let LitKind::Int(v, _) = spanned.node
&& v == 0 =>
&& v.as_u128() == 0 =>
{
cx.emit_span_lint(USELESS_PTR_NULL_CHECKS, expr.span, diag)
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_lint/src/transmute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ fn check_int_to_ptr_transmute<'tcx>(
};
// bail-out if the argument is literal 0 as we have other lints for those cases
if let hir::ExprKind::Lit(hir::Lit { node: LitKind::Int(v, _), .. }) = arg.kind
&& v == 0
&& v.as_u128() == 0
{
return;
}
Expand Down
Loading
Loading