Skip to content

Commit b62c38f

Browse files
committed
error on unsupported state type
1 parent 0bb9c46 commit b62c38f

File tree

6 files changed

+101
-4
lines changed

6 files changed

+101
-4
lines changed

compiler/rustc_mir_build/messages.ftl

+4
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,10 @@ mir_build_loop_match_invalid_update =
237237
mir_build_loop_match_missing_assignment =
238238
expected a single assignment expression
239239
240+
mir_build_loop_match_unsupported_type =
241+
this `#[loop_match]` state value has type `{$ty}`, which is not supported
242+
.note = only integers and enums without fields are supported
243+
240244
mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper =
241245
lower range bound must be less than or equal to upper
242246
.label = lower bound larger than upper bound

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

+30-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_hir::lang_items::LangItem;
88
use rustc_middle::mir::*;
99
use rustc_middle::span_bug;
1010
use rustc_middle::thir::*;
11-
use rustc_middle::ty::{CanonicalUserTypeAnnotation, Ty};
11+
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty};
1212
use rustc_span::DUMMY_SP;
1313
use rustc_span::source_map::Spanned;
1414
use rustc_trait_selection::infer::InferCtxtExt;
@@ -17,7 +17,7 @@ use tracing::{debug, instrument};
1717
use crate::builder::expr::category::{Category, RvalueFunc};
1818
use crate::builder::matches::{DeclareLetBindings, HasMatchGuard};
1919
use crate::builder::{BlockAnd, BlockAndExtension, BlockFrame, Builder, NeedsTemporary};
20-
use crate::errors::LoopMatchArmWithGuard;
20+
use crate::errors::{LoopMatchArmWithGuard, LoopMatchUnsupportedType};
2121

2222
impl<'a, 'tcx> Builder<'a, 'tcx> {
2323
/// Compile `expr`, storing the result into `destination`, which
@@ -253,6 +253,34 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
253253
// `in_const_continuable_scope`, which makes the match arms and their target basic
254254
// block available to the lowering of `#[const_continue]`.
255255

256+
fn is_supported_loop_match_type(ty: Ty<'_>) -> bool {
257+
if ty.is_integral() {
258+
return true;
259+
}
260+
261+
if let Some(adt_def) = ty.ty_adt_def() {
262+
if adt_def.adt_kind() != ty::AdtKind::Enum {
263+
return false;
264+
}
265+
266+
for variant in adt_def.variants() {
267+
if !variant.fields.is_empty() {
268+
return false;
269+
}
270+
}
271+
272+
return true;
273+
}
274+
275+
false
276+
}
277+
278+
let state_ty = this.thir.exprs[state].ty;
279+
if !is_supported_loop_match_type(state_ty) {
280+
let span = this.thir.exprs[state].span;
281+
this.tcx.dcx().emit_fatal(LoopMatchUnsupportedType { span, ty: state_ty })
282+
}
283+
256284
let loop_block = this.cfg.start_new_block();
257285

258286
// Start the loop.

compiler/rustc_mir_build/src/builder/matches/mod.rs

+23-2
Original file line numberDiff line numberDiff line change
@@ -2972,8 +2972,29 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
29722972
IntRange::from_singleton(actual_int).is_subrange(int_range)
29732973
}
29742974
Constructor::Wildcard => true,
2975-
// FIXME error out before static_pattern_match gets run and replace this with bug!()
2976-
_ => false,
2975+
2976+
// these we may eventually support
2977+
Constructor::Struct
2978+
| Constructor::Ref
2979+
| Constructor::Slice(_)
2980+
| Constructor::UnionField
2981+
| Constructor::Or
2982+
| Constructor::Bool(_)
2983+
| Constructor::F16Range(..)
2984+
| Constructor::F32Range(..)
2985+
| Constructor::F64Range(..)
2986+
| Constructor::F128Range(..)
2987+
| Constructor::Str(_) => bug!("unsupported pattern constructor {:?}", pat.ctor()),
2988+
2989+
// these should never occur here
2990+
Constructor::Opaque(_)
2991+
| Constructor::Never
2992+
| Constructor::NonExhaustive
2993+
| Constructor::Hidden
2994+
| Constructor::Missing
2995+
| Constructor::PrivateUninhabited => {
2996+
bug!("unsupported pattern constructor {:?}", pat.ctor())
2997+
}
29772998
}
29782999
}
29793000
}

compiler/rustc_mir_build/src/errors.rs

+9
Original file line numberDiff line numberDiff line change
@@ -1179,6 +1179,15 @@ pub(crate) struct LoopMatchInvalidMatch {
11791179
pub span: Span,
11801180
}
11811181

1182+
#[derive(Diagnostic)]
1183+
#[diag(mir_build_loop_match_unsupported_type)]
1184+
#[note]
1185+
pub(crate) struct LoopMatchUnsupportedType<'tcx> {
1186+
#[primary_span]
1187+
pub span: Span,
1188+
pub ty: Ty<'tcx>,
1189+
}
1190+
11821191
#[derive(Diagnostic)]
11831192
#[diag(mir_build_loop_match_bad_statements)]
11841193
pub(crate) struct LoopMatchBadStatements {
+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Test that a good error is emitted when the #[loop_match] state is an unsupported type
2+
#![allow(incomplete_features)]
3+
#![feature(loop_match)]
4+
#![crate_type = "lib"]
5+
6+
fn unsupported_type() {
7+
let mut state = Some(false);
8+
#[loop_match]
9+
'a: loop {
10+
state = 'blk: {
11+
//~^ ERROR this `#[loop_match]` state value has type `Option<bool>`, which is not supported
12+
match state {
13+
Some(false) => {
14+
#[const_continue]
15+
break 'blk Some(true);
16+
}
17+
Some(true) => {
18+
#[const_continue]
19+
break 'blk None;
20+
}
21+
None => break 'a,
22+
}
23+
}
24+
}
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: this `#[loop_match]` state value has type `Option<bool>`, which is not supported
2+
--> $DIR/unsupported-type.rs:10:9
3+
|
4+
LL | state = 'blk: {
5+
| ^^^^^
6+
|
7+
= note: only integers and enums without fields are supported
8+
9+
error: aborting due to 1 previous error
10+

0 commit comments

Comments
 (0)