Skip to content

Commit 434b81e

Browse files
committed
Remove ast::Lit::kind.
This shrinks `ast::Lit` kind considerably. The conversion to semantic literals now happens at AST lowering time, with a few exceptions where the literal values are needed before that.
1 parent ca00cfb commit 434b81e

File tree

52 files changed

+522
-454
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+522
-454
lines changed

compiler/rustc_ast/src/ast.rs

+2-21
Original file line numberDiff line numberDiff line change
@@ -1691,10 +1691,6 @@ pub enum StrStyle {
16911691
pub struct Lit {
16921692
/// The original literal token as written in source code.
16931693
pub token_lit: token::Lit,
1694-
/// The "semantic" representation of the literal lowered from the original tokens.
1695-
/// Strings are unescaped, hexadecimal forms are eliminated, etc.
1696-
/// FIXME: Remove this and only create the semantic representation during lowering to HIR.
1697-
pub kind: LitKind,
16981694
pub span: Span,
16991695
}
17001696

@@ -1717,11 +1713,7 @@ impl StrLit {
17171713
StrStyle::Cooked => token::Str,
17181714
StrStyle::Raw(n) => token::StrRaw(n),
17191715
};
1720-
Lit {
1721-
token_lit: token::Lit::new(token_kind, self.symbol, self.suffix),
1722-
span: self.span,
1723-
kind: LitKind::Str(self.symbol_unescaped, self.style),
1724-
}
1716+
Lit { token_lit: token::Lit::new(token_kind, self.symbol, self.suffix), span: self.span }
17251717
}
17261718
}
17271719

@@ -1778,22 +1770,11 @@ impl LitKind {
17781770
matches!(self, LitKind::Str(..))
17791771
}
17801772

1781-
/// Returns `true` if this literal is byte literal string.
1782-
pub fn is_bytestr(&self) -> bool {
1783-
matches!(self, LitKind::ByteStr(_))
1784-
}
1785-
17861773
/// Returns `true` if this is a numeric literal.
17871774
pub fn is_numeric(&self) -> bool {
17881775
matches!(self, LitKind::Int(..) | LitKind::Float(..))
17891776
}
17901777

1791-
/// Returns `true` if this literal has no suffix.
1792-
/// Note: this will return true for literals with prefixes such as raw strings and byte strings.
1793-
pub fn is_unsuffixed(&self) -> bool {
1794-
!self.is_suffixed()
1795-
}
1796-
17971778
/// Returns `true` if this literal has a suffix.
17981779
pub fn is_suffixed(&self) -> bool {
17991780
match *self {
@@ -3056,7 +3037,7 @@ mod size_asserts {
30563037
static_assert_size!(Impl, 200);
30573038
static_assert_size!(Item, 184);
30583039
static_assert_size!(ItemKind, 112);
3059-
static_assert_size!(Lit, 48);
3040+
static_assert_size!(Lit, 20);
30603041
static_assert_size!(LitKind, 24);
30613042
static_assert_size!(Local, 72);
30623043
static_assert_size!(Param, 40);

compiler/rustc_ast/src/attr/mod.rs

+5-7
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ pub fn mk_name_value_item_str(ident: Ident, str: Symbol, str_span: Span) -> Meta
335335
}
336336

337337
pub fn mk_name_value_item(ident: Ident, lit_kind: LitKind, lit_span: Span) -> MetaItem {
338-
let lit = Lit::from_lit_kind(lit_kind, lit_span);
338+
let lit = Lit { token_lit: lit_kind.to_token_lit(), span: lit_span };
339339
let span = ident.span.to(lit_span);
340340
MetaItem { path: Path::from_ident(ident), span, kind: MetaItemKind::NameValue(lit) }
341341
}
@@ -519,8 +519,8 @@ impl MetaItem {
519519
impl MetaItemKind {
520520
pub fn value_str(&self) -> Option<Symbol> {
521521
match self {
522-
MetaItemKind::NameValue(ref v) => match v.kind {
523-
LitKind::Str(ref s, _) => Some(*s),
522+
MetaItemKind::NameValue(ref v) => match LitKind::from_token_lit(v.token_lit) {
523+
Ok(LitKind::Str(ref s, _)) => Some(*s),
524524
_ => None,
525525
},
526526
_ => None,
@@ -605,7 +605,7 @@ impl MetaItemKind {
605605
MetaItemKind::name_value_from_tokens(&mut inner_tokens.into_trees())
606606
}
607607
Some(TokenTree::Token(token, _)) => {
608-
Lit::from_token(&token).ok().map(MetaItemKind::NameValue)
608+
Lit::from_token(&token).map(MetaItemKind::NameValue)
609609
}
610610
_ => None,
611611
}
@@ -667,9 +667,7 @@ impl NestedMetaItem {
667667
I: Iterator<Item = TokenTree>,
668668
{
669669
match tokens.peek() {
670-
Some(TokenTree::Token(token, _))
671-
if let Ok(lit) = Lit::from_token(token) =>
672-
{
670+
Some(TokenTree::Token(token, _)) if let Some(lit) = Lit::from_token(token) => {
673671
tokens.next();
674672
return Some(NestedMetaItem::Literal(lit));
675673
}

compiler/rustc_ast/src/token.rs

+22
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,28 @@ pub struct Lit {
8080
pub suffix: Option<Symbol>,
8181
}
8282

83+
impl Lit {
84+
pub fn is_bool_true(&self) -> bool {
85+
matches!(self.kind, LitKind::Bool) && self.symbol == kw::True
86+
}
87+
88+
/// Returns `true` if this literal is a string.
89+
pub fn is_str(&self) -> bool {
90+
matches!(self.kind, LitKind::Str | LitKind::StrRaw(_))
91+
}
92+
93+
/// Returns `true` if this literal is byte literal string.
94+
pub fn is_bytestr(&self) -> bool {
95+
matches!(self.kind, LitKind::ByteStr | LitKind::ByteStrRaw(_))
96+
}
97+
98+
/// Returns `true` if this literal has no suffix.
99+
/// Note: this will return true for literals with prefixes such as raw strings and byte strings.
100+
pub fn is_unsuffixed(&self) -> bool {
101+
self.suffix.is_none()
102+
}
103+
}
104+
83105
impl fmt::Display for Lit {
84106
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85107
let Lit { kind, symbol, suffix } = *self;

compiler/rustc_ast/src/util/literal.rs

+12-23
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,10 @@ use crate::token::{self, Token};
66
use rustc_lexer::unescape::{unescape_byte, unescape_char};
77
use rustc_lexer::unescape::{unescape_byte_literal, unescape_literal, Mode};
88
use rustc_span::symbol::{kw, sym, Symbol};
9-
use rustc_span::Span;
109

1110
use std::ascii;
1211

1312
pub enum LitError {
14-
NotLiteral,
1513
LexerError,
1614
InvalidSuffix,
1715
InvalidIntSuffix,
@@ -149,7 +147,7 @@ impl LitKind {
149147
})
150148
}
151149

152-
/// Attempts to recover a token from semantic literal.
150+
/// Creates a token literal from a semantic literal kind.
153151
/// This function is used when the original token doesn't exist (e.g. the literal is created
154152
/// by an AST-based macro) or unavailable (e.g. from HIR pretty-printing).
155153
pub fn to_token_lit(&self) -> token::Lit {
@@ -203,39 +201,30 @@ impl LitKind {
203201
}
204202

205203
impl Lit {
206-
/// Converts literal token into an AST literal.
207-
pub fn from_token_lit(token_lit: token::Lit, span: Span) -> Result<Lit, LitError> {
208-
Ok(Lit { token_lit, kind: LitKind::from_token_lit(token_lit)?, span })
209-
}
210-
211-
/// Converts arbitrary token into an AST literal.
204+
/// Converts an arbitrary token into an AST literal. Returns `None` if the
205+
/// token is not a literal. The literal may be invalid in some fashion
206+
/// (e.g. invalid suffix, too-large int, etc.); this will be caught during
207+
/// lowering to HIR.
212208
///
213209
/// Keep this in sync with `Token::can_begin_literal_or_bool` excluding unary negation.
214-
pub fn from_token(token: &Token) -> Result<Lit, LitError> {
215-
let lit = match token.uninterpolate().kind {
210+
pub fn from_token(token: &Token) -> Option<Lit> {
211+
let token_lit = match token.uninterpolate().kind {
216212
token::Ident(name, false) if name.is_bool_lit() => {
217213
token::Lit::new(token::Bool, name, None)
218214
}
219-
token::Literal(lit) => lit,
215+
token::Literal(token_lit) => token_lit,
220216
token::Interpolated(ref nt) => {
221217
if let token::NtExpr(expr) | token::NtLiteral(expr) = &**nt
222218
&& let ast::ExprKind::Lit(lit) = &expr.kind
223219
{
224-
return Ok(lit.clone());
220+
return Some(lit.clone());
225221
}
226-
return Err(LitError::NotLiteral);
222+
return None;
227223
}
228-
_ => return Err(LitError::NotLiteral),
224+
_ => return None,
229225
};
230226

231-
Lit::from_token_lit(lit, token.span)
232-
}
233-
234-
/// Attempts to recover an AST literal from semantic literal.
235-
/// This function is used when the original token doesn't exist (e.g. the literal is created
236-
/// by an AST-based macro) or unavailable (e.g. from HIR pretty-printing).
237-
pub fn from_lit_kind(kind: LitKind, span: Span) -> Lit {
238-
Lit { token_lit: kind.to_token_lit(), kind, span }
227+
Some(Lit { token_lit, span: token.span })
239228
}
240229

241230
/// Losslessly convert an AST literal into a token.

compiler/rustc_ast_lowering/src/errors.rs

+55
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,61 @@ use rustc_errors::{fluent, AddSubdiagnostic, Applicability, Diagnostic, Diagnost
22
use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic};
33
use rustc_span::{symbol::Ident, Span, Symbol};
44

5+
#[derive(SessionDiagnostic)]
6+
#[diag(parser::invalid_int_literal_width)]
7+
#[help]
8+
pub(crate) struct InvalidIntLiteralWidth {
9+
#[primary_span]
10+
pub span: Span,
11+
pub width: String,
12+
}
13+
14+
#[derive(SessionDiagnostic)]
15+
#[diag(parser::invalid_num_literal_base_prefix)]
16+
#[note]
17+
pub(crate) struct InvalidNumLiteralBasePrefix {
18+
#[primary_span]
19+
#[suggestion(applicability = "maybe-incorrect", code = "{fixed}")]
20+
pub span: Span,
21+
pub fixed: String,
22+
}
23+
24+
#[derive(SessionDiagnostic)]
25+
#[diag(parser::invalid_num_literal_suffix)]
26+
#[help]
27+
pub(crate) struct InvalidNumLiteralSuffix {
28+
#[primary_span]
29+
#[label]
30+
pub span: Span,
31+
pub suffix: String,
32+
}
33+
34+
#[derive(SessionDiagnostic)]
35+
#[diag(parser::invalid_float_literal_width)]
36+
#[help]
37+
pub(crate) struct InvalidFloatLiteralWidth {
38+
#[primary_span]
39+
pub span: Span,
40+
pub width: String,
41+
}
42+
43+
#[derive(SessionDiagnostic)]
44+
#[diag(parser::invalid_float_literal_suffix)]
45+
#[help]
46+
pub(crate) struct InvalidFloatLiteralSuffix {
47+
#[primary_span]
48+
#[label]
49+
pub span: Span,
50+
pub suffix: String,
51+
}
52+
53+
#[derive(SessionDiagnostic)]
54+
#[diag(parser::int_literal_too_large)]
55+
pub(crate) struct IntLiteralTooLarge {
56+
#[primary_span]
57+
pub span: Span,
58+
}
59+
560
#[derive(SessionDiagnostic, Clone, Copy)]
661
#[diag(ast_lowering::generic_type_with_parentheses, code = "E0214")]
762
pub struct GenericTypeWithParentheses {

compiler/rustc_ast_lowering/src/expr.rs

+96-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
use super::errors::{
22
AsyncGeneratorsNotSupported, AsyncNonMoveClosureNotSupported, AwaitOnlyInAsyncFnAndBlocks,
33
BaseExpressionDoubleDot, ClosureCannotBeStatic, FunctionalRecordUpdateDestructuringAssignemnt,
4-
GeneratorTooManyParameters, InclusiveRangeWithNoEnd, NotSupportedForLifetimeBinderAsyncClosure,
5-
RustcBoxAttributeError, UnderscoreExprLhsAssign,
4+
GeneratorTooManyParameters, InclusiveRangeWithNoEnd, IntLiteralTooLarge,
5+
InvalidFloatLiteralSuffix, InvalidFloatLiteralWidth, InvalidIntLiteralWidth,
6+
InvalidNumLiteralBasePrefix, InvalidNumLiteralSuffix,
7+
NotSupportedForLifetimeBinderAsyncClosure, RustcBoxAttributeError, UnderscoreExprLhsAssign,
68
};
79
use super::ResolverAstLoweringExt;
810
use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs};
911
use crate::{FnDeclKind, ImplTraitPosition};
1012
use rustc_ast::attr;
1113
use rustc_ast::ptr::P as AstP;
14+
use rustc_ast::util::literal::LitError;
1215
use rustc_ast::*;
1316
use rustc_data_structures::stack::ensure_sufficient_stack;
1417
use rustc_hir as hir;
@@ -84,8 +87,17 @@ impl<'hir> LoweringContext<'_, 'hir> {
8487
let ohs = self.lower_expr(ohs);
8588
hir::ExprKind::Unary(op, ohs)
8689
}
87-
ExprKind::Lit(ref l) => {
88-
hir::ExprKind::Lit(respan(self.lower_span(l.span), l.kind.clone()))
90+
ExprKind::Lit(ref lit) => {
91+
let token_lit = lit.token_lit;
92+
let lit_kind = match LitKind::from_token_lit(token_lit) {
93+
Ok(lit_kind) => lit_kind,
94+
Err(err) => {
95+
let span = lit.span;
96+
self.report_lit_error(err, token_lit, span);
97+
LitKind::Err
98+
}
99+
};
100+
hir::ExprKind::Lit(respan(self.lower_span(lit.span), lit_kind))
89101
}
90102
ExprKind::Cast(ref expr, ref ty) => {
91103
let expr = self.lower_expr(expr);
@@ -306,6 +318,86 @@ impl<'hir> LoweringContext<'_, 'hir> {
306318
})
307319
}
308320

321+
#[allow(rustc::diagnostic_outside_of_impl)]
322+
#[allow(rustc::untranslatable_diagnostic)]
323+
fn report_lit_error(&self, err: LitError, lit: token::Lit, span: Span) {
324+
// Checks if `s` looks like i32 or u1234 etc.
325+
fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool {
326+
s.len() > 1 && s.starts_with(first_chars) && s[1..].chars().all(|c| c.is_ascii_digit())
327+
}
328+
329+
// Try to lowercase the prefix if it's a valid base prefix.
330+
fn fix_base_capitalisation(s: &str) -> Option<String> {
331+
if let Some(stripped) = s.strip_prefix('B') {
332+
Some(format!("0b{stripped}"))
333+
} else if let Some(stripped) = s.strip_prefix('O') {
334+
Some(format!("0o{stripped}"))
335+
} else if let Some(stripped) = s.strip_prefix('X') {
336+
Some(format!("0x{stripped}"))
337+
} else {
338+
None
339+
}
340+
}
341+
342+
let token::Lit { kind, suffix, .. } = lit;
343+
match err {
344+
// `LexerError` *is* an error, but it was already reported
345+
// by lexer, so here we don't report it the second time.
346+
LitError::LexerError => {}
347+
LitError::InvalidSuffix => {
348+
self.tcx.sess.parse_sess.expect_no_suffix(
349+
span,
350+
&format!("{} {} literal", kind.article(), kind.descr()),
351+
suffix,
352+
);
353+
}
354+
LitError::InvalidIntSuffix => {
355+
let suf = suffix.expect("suffix error with no suffix");
356+
let suf = suf.as_str();
357+
if looks_like_width_suffix(&['i', 'u'], &suf) {
358+
// If it looks like a width, try to be helpful.
359+
self.tcx.sess.emit_err(InvalidIntLiteralWidth { span, width: suf[1..].into() });
360+
} else if let Some(fixed) = fix_base_capitalisation(suf) {
361+
self.tcx.sess.emit_err(InvalidNumLiteralBasePrefix { span, fixed });
362+
} else {
363+
self.tcx
364+
.sess
365+
.emit_err(InvalidNumLiteralSuffix { span, suffix: suf.to_string() });
366+
}
367+
}
368+
LitError::InvalidFloatSuffix => {
369+
let suf = suffix.expect("suffix error with no suffix");
370+
let suf = suf.as_str();
371+
if looks_like_width_suffix(&['f'], suf) {
372+
// If it looks like a width, try to be helpful.
373+
self.tcx
374+
.sess
375+
.emit_err(InvalidFloatLiteralWidth { span, width: suf[1..].to_string() });
376+
} else {
377+
self.tcx
378+
.sess
379+
.emit_err(InvalidFloatLiteralSuffix { span, suffix: suf.to_string() });
380+
}
381+
}
382+
LitError::NonDecimalFloat(base) => {
383+
let descr = match base {
384+
16 => "hexadecimal",
385+
8 => "octal",
386+
2 => "binary",
387+
_ => unreachable!(),
388+
};
389+
self.tcx
390+
.sess
391+
.struct_span_err(span, &format!("{descr} float literal is not supported"))
392+
.span_label(span, "not supported")
393+
.emit();
394+
}
395+
LitError::IntTooLarge => {
396+
self.tcx.sess.emit_err(IntLiteralTooLarge { span });
397+
}
398+
}
399+
}
400+
309401
fn lower_unop(&mut self, u: UnOp) -> hir::UnOp {
310402
match u {
311403
UnOp::Deref => hir::UnOp::Deref,

compiler/rustc_ast_lowering/src/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -952,7 +952,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
952952
} else {
953953
Lit {
954954
token_lit: token::Lit::new(token::LitKind::Err, kw::Empty, None),
955-
kind: LitKind::Err,
956955
span: DUMMY_SP,
957956
}
958957
};

0 commit comments

Comments
 (0)