Skip to content

Commit 94dadf4

Browse files
committed
Allow initializing NonZero with literals
1 parent ab2eecc commit 94dadf4

File tree

10 files changed

+164
-207
lines changed

10 files changed

+164
-207
lines changed

compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1665,6 +1665,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
16651665
_ => unreachable!(),
16661666
}
16671667
}
1668+
ty::Adt(adt, ..) if tcx.is_lang_item(adt.did(), LangItem::NonZero) => {
1669+
if i.get() == 0 {
1670+
// FIXME: report a nice error
1671+
None
1672+
} else {
1673+
Some(ty)
1674+
}
1675+
}
16681676
_ => None,
16691677
});
16701678
opt_ty.unwrap_or_else(|| self.next_int_var())

compiler/rustc_lint/src/lints.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use rustc_hir as hir;
1111
use rustc_hir::def::Namespace;
1212
use rustc_hir::def_id::DefId;
1313
use rustc_hir::intravisit::VisitorExt;
14-
use rustc_macros::{LintDiagnostic, Subdiagnostic};
14+
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
1515
use rustc_middle::ty::inhabitedness::InhabitedPredicate;
1616
use rustc_middle::ty::{Clause, PolyExistentialTraitRef, Ty, TyCtxt};
1717
use rustc_session::Session;
@@ -1713,6 +1713,19 @@ pub(crate) struct OverflowingInt<'a> {
17131713
#[subdiagnostic]
17141714
pub help: Option<OverflowingIntHelp<'a>>,
17151715
}
1716+
#[derive(Diagnostic)]
1717+
#[diag(lint_overflowing_int)]
1718+
#[note]
1719+
pub(crate) struct OverflowingIntError<'a> {
1720+
#[primary_span]
1721+
pub span: Span,
1722+
pub ty: &'a str,
1723+
pub lit: String,
1724+
pub min: i128,
1725+
pub max: u128,
1726+
#[subdiagnostic]
1727+
pub help: Option<OverflowingIntHelp<'a>>,
1728+
}
17161729

17171730
#[derive(Subdiagnostic)]
17181731
#[help(lint_help)]
@@ -1738,6 +1751,18 @@ pub(crate) struct OverflowingUInt<'a> {
17381751
pub max: u128,
17391752
}
17401753

1754+
#[derive(Diagnostic)]
1755+
#[diag(lint_overflowing_uint)]
1756+
#[note]
1757+
pub(crate) struct OverflowingUIntError<'a> {
1758+
#[primary_span]
1759+
pub span: Span,
1760+
pub ty: &'a str,
1761+
pub lit: String,
1762+
pub min: u128,
1763+
pub max: u128,
1764+
}
1765+
17411766
#[derive(LintDiagnostic)]
17421767
#[diag(lint_overflowing_literal)]
17431768
#[note]

compiler/rustc_lint/src/types/literal.rs

Lines changed: 71 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ use crate::LateContext;
1111
use crate::context::LintContext;
1212
use crate::lints::{
1313
OnlyCastu8ToChar, OverflowingBinHex, OverflowingBinHexSign, OverflowingBinHexSignBitSub,
14-
OverflowingBinHexSub, OverflowingInt, OverflowingIntHelp, OverflowingLiteral, OverflowingUInt,
15-
RangeEndpointOutOfRange, UseInclusiveRange,
14+
OverflowingBinHexSub, OverflowingInt, OverflowingIntError, OverflowingIntHelp,
15+
OverflowingLiteral, OverflowingUInt, OverflowingUIntError, RangeEndpointOutOfRange,
16+
UseInclusiveRange,
1617
};
1718
use crate::types::{OVERFLOWING_LITERALS, TypeLimits};
1819

@@ -250,6 +251,7 @@ fn lint_int_literal<'tcx>(
250251
lit: &hir::Lit,
251252
t: ty::IntTy,
252253
v: u128,
254+
force_error: bool,
253255
) {
254256
let int_type = t.normalize(cx.sess().target.pointer_width);
255257
let (min, max) = int_ty_range(int_type);
@@ -287,11 +289,22 @@ fn lint_int_literal<'tcx>(
287289
let help = get_type_suggestion(cx.typeck_results().node_type(hir_id), v, negative)
288290
.map(|suggestion_ty| OverflowingIntHelp { suggestion_ty });
289291

290-
cx.emit_span_lint(
291-
OVERFLOWING_LITERALS,
292-
span,
293-
OverflowingInt { ty: t.name_str(), lit, min, max, help },
294-
);
292+
if force_error {
293+
cx.tcx.dcx().emit_err(OverflowingIntError {
294+
span,
295+
ty: t.name_str(),
296+
lit,
297+
min,
298+
max,
299+
help,
300+
});
301+
} else {
302+
cx.emit_span_lint(
303+
OVERFLOWING_LITERALS,
304+
span,
305+
OverflowingInt { ty: t.name_str(), lit, min, max, help },
306+
);
307+
}
295308
}
296309
}
297310

@@ -301,6 +314,7 @@ fn lint_uint_literal<'tcx>(
301314
span: Span,
302315
lit: &hir::Lit,
303316
t: ty::UintTy,
317+
force_error: bool,
304318
) {
305319
let uint_type = t.normalize(cx.sess().target.pointer_width);
306320
let (min, max) = uint_ty_range(uint_type);
@@ -344,10 +358,9 @@ fn lint_uint_literal<'tcx>(
344358
);
345359
return;
346360
}
347-
cx.emit_span_lint(
348-
OVERFLOWING_LITERALS,
349-
span,
350-
OverflowingUInt {
361+
if force_error {
362+
cx.tcx.dcx().emit_err(OverflowingUIntError {
363+
span,
351364
ty: t.name_str(),
352365
lit: cx
353366
.sess()
@@ -356,8 +369,23 @@ fn lint_uint_literal<'tcx>(
356369
.unwrap_or_else(|_| lit_val.to_string()),
357370
min,
358371
max,
359-
},
360-
);
372+
});
373+
} else {
374+
cx.emit_span_lint(
375+
OVERFLOWING_LITERALS,
376+
span,
377+
OverflowingUInt {
378+
ty: t.name_str(),
379+
lit: cx
380+
.sess()
381+
.source_map()
382+
.span_to_snippet(lit.span)
383+
.unwrap_or_else(|_| lit_val.to_string()),
384+
min,
385+
max,
386+
},
387+
);
388+
}
361389
}
362390
}
363391

@@ -369,18 +397,39 @@ pub(crate) fn lint_literal<'tcx>(
369397
lit: &hir::Lit,
370398
negated: bool,
371399
) {
372-
match *cx.typeck_results().node_type(hir_id).kind() {
400+
lint_literal_inner(
401+
cx,
402+
type_limits,
403+
hir_id,
404+
cx.typeck_results().node_type(hir_id),
405+
span,
406+
lit,
407+
negated,
408+
false,
409+
)
410+
}
411+
pub(crate) fn lint_literal_inner<'tcx>(
412+
cx: &LateContext<'tcx>,
413+
type_limits: &TypeLimits,
414+
hir_id: HirId,
415+
ty: Ty<'tcx>,
416+
span: Span,
417+
lit: &hir::Lit,
418+
negated: bool,
419+
force_error: bool,
420+
) {
421+
match *ty.kind() {
373422
ty::Int(t) => {
374423
match lit.node {
375424
ast::LitKind::Int(v, ast::LitIntType::Signed(_) | ast::LitIntType::Unsuffixed) => {
376-
lint_int_literal(cx, type_limits, hir_id, span, lit, t, v.get())
425+
lint_int_literal(cx, type_limits, hir_id, span, lit, t, v.get(), force_error)
377426
}
378427
_ => bug!(),
379428
};
380429
}
381430
ty::Uint(t) => {
382431
assert!(!negated);
383-
lint_uint_literal(cx, hir_id, span, lit, t)
432+
lint_uint_literal(cx, hir_id, span, lit, t, force_error)
384433
}
385434
ty::Float(t) => {
386435
let (is_infinite, sym) = match lit.node {
@@ -409,6 +458,12 @@ pub(crate) fn lint_literal<'tcx>(
409458
);
410459
}
411460
}
461+
ty::Pat(base, ..) if base.is_integral() => {
462+
lint_literal_inner(cx, type_limits, hir_id, base, span, lit, negated, true)
463+
}
464+
ty::Adt(adt, args) if cx.tcx.is_lang_item(adt.did(), hir::LangItem::NonZero) => {
465+
lint_literal_inner(cx, type_limits, hir_id, args.type_at(0), span, lit, negated, true)
466+
}
412467
_ => {}
413468
}
414469
}

compiler/rustc_mir_build/src/builder/expr/as_constant.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ fn lit_to_mir_constant<'tcx>(tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx>
107107

108108
let lit_ty = match *ty.kind() {
109109
ty::Pat(base, _) => base,
110+
ty::Adt(adt, args) if tcx.is_lang_item(adt.did(), LangItem::NonZero) => args.type_at(0),
110111
_ => ty,
111112
};
112113

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1+
//@ check-pass
2+
13
#![allow(overflowing_literals)]
24

35
fn main() {
46
let x: std::num::NonZero<i8> = -128;
5-
//~^ ERROR mismatched types
6-
//~| HELP consider calling `NonZero::new`
77
assert_eq!(x.get(), -128_i8);
88
}

tests/ui/mismatched_types/non_zero_assigned_lit.stderr

Lines changed: 0 additions & 18 deletions
This file was deleted.
Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1+
//! Ensure overflowing literals are not allowed for
2+
//! layout constrained types like `NonZero`, as that makes
3+
//! it harder to perform the layout checks. Instead
4+
//! we hard error if such literals are out of range.
5+
16
#![allow(overflowing_literals)]
27

38
fn main() {
49
let _: std::num::NonZero<u8> = 256;
5-
//~^ ERROR mismatched types
6-
//~| HELP consider calling `NonZero::new`
10+
//~^ ERROR literal out of range
711

812
let _: std::num::NonZero<i8> = -128;
9-
//~^ ERROR mismatched types
10-
//~| HELP consider calling `NonZero::new`
1113
let _: std::num::NonZero<i8> = -129;
12-
//~^ ERROR mismatched types
13-
//~| HELP consider calling `NonZero::new`
14+
//~^ ERROR literal out of range
1415
}
Lines changed: 9 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,18 @@
1-
error[E0308]: mismatched types
2-
--> $DIR/non_zero_assigned_oflo_lit.rs:4:36
1+
error: literal out of range for `u8`
2+
--> $DIR/non_zero_assigned_oflo_lit.rs:9:36
33
|
44
LL | let _: std::num::NonZero<u8> = 256;
5-
| --------------------- ^^^ expected `NonZero<u8>`, found integer
6-
| |
7-
| expected due to this
5+
| ^^^
86
|
9-
= note: expected struct `NonZero<u8>`
10-
found type `{integer}`
11-
help: consider calling `NonZero::new`
12-
|
13-
LL | let _: std::num::NonZero<u8> = NonZero::new(256).unwrap();
14-
| +++++++++++++ ++++++++++
15-
16-
error[E0308]: mismatched types
17-
--> $DIR/non_zero_assigned_oflo_lit.rs:8:36
18-
|
19-
LL | let _: std::num::NonZero<i8> = -128;
20-
| --------------------- ^^^^ expected `NonZero<i8>`, found integer
21-
| |
22-
| expected due to this
23-
|
24-
= note: expected struct `NonZero<i8>`
25-
found type `{integer}`
26-
help: consider calling `NonZero::new`
27-
|
28-
LL | let _: std::num::NonZero<i8> = NonZero::new(-128).unwrap();
29-
| +++++++++++++ ++++++++++
7+
= note: the literal `256` does not fit into the type `u8` whose range is `0..=255`
308

31-
error[E0308]: mismatched types
32-
--> $DIR/non_zero_assigned_oflo_lit.rs:11:36
9+
error: literal out of range for `i8`
10+
--> $DIR/non_zero_assigned_oflo_lit.rs:13:36
3311
|
3412
LL | let _: std::num::NonZero<i8> = -129;
35-
| --------------------- ^^^^ expected `NonZero<i8>`, found integer
36-
| |
37-
| expected due to this
38-
|
39-
= note: expected struct `NonZero<i8>`
40-
found type `{integer}`
41-
help: consider calling `NonZero::new`
13+
| ^^^^
4214
|
43-
LL | let _: std::num::NonZero<i8> = NonZero::new(-129).unwrap();
44-
| +++++++++++++ ++++++++++
15+
= note: the literal `-129` does not fit into the type `i8` whose range is `-128..=127`
4516

46-
error: aborting due to 3 previous errors
17+
error: aborting due to 2 previous errors
4718

48-
For more information about this error, try `rustc --explain E0308`.

tests/ui/mismatched_types/non_zero_assigned_something.rs

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,41 +7,34 @@ fn main() {
77
//~^ ERROR mismatched types
88
//~| HELP consider calling `NonZero::new`
99

10-
let _: std::num::NonZero<u64> = 1;
10+
let _: std::num::NonZero<u64> = 0;
11+
//~^ ERROR mismatched types
12+
//~| HELP consider calling `NonZero::new`
13+
14+
let _: Option<std::num::NonZero<u64>> = 0;
1115
//~^ ERROR mismatched types
1216
//~| HELP consider calling `NonZero::new`
17+
18+
let _: std::num::NonZero<u64> = 1;
1319
let _: std::num::NonZero<u64> = 1u8;
1420
//~^ ERROR mismatched types
1521
let _: std::num::NonZero<u64> = 1u64;
1622
//~^ ERROR mismatched types
1723
//~| HELP consider calling `NonZero::new`
1824

1925
let _: std::num::NonZero<u8> = 255;
20-
//~^ ERROR mismatched types
21-
//~| HELP consider calling `NonZero::new`
22-
let _: std::num::NonZero<u8> = 256;
23-
//~^ ERROR mismatched types
24-
//~| HELP consider calling `NonZero::new`
26+
let _: std::num::NonZero<u8> = 256; // errors only if no other errors occurred
2527

2628
let _: std::num::NonZero<u8> = -10;
27-
//~^ ERROR mismatched types
28-
//~| HELP consider calling `NonZero::new`
29+
//~^ ERROR cannot apply unary operator `-` to type `NonZero<u8>`
2930

3031
let _: std::num::NonZero<i8> = -128;
31-
//~^ ERROR mismatched types
32-
//~| HELP consider calling `NonZero::new`
33-
let _: std::num::NonZero<i8> = -129;
34-
//~^ ERROR mismatched types
35-
//~| HELP consider calling `NonZero::new`
32+
let _: std::num::NonZero<i8> = -129; // errors only if no other errors occurred
3633
let _: std::num::NonZero<i8> = -1;
37-
//~^ ERROR mismatched types
38-
//~| HELP consider calling `NonZero::new`
3934
let _: std::num::NonZero<i8> = 0;
4035
//~^ ERROR mismatched types
4136
//~| HELP consider calling `NonZero::new`
4237
let _: std::num::NonZero<i8> = 1;
43-
//~^ ERROR mismatched types
44-
//~| HELP consider calling `NonZero::new`
4538

4639
let _: Option<std::num::NonZero<u64>> = 1;
4740
//~^ ERROR mismatched types

0 commit comments

Comments
 (0)