Skip to content

Commit 481d220

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 bcfea1f commit 481d220

File tree

46 files changed

+365
-42
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
-42
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 & 32 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::{InferCtxt, TyCtxtInferExt};
@@ -38,11 +39,14 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
3839
// FIXME(#132279): We likely want to be able to reveal the hidden types
3940
// of opaques defined in this function here.
4041
let infcx = self.tcx.infer_ctxt().build(TypingMode::non_body_analysis());
41-
let mut convert = ConstToPat::new(self, id, span, infcx);
42+
let mut convert = ConstToPat::new(self, id, span, infcx, c);
4243

4344
match c.kind() {
4445
ty::ConstKind::Unevaluated(uv) => convert.unevaluated_to_pat(uv, ty),
45-
ty::ConstKind::Value(_, val) => convert.valtree_to_pat(val, ty),
46+
ty::ConstKind::Value(_, val) => match convert.valtree_to_pat(val, ty) {
47+
Ok(pat) => pat,
48+
Err(err) => convert.mk_err(err, ty),
49+
},
4650
_ => span_bug!(span, "Invalid `ConstKind` for `const_to_pat`: {:?}", c),
4751
}
4852
}
@@ -56,6 +60,8 @@ struct ConstToPat<'tcx> {
5660
param_env: ty::ParamEnv<'tcx>,
5761

5862
treat_byte_string_as_slice: bool,
63+
64+
c: ty::Const<'tcx>,
5965
}
6066

6167
impl<'tcx> ConstToPat<'tcx> {
@@ -64,6 +70,7 @@ impl<'tcx> ConstToPat<'tcx> {
6470
id: hir::HirId,
6571
span: Span,
6672
infcx: InferCtxt<'tcx>,
73+
c: ty::Const<'tcx>,
6774
) -> Self {
6875
trace!(?pat_ctxt.typeck_results.hir_owner);
6976
ConstToPat {
@@ -74,6 +81,7 @@ impl<'tcx> ConstToPat<'tcx> {
7481
.typeck_results
7582
.treat_byte_string_as_slice
7683
.contains(&id.local_id),
84+
c,
7785
}
7886
}
7987

@@ -89,13 +97,32 @@ impl<'tcx> ConstToPat<'tcx> {
8997
ty.is_structural_eq_shallow(self.infcx.tcx)
9098
}
9199

100+
/// We errored. Signal that in the pattern, so that follow up errors can be silenced.
101+
fn mk_err(&self, mut err: Diag<'_>, ty: Ty<'tcx>) -> Box<Pat<'tcx>> {
102+
if let ty::ConstKind::Unevaluated(uv) = self.c.kind() {
103+
let def_kind = self.tcx().def_kind(uv.def);
104+
if let hir::def::DefKind::AssocConst = def_kind
105+
&& let Some(def_id) = uv.def.as_local()
106+
{
107+
// Include the container item in the output.
108+
err.span_label(self.tcx().def_span(self.tcx().local_parent(def_id)), "");
109+
}
110+
if let hir::def::DefKind::Const | hir::def::DefKind::AssocConst = def_kind {
111+
err.span_label(
112+
self.tcx().def_span(uv.def),
113+
crate::fluent_generated::mir_build_const_defined_here,
114+
);
115+
}
116+
}
117+
Box::new(Pat { span: self.span, ty, kind: PatKind::Error(err.emit()) })
118+
}
119+
92120
fn unevaluated_to_pat(
93121
&mut self,
94122
uv: ty::UnevaluatedConst<'tcx>,
95123
ty: Ty<'tcx>,
96124
) -> Box<Pat<'tcx>> {
97125
trace!(self.treat_byte_string_as_slice);
98-
let pat_from_kind = |kind| Box::new(Pat { span: self.span, ty, kind });
99126

100127
// It's not *technically* correct to be revealing opaque types here as borrowcheck has
101128
// not run yet. However, CTFE itself uses `Reveal::All` unconditionally even during
@@ -115,44 +142,46 @@ impl<'tcx> ConstToPat<'tcx> {
115142
Ok(Ok(c)) => c,
116143
Err(ErrorHandled::Reported(_, _)) => {
117144
// Let's tell the use where this failing const occurs.
118-
let e = self.tcx().dcx().emit_err(CouldNotEvalConstPattern { span: self.span });
119-
return pat_from_kind(PatKind::Error(e));
145+
let err = self.tcx().dcx().create_err(CouldNotEvalConstPattern { span: self.span });
146+
return self.mk_err(err, ty);
120147
}
121148
Err(ErrorHandled::TooGeneric(_)) => {
122149
let e = self
123150
.tcx()
124151
.dcx()
125-
.emit_err(ConstPatternDependsOnGenericParameter { span: self.span });
126-
return pat_from_kind(PatKind::Error(e));
152+
.create_err(ConstPatternDependsOnGenericParameter { span: self.span });
153+
return self.mk_err(e, ty);
127154
}
128155
Ok(Err(bad_ty)) => {
129156
// The pattern cannot be turned into a valtree.
130157
let e = match bad_ty.kind() {
131158
ty::Adt(def, ..) => {
132159
assert!(def.is_union());
133-
self.tcx().dcx().emit_err(UnionPattern { span: self.span })
160+
self.tcx().dcx().create_err(UnionPattern { span: self.span })
134161
}
135162
ty::FnPtr(..) | ty::RawPtr(..) => {
136-
self.tcx().dcx().emit_err(PointerPattern { span: self.span })
163+
self.tcx().dcx().create_err(PointerPattern { span: self.span })
137164
}
138165
_ => self
139166
.tcx()
140167
.dcx()
141-
.emit_err(InvalidPattern { span: self.span, non_sm_ty: bad_ty }),
168+
.create_err(InvalidPattern { span: self.span, non_sm_ty: bad_ty }),
142169
};
143-
return pat_from_kind(PatKind::Error(e));
170+
return self.mk_err(e, ty);
144171
}
145172
};
146173

147174
// Convert the valtree to a const.
148-
let inlined_const_as_pat = self.valtree_to_pat(valtree, ty);
175+
let inlined_const_as_pat = match self.valtree_to_pat(valtree, ty) {
176+
Ok(pat) => pat,
177+
Err(err) => self.mk_err(err, ty),
178+
};
149179

150180
if !inlined_const_as_pat.references_error() {
151181
// Always check for `PartialEq` if we had no other errors yet.
152182
if !self.type_has_partial_eq_impl(ty) {
153183
let err = TypeNotPartialEq { span: self.span, non_peq_ty: ty };
154-
let e = self.tcx().dcx().emit_err(err);
155-
return pat_from_kind(PatKind::Error(e));
184+
return self.mk_err(self.tcx().dcx().create_err(err), ty);
156185
}
157186
}
158187

@@ -193,14 +222,20 @@ impl<'tcx> ConstToPat<'tcx> {
193222
let field = FieldIdx::new(idx);
194223
// Patterns can only use monomorphic types.
195224
let ty = self.tcx().normalize_erasing_regions(self.typing_env(), ty);
196-
FieldPat { field, pattern: self.valtree_to_pat(val, ty) }
225+
FieldPat {
226+
field,
227+
pattern: match self.valtree_to_pat(val, ty) {
228+
Ok(pat) => pat,
229+
Err(err) => self.mk_err(err, ty),
230+
},
231+
}
197232
})
198233
.collect()
199234
}
200235

201236
// Recursive helper for `to_pat`; invoke that (instead of calling this directly).
202237
#[instrument(skip(self), level = "debug")]
203-
fn valtree_to_pat(&self, cv: ValTree<'tcx>, ty: Ty<'tcx>) -> Box<Pat<'tcx>> {
238+
fn valtree_to_pat(&self, cv: ValTree<'tcx>, ty: Ty<'tcx>) -> PResult<'_, Box<Pat<'tcx>>> {
204239
let span = self.span;
205240
let tcx = self.tcx();
206241
let param_env = self.param_env;
@@ -211,9 +246,7 @@ impl<'tcx> ConstToPat<'tcx> {
211246
// patterns.
212247
debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, ty,);
213248
let err = TypeNotStructural { span, non_sm_ty: ty };
214-
let e = tcx.dcx().emit_err(err);
215-
// We errored. Signal that in the pattern, so that follow up errors can be silenced.
216-
PatKind::Error(e)
249+
return Err(tcx.dcx().create_err(err));
217250
}
218251
ty::Adt(adt_def, args) if adt_def.is_enum() => {
219252
let (&variant_index, fields) = cv.unwrap_branch().split_first().unwrap();
@@ -252,7 +285,10 @@ impl<'tcx> ConstToPat<'tcx> {
252285
prefix: cv
253286
.unwrap_branch()
254287
.iter()
255-
.map(|val| self.valtree_to_pat(*val, *elem_ty))
288+
.map(|val| match self.valtree_to_pat(*val, *elem_ty) {
289+
Ok(pat) => pat,
290+
Err(err) => self.mk_err(err, ty),
291+
})
256292
.collect(),
257293
slice: None,
258294
suffix: Box::new([]),
@@ -261,7 +297,10 @@ impl<'tcx> ConstToPat<'tcx> {
261297
prefix: cv
262298
.unwrap_branch()
263299
.iter()
264-
.map(|val| self.valtree_to_pat(*val, *elem_ty))
300+
.map(|val| match self.valtree_to_pat(*val, *elem_ty) {
301+
Ok(pat) => pat,
302+
Err(err) => self.mk_err(err, ty),
303+
})
265304
.collect(),
266305
slice: None,
267306
suffix: Box::new([]),
@@ -277,10 +316,9 @@ impl<'tcx> ConstToPat<'tcx> {
277316
// deref pattern.
278317
_ => {
279318
if !pointee_ty.is_sized(tcx, param_env) && !pointee_ty.is_slice() {
280-
let err = UnsizedPattern { span, non_sm_ty: *pointee_ty };
281-
let e = tcx.dcx().emit_err(err);
282-
// We errored. Signal that in the pattern, so that follow up errors can be silenced.
283-
PatKind::Error(e)
319+
return Err(tcx
320+
.dcx()
321+
.create_err(UnsizedPattern { span, non_sm_ty: *pointee_ty }));
284322
} else {
285323
// `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when
286324
// matching against references, you can only use byte string literals.
@@ -295,7 +333,10 @@ impl<'tcx> ConstToPat<'tcx> {
295333
_ => *pointee_ty,
296334
};
297335
// References have the same valtree representation as their pointee.
298-
let subpattern = self.valtree_to_pat(cv, pointee_ty);
336+
let subpattern = match self.valtree_to_pat(cv, pointee_ty) {
337+
Ok(pat) => pat,
338+
Err(err) => self.mk_err(err, ty),
339+
};
299340
PatKind::Deref { subpattern }
300341
}
301342
}
@@ -311,8 +352,7 @@ impl<'tcx> ConstToPat<'tcx> {
311352
if is_nan {
312353
// NaNs are not ever equal to anything so they make no sense as patterns.
313354
// Also see <https://github.com/rust-lang/rfcs/pull/3535>.
314-
let e = tcx.dcx().emit_err(NaNPattern { span });
315-
PatKind::Error(e)
355+
return Err(tcx.dcx().create_err(NaNPattern { span }));
316356
} else {
317357
PatKind::Constant {
318358
value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)),
@@ -331,12 +371,10 @@ impl<'tcx> ConstToPat<'tcx> {
331371
}
332372
_ => {
333373
let err = InvalidPattern { span, non_sm_ty: ty };
334-
let e = tcx.dcx().emit_err(err);
335-
// We errored. Signal that in the pattern, so that follow up errors can be silenced.
336-
PatKind::Error(e)
374+
return Err(tcx.dcx().create_err(err));
337375
}
338376
};
339377

340-
Box::new(Pat { span, ty, kind })
378+
Ok(Box::new(Pat { span, ty, kind }))
341379
}
342380
}

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)