Skip to content

Commit 7041b65

Browse files
dlrobertsonpietroalbini
authored andcommitted
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.
1 parent 046bb83 commit 7041b65

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
@@ -3275,7 +3275,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
32753275
span: Span,
32763276
variant: &'tcx ty::VariantDef,
32773277
ast_fields: &'gcx [hir::Field],
3278-
check_completeness: bool) {
3278+
check_completeness: bool) -> bool {
32793279
let tcx = self.tcx;
32803280

32813281
let adt_ty_hint =
@@ -3377,6 +3377,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
33773377
truncated_fields_error))
33783378
.emit();
33793379
}
3380+
error_happened
33803381
}
33813382

33823383
fn check_struct_fields_on_error(&self,
@@ -3475,24 +3476,29 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
34753476
}
34763477
}
34773478

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

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)