Skip to content

Commit 5ef9944

Browse files
committed
On const pattern errors, point at the const item definition
Centralize emitting an error in `const_to_pat` so that all errors from that evaluating a `const` in a pattern can add addditional information. With this, now point at the `const` item's definition: ``` error[E0158]: constant pattern depends on a generic parameter --> $DIR/associated-const-type-parameter-pattern.rs:20:9 | LL | pub trait Foo { | ------------- LL | const X: EFoo; | ------------- constant defined here ... LL | A::X => println!("A::X"), | ^^^^ ```
1 parent bfe809d commit 5ef9944

File tree

46 files changed

+365
-43
lines changed

Some content is hidden

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

46 files changed

+365
-43
lines changed

compiler/rustc_mir_build/messages.ftl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ mir_build_call_to_unsafe_fn_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
8484
8585
mir_build_confused = missing patterns are not covered because `{$variable}` is interpreted as a constant pattern, not a new variable
8686
87+
mir_build_const_defined_here = constant defined here
88+
8789
mir_build_const_param_in_pattern = const parameters cannot be referenced in patterns
8890
8991
mir_build_const_pattern_depends_on_generic_parameter =

compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs

Lines changed: 70 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use rustc_abi::{FieldIdx, VariantIdx};
22
use rustc_apfloat::Float;
3+
use rustc_errors::{Diag, PResult};
34
use rustc_hir as hir;
45
use rustc_index::Idx;
56
use rustc_infer::infer::TyCtxtInferExt;
@@ -35,11 +36,14 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
3536
id: hir::HirId,
3637
span: Span,
3738
) -> Box<Pat<'tcx>> {
38-
let mut convert = ConstToPat::new(self, id, span);
39+
let mut convert = ConstToPat::new(self, id, span, c);
3940

4041
match c.kind() {
4142
ty::ConstKind::Unevaluated(uv) => convert.unevaluated_to_pat(uv, ty),
42-
ty::ConstKind::Value(_, val) => convert.valtree_to_pat(val, ty),
43+
ty::ConstKind::Value(_, val) => match convert.valtree_to_pat(val, ty) {
44+
Ok(pat) => pat,
45+
Err(err) => convert.mk_err(err, ty),
46+
},
4347
_ => span_bug!(span, "Invalid `ConstKind` for `const_to_pat`: {:?}", c),
4448
}
4549
}
@@ -51,10 +55,12 @@ struct ConstToPat<'tcx> {
5155
span: Span,
5256

5357
treat_byte_string_as_slice: bool,
58+
59+
c: ty::Const<'tcx>,
5460
}
5561

5662
impl<'tcx> ConstToPat<'tcx> {
57-
fn new(pat_ctxt: &PatCtxt<'_, 'tcx>, id: hir::HirId, span: Span) -> Self {
63+
fn new(pat_ctxt: &PatCtxt<'_, 'tcx>, id: hir::HirId, span: Span, c: ty::Const<'tcx>) -> Self {
5864
trace!(?pat_ctxt.typeck_results.hir_owner);
5965
ConstToPat {
6066
tcx: pat_ctxt.tcx,
@@ -64,20 +70,40 @@ impl<'tcx> ConstToPat<'tcx> {
6470
.typeck_results
6571
.treat_byte_string_as_slice
6672
.contains(&id.local_id),
73+
c,
6774
}
6875
}
6976

7077
fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool {
7178
ty.is_structural_eq_shallow(self.tcx)
7279
}
7380

81+
/// We errored. Signal that in the pattern, so that follow up errors can be silenced.
82+
fn mk_err(&self, mut err: Diag<'_>, ty: Ty<'tcx>) -> Box<Pat<'tcx>> {
83+
if let ty::ConstKind::Unevaluated(uv) = self.c.kind() {
84+
let def_kind = self.tcx.def_kind(uv.def);
85+
if let hir::def::DefKind::AssocConst = def_kind
86+
&& let Some(def_id) = uv.def.as_local()
87+
{
88+
// Include the container item in the output.
89+
err.span_label(self.tcx.def_span(self.tcx.local_parent(def_id)), "");
90+
}
91+
if let hir::def::DefKind::Const | hir::def::DefKind::AssocConst = def_kind {
92+
err.span_label(
93+
self.tcx.def_span(uv.def),
94+
crate::fluent_generated::mir_build_const_defined_here,
95+
);
96+
}
97+
}
98+
Box::new(Pat { span: self.span, ty, kind: PatKind::Error(err.emit()) })
99+
}
100+
74101
fn unevaluated_to_pat(
75102
&mut self,
76103
uv: ty::UnevaluatedConst<'tcx>,
77104
ty: Ty<'tcx>,
78105
) -> Box<Pat<'tcx>> {
79106
trace!(self.treat_byte_string_as_slice);
80-
let pat_from_kind = |kind| Box::new(Pat { span: self.span, ty, kind });
81107

82108
// It's not *technically* correct to be revealing opaque types here as borrowcheck has
83109
// not run yet. However, CTFE itself uses `Reveal::All` unconditionally even during
@@ -96,44 +122,46 @@ impl<'tcx> ConstToPat<'tcx> {
96122
Ok(Ok(c)) => c,
97123
Err(ErrorHandled::Reported(_, _)) => {
98124
// Let's tell the use where this failing const occurs.
99-
let e = self.tcx.dcx().emit_err(CouldNotEvalConstPattern { span: self.span });
100-
return pat_from_kind(PatKind::Error(e));
125+
let err = self.tcx.dcx().create_err(CouldNotEvalConstPattern { span: self.span });
126+
return self.mk_err(err, ty);
101127
}
102128
Err(ErrorHandled::TooGeneric(_)) => {
103129
let e = self
104130
.tcx
105131
.dcx()
106-
.emit_err(ConstPatternDependsOnGenericParameter { span: self.span });
107-
return pat_from_kind(PatKind::Error(e));
132+
.create_err(ConstPatternDependsOnGenericParameter { span: self.span });
133+
return self.mk_err(e, ty);
108134
}
109135
Ok(Err(bad_ty)) => {
110136
// The pattern cannot be turned into a valtree.
111137
let e = match bad_ty.kind() {
112138
ty::Adt(def, ..) => {
113139
assert!(def.is_union());
114-
self.tcx.dcx().emit_err(UnionPattern { span: self.span })
140+
self.tcx.dcx().create_err(UnionPattern { span: self.span })
115141
}
116142
ty::FnPtr(..) | ty::RawPtr(..) => {
117-
self.tcx.dcx().emit_err(PointerPattern { span: self.span })
143+
self.tcx.dcx().create_err(PointerPattern { span: self.span })
118144
}
119145
_ => self
120146
.tcx
121147
.dcx()
122-
.emit_err(InvalidPattern { span: self.span, non_sm_ty: bad_ty }),
148+
.create_err(InvalidPattern { span: self.span, non_sm_ty: bad_ty }),
123149
};
124-
return pat_from_kind(PatKind::Error(e));
150+
return self.mk_err(e, ty);
125151
}
126152
};
127153

128154
// Convert the valtree to a const.
129-
let inlined_const_as_pat = self.valtree_to_pat(valtree, ty);
155+
let inlined_const_as_pat = match self.valtree_to_pat(valtree, ty) {
156+
Ok(pat) => pat,
157+
Err(err) => self.mk_err(err, ty),
158+
};
130159

131160
if !inlined_const_as_pat.references_error() {
132161
// Always check for `PartialEq` if we had no other errors yet.
133162
if !self.type_has_partial_eq_impl(ty) {
134163
let err = TypeNotPartialEq { span: self.span, non_peq_ty: ty };
135-
let e = self.tcx.dcx().emit_err(err);
136-
return pat_from_kind(PatKind::Error(e));
164+
return self.mk_err(self.tcx.dcx().create_err(err), ty);
137165
}
138166
}
139167

@@ -175,14 +203,20 @@ impl<'tcx> ConstToPat<'tcx> {
175203
let field = FieldIdx::new(idx);
176204
// Patterns can only use monomorphic types.
177205
let ty = self.tcx.normalize_erasing_regions(self.typing_env, ty);
178-
FieldPat { field, pattern: self.valtree_to_pat(val, ty) }
206+
FieldPat {
207+
field,
208+
pattern: match self.valtree_to_pat(val, ty) {
209+
Ok(pat) => pat,
210+
Err(err) => self.mk_err(err, ty),
211+
},
212+
}
179213
})
180214
.collect()
181215
}
182216

183217
// Recursive helper for `to_pat`; invoke that (instead of calling this directly).
184218
#[instrument(skip(self), level = "debug")]
185-
fn valtree_to_pat(&self, cv: ValTree<'tcx>, ty: Ty<'tcx>) -> Box<Pat<'tcx>> {
219+
fn valtree_to_pat(&self, cv: ValTree<'tcx>, ty: Ty<'tcx>) -> PResult<'_, Box<Pat<'tcx>>> {
186220
let span = self.span;
187221
let tcx = self.tcx;
188222
let kind = match ty.kind() {
@@ -191,9 +225,7 @@ impl<'tcx> ConstToPat<'tcx> {
191225
// patterns.
192226
debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, ty);
193227
let err = TypeNotStructural { span, non_sm_ty: ty };
194-
let e = tcx.dcx().emit_err(err);
195-
// We errored. Signal that in the pattern, so that follow up errors can be silenced.
196-
PatKind::Error(e)
228+
return Err(tcx.dcx().create_err(err));
197229
}
198230
ty::Adt(adt_def, args) if adt_def.is_enum() => {
199231
let (&variant_index, fields) = cv.unwrap_branch().split_first().unwrap();
@@ -227,7 +259,10 @@ impl<'tcx> ConstToPat<'tcx> {
227259
prefix: cv
228260
.unwrap_branch()
229261
.iter()
230-
.map(|val| self.valtree_to_pat(*val, *elem_ty))
262+
.map(|val| match self.valtree_to_pat(*val, *elem_ty) {
263+
Ok(pat) => pat,
264+
Err(err) => self.mk_err(err, ty),
265+
})
231266
.collect(),
232267
slice: None,
233268
suffix: Box::new([]),
@@ -236,7 +271,10 @@ impl<'tcx> ConstToPat<'tcx> {
236271
prefix: cv
237272
.unwrap_branch()
238273
.iter()
239-
.map(|val| self.valtree_to_pat(*val, *elem_ty))
274+
.map(|val| match self.valtree_to_pat(*val, *elem_ty) {
275+
Ok(pat) => pat,
276+
Err(err) => self.mk_err(err, ty),
277+
})
240278
.collect(),
241279
slice: None,
242280
suffix: Box::new([]),
@@ -252,10 +290,9 @@ impl<'tcx> ConstToPat<'tcx> {
252290
// deref pattern.
253291
_ => {
254292
if !pointee_ty.is_sized(tcx, self.typing_env) && !pointee_ty.is_slice() {
255-
let err = UnsizedPattern { span, non_sm_ty: *pointee_ty };
256-
let e = tcx.dcx().emit_err(err);
257-
// We errored. Signal that in the pattern, so that follow up errors can be silenced.
258-
PatKind::Error(e)
293+
return Err(tcx
294+
.dcx()
295+
.create_err(UnsizedPattern { span, non_sm_ty: *pointee_ty }));
259296
} else {
260297
// `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when
261298
// matching against references, you can only use byte string literals.
@@ -270,7 +307,10 @@ impl<'tcx> ConstToPat<'tcx> {
270307
_ => *pointee_ty,
271308
};
272309
// References have the same valtree representation as their pointee.
273-
let subpattern = self.valtree_to_pat(cv, pointee_ty);
310+
let subpattern = match self.valtree_to_pat(cv, pointee_ty) {
311+
Ok(pat) => pat,
312+
Err(err) => self.mk_err(err, ty),
313+
};
274314
PatKind::Deref { subpattern }
275315
}
276316
}
@@ -286,8 +326,7 @@ impl<'tcx> ConstToPat<'tcx> {
286326
if is_nan {
287327
// NaNs are not ever equal to anything so they make no sense as patterns.
288328
// Also see <https://github.com/rust-lang/rfcs/pull/3535>.
289-
let e = tcx.dcx().emit_err(NaNPattern { span });
290-
PatKind::Error(e)
329+
return Err(tcx.dcx().create_err(NaNPattern { span }));
291330
} else {
292331
PatKind::Constant {
293332
value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)),
@@ -306,12 +345,10 @@ impl<'tcx> ConstToPat<'tcx> {
306345
}
307346
_ => {
308347
let err = InvalidPattern { span, non_sm_ty: ty };
309-
let e = tcx.dcx().emit_err(err);
310-
// We errored. Signal that in the pattern, so that follow up errors can be silenced.
311-
PatKind::Error(e)
348+
return Err(tcx.dcx().create_err(err));
312349
}
313350
};
314351

315-
Box::new(Pat { span, ty, kind })
352+
Ok(Box::new(Pat { span, ty, kind }))
316353
}
317354
}

tests/ui/associated-consts/associated-const-type-parameter-pattern.stderr

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,44 @@
11
error[E0158]: constant pattern depends on a generic parameter
22
--> $DIR/associated-const-type-parameter-pattern.rs:20:9
33
|
4+
LL | pub trait Foo {
5+
| -------------
6+
LL | const X: EFoo;
7+
| ------------- constant defined here
8+
...
49
LL | A::X => println!("A::X"),
510
| ^^^^
611

712
error[E0158]: constant pattern depends on a generic parameter
813
--> $DIR/associated-const-type-parameter-pattern.rs:22:9
914
|
15+
LL | pub trait Foo {
16+
| -------------
17+
LL | const X: EFoo;
18+
| ------------- constant defined here
19+
...
1020
LL | B::X => println!("B::X"),
1121
| ^^^^
1222

1323
error[E0158]: constant pattern depends on a generic parameter
1424
--> $DIR/associated-const-type-parameter-pattern.rs:30:9
1525
|
26+
LL | pub trait Foo {
27+
| -------------
28+
LL | const X: EFoo;
29+
| ------------- constant defined here
30+
...
1631
LL | let A::X = arg;
1732
| ^^^^
1833

1934
error[E0158]: constant pattern depends on a generic parameter
2035
--> $DIR/associated-const-type-parameter-pattern.rs:28:48
2136
|
37+
LL | pub trait Foo {
38+
| -------------
39+
LL | const X: EFoo;
40+
| ------------- constant defined here
41+
...
2242
LL | pub fn test_let_pat<A: Foo, B: Foo>(arg: EFoo, A::X: EFoo) {
2343
| ^^^^
2444

tests/ui/const_prop/ice-type-mismatch-when-copying-112824.stderr

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ LL | pub struct Opcode2<S>(&'a S);
2020
error: could not evaluate constant pattern
2121
--> $DIR/ice-type-mismatch-when-copying-112824.rs:15:9
2222
|
23+
LL | impl Opcode2 {
24+
| ------------
25+
LL | pub const OP2: Opcode2 = Opcode2(Opcode(0x1));
26+
| ---------------------- constant defined here
27+
...
2328
LL | Opcode2::OP2 => unimplemented!(),
2429
| ^^^^^^^^^^^^
2530

tests/ui/consts/const-eval/const-eval-overflow-2.stderr

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ LL | const NEG_NEG_128: i8 = -NEG_128;
77
error: could not evaluate constant pattern
88
--> $DIR/const-eval-overflow-2.rs:15:9
99
|
10+
LL | const NEG_NEG_128: i8 = -NEG_128;
11+
| --------------------- constant defined here
12+
...
1013
LL | NEG_NEG_128 => println!("A"),
1114
| ^^^^^^^^^^^
1215

tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ error: could not evaluate constant pattern
1212
|
1313
LL | 10..=BAR => {},
1414
| ^^^
15+
...
16+
LL | const BAR: Int = unsafe { Foo { r: &42 }.f };
17+
| -------------- constant defined here
1518

1619
error: aborting due to 2 previous errors
1720

tests/ui/consts/const_in_pattern/cross-crate-fail.stderr

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ error: to use a constant of type `CustomEq` in a pattern, `CustomEq` must be ann
44
LL | consts::SOME => panic!(),
55
| ^^^^^^^^^^^^
66
|
7+
::: $DIR/auxiliary/consts.rs:11:1
8+
|
9+
LL | pub const SOME: Option<CustomEq> = Some(CustomEq);
10+
| -------------------------------- constant defined here
11+
|
712
= note: the traits must be derived, manual `impl`s are not sufficient
813
= note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
914

@@ -13,6 +18,11 @@ error: to use a constant of type `CustomEq` in a pattern, `CustomEq` must be ann
1318
LL | <Defaulted as consts::AssocConst>::SOME => panic!(),
1419
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1520
|
21+
::: $DIR/auxiliary/consts.rs:15:5
22+
|
23+
LL | const SOME: Option<CustomEq> = Some(CustomEq);
24+
| ---------------------------- constant defined here
25+
|
1626
= note: the traits must be derived, manual `impl`s are not sufficient
1727
= note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
1828

tests/ui/consts/const_in_pattern/issue-34784-match-on-non-int-raw-ptr.stderr

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,36 @@
11
error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
22
--> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:9:9
33
|
4+
LL | const C: *const u8 = &0;
5+
| ------------------ constant defined here
6+
...
47
LL | C => {}
58
| ^
69

710
error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
811
--> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:16:9
912
|
13+
LL | const C_INNER: (*const u8, u8) = (C, 0);
14+
| ------------------------------ constant defined here
15+
...
1016
LL | C_INNER => {}
1117
| ^^^^^^^
1218

1319
error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
1420
--> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:27:9
1521
|
22+
LL | const D: *const [u8; 4] = b"abcd";
23+
| ----------------------- constant defined here
24+
...
1625
LL | D => {}
1726
| ^
1827

1928
error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
2029
--> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:32:9
2130
|
31+
LL | const STR: *const str = "abcd";
32+
| --------------------- constant defined here
33+
...
2234
LL | STR => {}
2335
| ^^^
2436

0 commit comments

Comments
 (0)