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

Commit 994d560

Browse files
committed
Auto merge of rust-lang#136860 - oli-obk:signed-literals, r=<try>
Give integer literals a sign instead of relying on negation expressions r? `@ghost` A lot of situations in the compiler check for unary negation of literals, which I want to replace entirely at some point. I think the only place that should have to handle such things is the overflowing literals lint to detect double negation. Everywhere else we should just have the concept of negative literals.
2 parents c182ce9 + 25e4dd9 commit 994d560

File tree

62 files changed

+628
-281
lines changed

Some content is hidden

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

62 files changed

+628
-281
lines changed

compiler/rustc_ast/src/ast.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1874,11 +1874,13 @@ impl StrLit {
18741874
#[derive(HashStable_Generic)]
18751875
pub enum LitIntType {
18761876
/// e.g. `42_i32`.
1877-
Signed(IntTy),
1877+
/// The bool signals whether the literal is negated
1878+
Signed(IntTy, bool),
18781879
/// e.g. `42_u32`.
18791880
Unsigned(UintTy),
18801881
/// e.g. `42`.
1881-
Unsuffixed,
1882+
/// The bool signals whether the literal is negated
1883+
Unsuffixed(bool),
18821884
}
18831885

18841886
/// Type of the float literal based on provided suffix.
@@ -1913,7 +1915,7 @@ pub enum LitKind {
19131915
Char(char),
19141916
/// An integer literal (`1`).
19151917
Int(Pu128, LitIntType),
1916-
/// A float literal (`1.0`, `1f64` or `1E10f64`). The pre-suffix part is
1918+
/// A float literal (`1.0`, `-1.0`, `1f64` or `1E10f64`). The pre-suffix part is
19171919
/// stored as a symbol rather than `f64` so that `LitKind` can impl `Eq`
19181920
/// and `Hash`.
19191921
Float(Symbol, LitFloatType),
@@ -1964,7 +1966,7 @@ impl LitKind {
19641966
| LitKind::CStr(..)
19651967
| LitKind::Byte(..)
19661968
| LitKind::Char(..)
1967-
| LitKind::Int(_, LitIntType::Unsuffixed)
1969+
| LitKind::Int(_, LitIntType::Unsuffixed(_))
19681970
| LitKind::Float(_, LitFloatType::Unsuffixed)
19691971
| LitKind::Bool(..)
19701972
| LitKind::Err(_) => false,

compiler/rustc_ast/src/util/literal.rs

Lines changed: 50 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -36,20 +36,32 @@ pub enum LitError {
3636
InvalidSuffix(Symbol),
3737
InvalidIntSuffix(Symbol),
3838
InvalidFloatSuffix(Symbol),
39+
InvalidNegation(token::LitKind),
3940
NonDecimalFloat(u32), // u32 is the base
4041
IntTooLarge(u32), // u32 is the base
4142
}
4243

4344
impl LitKind {
44-
/// Converts literal token into a semantic literal.
4545
pub fn from_token_lit(lit: token::Lit) -> Result<LitKind, LitError> {
46+
Self::from_token_lit_maybe_negated(lit, false)
47+
}
48+
49+
/// Converts literal token into a semantic literal.
50+
pub fn from_token_lit_maybe_negated(
51+
lit: token::Lit,
52+
negated: bool,
53+
) -> Result<LitKind, LitError> {
4654
let token::Lit { kind, symbol, suffix } = lit;
4755
if let Some(suffix) = suffix
4856
&& !kind.may_have_suffix()
4957
{
5058
return Err(LitError::InvalidSuffix(suffix));
5159
}
5260

61+
if negated && !matches!(kind, token::Integer | token::Float) {
62+
return Err(LitError::InvalidNegation(kind));
63+
}
64+
5365
// For byte/char/string literals, chars and escapes have already been
5466
// checked in the lexer (in `cook_lexer_literal`). So we can assume all
5567
// chars and escapes are valid here.
@@ -71,8 +83,8 @@ impl LitKind {
7183

7284
// There are some valid suffixes for integer and float literals,
7385
// so all the handling is done internally.
74-
token::Integer => return integer_lit(symbol, suffix),
75-
token::Float => return float_lit(symbol, suffix),
86+
token::Integer => return integer_lit(symbol, suffix, negated),
87+
token::Float => return float_lit(symbol, suffix, negated),
7688

7789
token::Str => {
7890
// If there are no characters requiring special treatment we can
@@ -189,14 +201,21 @@ impl fmt::Display for LitKind {
189201
let symbol = str::from_utf8(bytes).unwrap();
190202
write!(f, "cr{delim}\"{symbol}\"{delim}", delim = "#".repeat(n as usize),)?;
191203
}
192-
LitKind::Int(n, ty) => {
193-
write!(f, "{n}")?;
194-
match ty {
195-
ast::LitIntType::Unsigned(ty) => write!(f, "{}", ty.name())?,
196-
ast::LitIntType::Signed(ty) => write!(f, "{}", ty.name())?,
197-
ast::LitIntType::Unsuffixed => {}
204+
LitKind::Int(n, ty) => match ty {
205+
ast::LitIntType::Unsigned(ty) => write!(f, "{n}{}", ty.name())?,
206+
ast::LitIntType::Signed(ty, negated) => {
207+
if negated {
208+
write!(f, "-")?;
209+
}
210+
write!(f, "{n}{}", ty.name())?
198211
}
199-
}
212+
ast::LitIntType::Unsuffixed(negated) => {
213+
if negated {
214+
write!(f, "-")?;
215+
}
216+
write!(f, "{n}")?;
217+
}
218+
},
200219
LitKind::Float(symbol, ty) => {
201220
write!(f, "{symbol}")?;
202221
match ty {
@@ -269,11 +288,13 @@ fn filtered_float_lit(
269288
symbol: Symbol,
270289
suffix: Option<Symbol>,
271290
base: u32,
291+
negated: bool,
272292
) -> Result<LitKind, LitError> {
273-
debug!("filtered_float_lit: {:?}, {:?}, {:?}", symbol, suffix, base);
293+
debug!(?symbol, ?suffix, ?base, ?negated);
274294
if base != 10 {
275295
return Err(LitError::NonDecimalFloat(base));
276296
}
297+
let symbol = if negated { Symbol::intern(&format!("-{}", symbol.as_str())) } else { symbol };
277298
Ok(match suffix {
278299
Some(suffix) => LitKind::Float(
279300
symbol,
@@ -289,12 +310,12 @@ fn filtered_float_lit(
289310
})
290311
}
291312

292-
fn float_lit(symbol: Symbol, suffix: Option<Symbol>) -> Result<LitKind, LitError> {
313+
fn float_lit(symbol: Symbol, suffix: Option<Symbol>, negated: bool) -> Result<LitKind, LitError> {
293314
debug!("float_lit: {:?}, {:?}", symbol, suffix);
294-
filtered_float_lit(strip_underscores(symbol), suffix, 10)
315+
filtered_float_lit(strip_underscores(symbol), suffix, 10, negated)
295316
}
296317

297-
fn integer_lit(symbol: Symbol, suffix: Option<Symbol>) -> Result<LitKind, LitError> {
318+
fn integer_lit(symbol: Symbol, suffix: Option<Symbol>, negated: bool) -> Result<LitKind, LitError> {
298319
debug!("integer_lit: {:?}, {:?}", symbol, suffix);
299320
let symbol = strip_underscores(symbol);
300321
let s = symbol.as_str();
@@ -308,12 +329,12 @@ fn integer_lit(symbol: Symbol, suffix: Option<Symbol>) -> Result<LitKind, LitErr
308329

309330
let ty = match suffix {
310331
Some(suf) => match suf {
311-
sym::isize => ast::LitIntType::Signed(ast::IntTy::Isize),
312-
sym::i8 => ast::LitIntType::Signed(ast::IntTy::I8),
313-
sym::i16 => ast::LitIntType::Signed(ast::IntTy::I16),
314-
sym::i32 => ast::LitIntType::Signed(ast::IntTy::I32),
315-
sym::i64 => ast::LitIntType::Signed(ast::IntTy::I64),
316-
sym::i128 => ast::LitIntType::Signed(ast::IntTy::I128),
332+
sym::isize => ast::LitIntType::Signed(ast::IntTy::Isize, negated),
333+
sym::i8 => ast::LitIntType::Signed(ast::IntTy::I8, negated),
334+
sym::i16 => ast::LitIntType::Signed(ast::IntTy::I16, negated),
335+
sym::i32 => ast::LitIntType::Signed(ast::IntTy::I32, negated),
336+
sym::i64 => ast::LitIntType::Signed(ast::IntTy::I64, negated),
337+
sym::i128 => ast::LitIntType::Signed(ast::IntTy::I128, negated),
317338
sym::usize => ast::LitIntType::Unsigned(ast::UintTy::Usize),
318339
sym::u8 => ast::LitIntType::Unsigned(ast::UintTy::U8),
319340
sym::u16 => ast::LitIntType::Unsigned(ast::UintTy::U16),
@@ -322,11 +343,18 @@ fn integer_lit(symbol: Symbol, suffix: Option<Symbol>) -> Result<LitKind, LitErr
322343
sym::u128 => ast::LitIntType::Unsigned(ast::UintTy::U128),
323344
// `1f64` and `2f32` etc. are valid float literals, and
324345
// `fxxx` looks more like an invalid float literal than invalid integer literal.
325-
_ if suf.as_str().starts_with('f') => return filtered_float_lit(symbol, suffix, base),
346+
_ if suf.as_str().starts_with('f') => {
347+
return filtered_float_lit(symbol, suffix, base, negated);
348+
}
326349
_ => return Err(LitError::InvalidIntSuffix(suf)),
327350
},
328-
_ => ast::LitIntType::Unsuffixed,
351+
_ => ast::LitIntType::Unsuffixed(negated),
329352
};
353+
if let ast::LitIntType::Unsigned(_) = ty
354+
&& negated
355+
{
356+
return Err(LitError::InvalidNegation(token::Integer));
357+
}
330358

331359
let s = &s[if base != 10 { 2 } else { 0 }..];
332360
u128::from_str_radix(s, base)

compiler/rustc_ast_lowering/src/expr.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,11 +139,22 @@ impl<'hir> LoweringContext<'_, 'hir> {
139139
hir::ExprKind::Binary(binop, lhs, rhs)
140140
}
141141
ExprKind::Unary(op, ohs) => {
142+
if let UnOp::Neg = op {
143+
if let ExprKind::Lit(token_lit) = &ohs.kind {
144+
return hir::Expr {
145+
hir_id: expr_hir_id,
146+
kind: hir::ExprKind::Lit(self.lower_lit(token_lit, e.span, true)),
147+
span: self.lower_span(e.span),
148+
};
149+
}
150+
}
142151
let op = self.lower_unop(*op);
143152
let ohs = self.lower_expr(ohs);
144153
hir::ExprKind::Unary(op, ohs)
145154
}
146-
ExprKind::Lit(token_lit) => hir::ExprKind::Lit(self.lower_lit(token_lit, e.span)),
155+
ExprKind::Lit(token_lit) => {
156+
hir::ExprKind::Lit(self.lower_lit(token_lit, e.span, false))
157+
}
147158
ExprKind::IncludedBytes(bytes) => {
148159
let lit = self.arena.alloc(respan(
149160
self.lower_span(e.span),
@@ -420,8 +431,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
420431
&mut self,
421432
token_lit: &token::Lit,
422433
span: Span,
434+
negated: bool,
423435
) -> &'hir Spanned<LitKind> {
424-
let lit_kind = match LitKind::from_token_lit(*token_lit) {
436+
let lit_kind = match LitKind::from_token_lit_maybe_negated(*token_lit, negated) {
425437
Ok(lit_kind) => lit_kind,
426438
Err(err) => {
427439
let guar = report_lit_error(&self.tcx.sess.psess, err, *token_lit, span);

compiler/rustc_ast_lowering/src/format.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
3030
Ok(LitKind::Int(n, ty)) => {
3131
match ty {
3232
// unsuffixed integer literals are assumed to be i32's
33-
LitIntType::Unsuffixed => {
34-
(n <= i32::MAX as u128).then_some(Symbol::intern(&n.to_string()))
35-
}
36-
LitIntType::Signed(int_ty) => {
33+
LitIntType::Unsuffixed(negated) => (!negated && n <= i32::MAX as u128)
34+
.then_some(Symbol::intern(&n.to_string())),
35+
LitIntType::Signed(int_ty, negated) => {
3736
let max_literal = self.int_ty_max(int_ty);
38-
(n <= max_literal).then_some(Symbol::intern(&n.to_string()))
37+
(!negated && n <= max_literal).then_some(Symbol::intern(&n.to_string()))
3938
}
4039
LitIntType::Unsigned(uint_ty) => {
4140
let max_literal = self.uint_ty_max(uint_ty);

compiler/rustc_ast_lowering/src/pat.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -391,18 +391,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
391391
let span = self.lower_span(expr.span);
392392
let err = |guar| hir::PatExprKind::Lit {
393393
lit: self.arena.alloc(respan(span, LitKind::Err(guar))),
394-
negated: false,
395394
};
396395
let kind = match &expr.kind {
397-
ExprKind::Lit(lit) => {
398-
hir::PatExprKind::Lit { lit: self.lower_lit(lit, span), negated: false }
399-
}
396+
ExprKind::Lit(lit) => hir::PatExprKind::Lit { lit: self.lower_lit(lit, span, false) },
400397
ExprKind::ConstBlock(c) => hir::PatExprKind::ConstBlock(self.lower_const_block(c)),
401398
ExprKind::IncludedBytes(bytes) => hir::PatExprKind::Lit {
402399
lit: self
403400
.arena
404401
.alloc(respan(span, LitKind::ByteStr(Arc::clone(bytes), StrStyle::Cooked))),
405-
negated: false,
406402
},
407403
ExprKind::Err(guar) => err(*guar),
408404
ExprKind::Dummy => span_bug!(span, "lowered ExprKind::Dummy"),
@@ -416,7 +412,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
416412
None,
417413
)),
418414
ExprKind::Unary(UnOp::Neg, inner) if let ExprKind::Lit(lit) = &inner.kind => {
419-
hir::PatExprKind::Lit { lit: self.lower_lit(lit, span), negated: true }
415+
hir::PatExprKind::Lit { lit: self.lower_lit(lit, span, true) }
420416
}
421417
_ => {
422418
let pattern_from_macro = expr.is_approximately_pattern();

compiler/rustc_attr_parsing/src/attributes/repr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ fn int_type_of_word(s: Symbol) -> Option<IntType> {
196196
}
197197

198198
pub fn parse_alignment(node: &ast::LitKind) -> Result<Align, &'static str> {
199-
if let ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed) = node {
199+
if let ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed(false)) = node {
200200
// `Align::from_bytes` accepts 0 as an input, check is_power_of_two() first
201201
if literal.get().is_power_of_two() {
202202
// Only possible error is larger than 2^29

compiler/rustc_attr_parsing/src/session_diagnostics.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ pub(crate) enum IncorrectReprFormatGenericCause<'a> {
298298
name: &'a str,
299299

300300
#[skip_arg]
301-
int: u128,
301+
int: String,
302302
},
303303

304304
#[suggestion(
@@ -320,11 +320,13 @@ pub(crate) enum IncorrectReprFormatGenericCause<'a> {
320320

321321
impl<'a> IncorrectReprFormatGenericCause<'a> {
322322
pub(crate) fn from_lit_kind(span: Span, kind: &ast::LitKind, name: &'a str) -> Option<Self> {
323-
match kind {
324-
ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => {
325-
Some(Self::Int { span, name, int: int.get() })
326-
}
327-
ast::LitKind::Str(symbol, _) => Some(Self::Symbol { span, name, symbol: *symbol }),
323+
match *kind {
324+
ast::LitKind::Int(int, ast::LitIntType::Unsuffixed(negated)) => Some(Self::Int {
325+
span,
326+
name,
327+
int: if negated { format!("-{}", int.get()) } else { int.get().to_string() },
328+
}),
329+
ast::LitKind::Str(symbol, _) => Some(Self::Symbol { span, name, symbol }),
328330
_ => None,
329331
}
330332
}

compiler/rustc_builtin_macros/src/concat_bytes.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ fn invalid_type_err(
5151
snippet.map(|snippet| ConcatBytesInvalidSuggestion::IntLit { span, snippet });
5252
dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "numeric", sugg })
5353
}
54-
Ok(LitKind::Int(val, LitIntType::Unsuffixed | LitIntType::Unsigned(UintTy::U8))) => {
54+
Ok(LitKind::Int(val, LitIntType::Unsuffixed(false) | LitIntType::Unsigned(UintTy::U8))) => {
5555
assert!(val.get() > u8::MAX.into()); // must be an error
5656
dcx.emit_err(ConcatBytesOob { span })
5757
}
@@ -79,7 +79,7 @@ fn handle_array_element(
7979
match LitKind::from_token_lit(token_lit) {
8080
Ok(LitKind::Int(
8181
val,
82-
LitIntType::Unsuffixed | LitIntType::Unsigned(UintTy::U8),
82+
LitIntType::Unsuffixed(false) | LitIntType::Unsigned(UintTy::U8),
8383
)) if let Ok(val) = u8::try_from(val.get()) => {
8484
return Some(val);
8585
}

compiler/rustc_codegen_ssa/src/codegen_attrs.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -777,8 +777,9 @@ fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &hir::Attribute) -> Option<u16> {
777777
}
778778
_ => None,
779779
};
780-
if let Some(MetaItemLit { kind: LitKind::Int(ordinal, LitIntType::Unsuffixed), .. }) =
781-
sole_meta_list
780+
if let Some(MetaItemLit {
781+
kind: LitKind::Int(ordinal, LitIntType::Unsuffixed(false)), ..
782+
}) = sole_meta_list
782783
{
783784
// According to the table at
784785
// https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-header, the

compiler/rustc_expand/src/mbe/metavar_expr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ fn parse_depth<'psess>(
191191
.struct_span_err(span, "meta-variable expression depth must be a literal"));
192192
};
193193
if let Ok(lit_kind) = LitKind::from_token_lit(*lit)
194-
&& let LitKind::Int(n_u128, LitIntType::Unsuffixed) = lit_kind
194+
&& let LitKind::Int(n_u128, LitIntType::Unsuffixed(false)) = lit_kind
195195
&& let Ok(n_usize) = usize::try_from(n_u128.get())
196196
{
197197
Ok(n_usize)

0 commit comments

Comments
 (0)