Skip to content

Commit cd9959a

Browse files
committed
Allow initializing NonZero with literals
1 parent 25bbcfc commit cd9959a

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
@@ -735,6 +735,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
735735
_ => unreachable!(),
736736
}
737737
}
738+
ty::Adt(adt, ..) if tcx.is_lang_item(adt.did(), LangItem::NonZero) => {
739+
if i.get() == 0 {
740+
// FIXME: report a nice error
741+
None
742+
} else {
743+
Some(ty)
744+
}
745+
}
738746
_ => None,
739747
});
740748
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_errors::{
1111
use rustc_hir as hir;
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;
@@ -1704,6 +1704,19 @@ pub(crate) struct OverflowingInt<'a> {
17041704
#[subdiagnostic]
17051705
pub help: Option<OverflowingIntHelp<'a>>,
17061706
}
1707+
#[derive(Diagnostic)]
1708+
#[diag(lint_overflowing_int)]
1709+
#[note]
1710+
pub(crate) struct OverflowingIntError<'a> {
1711+
#[primary_span]
1712+
pub span: Span,
1713+
pub ty: &'a str,
1714+
pub lit: String,
1715+
pub min: i128,
1716+
pub max: u128,
1717+
#[subdiagnostic]
1718+
pub help: Option<OverflowingIntHelp<'a>>,
1719+
}
17071720

17081721
#[derive(Subdiagnostic)]
17091722
#[help(lint_help)]
@@ -1729,6 +1742,18 @@ pub(crate) struct OverflowingUInt<'a> {
17291742
pub max: u128,
17301743
}
17311744

1745+
#[derive(Diagnostic)]
1746+
#[diag(lint_overflowing_uint)]
1747+
#[note]
1748+
pub(crate) struct OverflowingUIntError<'a> {
1749+
#[primary_span]
1750+
pub span: Span,
1751+
pub ty: &'a str,
1752+
pub lit: String,
1753+
pub min: u128,
1754+
pub max: u128,
1755+
}
1756+
17321757
#[derive(LintDiagnostic)]
17331758
#[diag(lint_overflowing_literal)]
17341759
#[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, SurrogateCharCast, TooLargeCharCast, UseInclusiveRange,
14+
OverflowingBinHexSub, OverflowingInt, OverflowingIntError, OverflowingIntHelp,
15+
OverflowingLiteral, OverflowingUInt, OverflowingUIntError, RangeEndpointOutOfRange,
16+
SurrogateCharCast, TooLargeCharCast, UseInclusiveRange,
1617
};
1718
use crate::types::{OVERFLOWING_LITERALS, TypeLimits};
1819

@@ -258,6 +259,7 @@ fn lint_int_literal<'tcx>(
258259
lit: &hir::Lit,
259260
t: ty::IntTy,
260261
v: u128,
262+
force_error: bool,
261263
) {
262264
let int_type = t.normalize(cx.sess().target.pointer_width);
263265
let (min, max) = int_ty_range(int_type);
@@ -295,11 +297,22 @@ fn lint_int_literal<'tcx>(
295297
let help = get_type_suggestion(cx.typeck_results().node_type(hir_id), v, negative)
296298
.map(|suggestion_ty| OverflowingIntHelp { suggestion_ty });
297299

298-
cx.emit_span_lint(
299-
OVERFLOWING_LITERALS,
300-
span,
301-
OverflowingInt { ty: t.name_str(), lit, min, max, help },
302-
);
300+
if force_error {
301+
cx.tcx.dcx().emit_err(OverflowingIntError {
302+
span,
303+
ty: t.name_str(),
304+
lit,
305+
min,
306+
max,
307+
help,
308+
});
309+
} else {
310+
cx.emit_span_lint(
311+
OVERFLOWING_LITERALS,
312+
span,
313+
OverflowingInt { ty: t.name_str(), lit, min, max, help },
314+
);
315+
}
303316
}
304317
}
305318

@@ -309,6 +322,7 @@ fn lint_uint_literal<'tcx>(
309322
span: Span,
310323
lit: &hir::Lit,
311324
t: ty::UintTy,
325+
force_error: bool,
312326
) {
313327
let uint_type = t.normalize(cx.sess().target.pointer_width);
314328
let (min, max) = uint_ty_range(uint_type);
@@ -366,10 +380,9 @@ fn lint_uint_literal<'tcx>(
366380
);
367381
return;
368382
}
369-
cx.emit_span_lint(
370-
OVERFLOWING_LITERALS,
371-
span,
372-
OverflowingUInt {
383+
if force_error {
384+
cx.tcx.dcx().emit_err(OverflowingUIntError {
385+
span,
373386
ty: t.name_str(),
374387
lit: cx
375388
.sess()
@@ -378,8 +391,23 @@ fn lint_uint_literal<'tcx>(
378391
.unwrap_or_else(|_| lit_val.to_string()),
379392
min,
380393
max,
381-
},
382-
);
394+
});
395+
} else {
396+
cx.emit_span_lint(
397+
OVERFLOWING_LITERALS,
398+
span,
399+
OverflowingUInt {
400+
ty: t.name_str(),
401+
lit: cx
402+
.sess()
403+
.source_map()
404+
.span_to_snippet(lit.span)
405+
.unwrap_or_else(|_| lit_val.to_string()),
406+
min,
407+
max,
408+
},
409+
);
410+
}
383411
}
384412
}
385413

@@ -391,18 +419,39 @@ pub(crate) fn lint_literal<'tcx>(
391419
lit: &hir::Lit,
392420
negated: bool,
393421
) {
394-
match *cx.typeck_results().node_type(hir_id).kind() {
422+
lint_literal_inner(
423+
cx,
424+
type_limits,
425+
hir_id,
426+
cx.typeck_results().node_type(hir_id),
427+
span,
428+
lit,
429+
negated,
430+
false,
431+
)
432+
}
433+
pub(crate) fn lint_literal_inner<'tcx>(
434+
cx: &LateContext<'tcx>,
435+
type_limits: &TypeLimits,
436+
hir_id: HirId,
437+
ty: Ty<'tcx>,
438+
span: Span,
439+
lit: &hir::Lit,
440+
negated: bool,
441+
force_error: bool,
442+
) {
443+
match *ty.kind() {
395444
ty::Int(t) => {
396445
match lit.node {
397446
ast::LitKind::Int(v, ast::LitIntType::Signed(_) | ast::LitIntType::Unsuffixed) => {
398-
lint_int_literal(cx, type_limits, hir_id, span, lit, t, v.get())
447+
lint_int_literal(cx, type_limits, hir_id, span, lit, t, v.get(), force_error)
399448
}
400449
_ => bug!(),
401450
};
402451
}
403452
ty::Uint(t) => {
404453
assert!(!negated);
405-
lint_uint_literal(cx, hir_id, span, lit, t)
454+
lint_uint_literal(cx, hir_id, span, lit, t, force_error)
406455
}
407456
ty::Float(t) => {
408457
let (is_infinite, sym) = match lit.node {
@@ -431,6 +480,12 @@ pub(crate) fn lint_literal<'tcx>(
431480
);
432481
}
433482
}
483+
ty::Pat(base, ..) if base.is_integral() => {
484+
lint_literal_inner(cx, type_limits, hir_id, base, span, lit, negated, true)
485+
}
486+
ty::Adt(adt, args) if cx.tcx.is_lang_item(adt.did(), hir::LangItem::NonZero) => {
487+
lint_literal_inner(cx, type_limits, hir_id, args.type_at(0), span, lit, negated, true)
488+
}
434489
_ => {}
435490
}
436491
}

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)