Skip to content

Commit 0d48c96

Browse files
committed
Auto merge of #50643 - dlrobertson:fix_ice, r=oli-obk
typeck: Fix ICE with struct update syntax If check_expr_struct_fields fails, do not continue to record update. If we continue to record update, the struct may cause us to ICE later on indexing a field that may or may not exist. Fixes: #50618
2 parents f9ae5bc + f6a46cf commit 0d48c96

File tree

3 files changed

+64
-18
lines changed

3 files changed

+64
-18
lines changed

src/librustc_typeck/check/mod.rs

+24-18
Original file line numberDiff line numberDiff line change
@@ -3278,7 +3278,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
32783278
span: Span,
32793279
variant: &'tcx ty::VariantDef,
32803280
ast_fields: &'gcx [hir::Field],
3281-
check_completeness: bool) {
3281+
check_completeness: bool) -> bool {
32823282
let tcx = self.tcx;
32833283

32843284
let adt_ty_hint =
@@ -3380,6 +3380,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
33803380
truncated_fields_error))
33813381
.emit();
33823382
}
3383+
error_happened
33833384
}
33843385

33853386
fn check_struct_fields_on_error(&self,
@@ -3478,24 +3479,29 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
34783479
}
34793480
}
34803481

3481-
self.check_expr_struct_fields(struct_ty, expected, expr.id, path_span, variant, fields,
3482-
base_expr.is_none());
3482+
let error_happened = self.check_expr_struct_fields(struct_ty, expected, expr.id, path_span,
3483+
variant, fields, base_expr.is_none());
34833484
if let &Some(ref base_expr) = base_expr {
3484-
self.check_expr_has_type_or_error(base_expr, struct_ty);
3485-
match struct_ty.sty {
3486-
ty::TyAdt(adt, substs) if adt.is_struct() => {
3487-
let fru_field_types = adt.non_enum_variant().fields.iter().map(|f| {
3488-
self.normalize_associated_types_in(expr.span, &f.ty(self.tcx, substs))
3489-
}).collect();
3490-
3491-
self.tables
3492-
.borrow_mut()
3493-
.fru_field_types_mut()
3494-
.insert(expr.hir_id, fru_field_types);
3495-
}
3496-
_ => {
3497-
span_err!(self.tcx.sess, base_expr.span, E0436,
3498-
"functional record update syntax requires a struct");
3485+
// If check_expr_struct_fields hit an error, do not attempt to populate
3486+
// the fields with the base_expr. This could cause us to hit errors later
3487+
// when certain fields are assumed to exist that in fact do not.
3488+
if !error_happened {
3489+
self.check_expr_has_type_or_error(base_expr, struct_ty);
3490+
match struct_ty.sty {
3491+
ty::TyAdt(adt, substs) if adt.is_struct() => {
3492+
let fru_field_types = adt.non_enum_variant().fields.iter().map(|f| {
3493+
self.normalize_associated_types_in(expr.span, &f.ty(self.tcx, substs))
3494+
}).collect();
3495+
3496+
self.tables
3497+
.borrow_mut()
3498+
.fru_field_types_mut()
3499+
.insert(expr.hir_id, fru_field_types);
3500+
}
3501+
_ => {
3502+
span_err!(self.tcx.sess, base_expr.span, E0436,
3503+
"functional record update syntax requires a struct");
3504+
}
34993505
}
35003506
}
35013507
}

src/test/ui/issue-50618.rs

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
struct Point {
12+
pub x: u64,
13+
pub y: u64,
14+
}
15+
16+
const TEMPLATE: Point = Point {
17+
x: 0,
18+
y: 0
19+
};
20+
21+
fn main() {
22+
let _ = || {
23+
Point {
24+
nonexistent: 0,
25+
//~^ ERROR struct `Point` has no field named `nonexistent`
26+
..TEMPLATE
27+
}
28+
};
29+
}

src/test/ui/issue-50618.stderr

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0560]: struct `Point` has no field named `nonexistent`
2+
--> $DIR/issue-50618.rs:24:13
3+
|
4+
LL | nonexistent: 0,
5+
| ^^^^^^^^^^^ `Point` does not have this field
6+
|
7+
= note: available fields are: `x`, `y`
8+
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0560`.

0 commit comments

Comments
 (0)