Skip to content

Commit

Permalink
add relaxed_struct_unsize feature gate
Browse files Browse the repository at this point in the history
  • Loading branch information
lcnr committed Feb 3, 2021
1 parent 50e394a commit 031cce8
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 15 deletions.
3 changes: 3 additions & 0 deletions compiler/rustc_feature/src/active.rs
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,9 @@ declare_features! (

/// Allows `extern "C-cmse-nonsecure-call" fn()`.
(active, abi_c_cmse_nonsecure_call, "1.51.0", Some(81391), None),

/// Lessens the requirements for structs to implement `Unsize`.
(active, relaxed_struct_unsize, "1.51.0", Some(1), None),
// -------------------------------------------------------------------------
// feature-group-end: actual feature gates
// -------------------------------------------------------------------------
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -907,6 +907,7 @@ symbols! {
register_attr,
register_tool,
relaxed_adts,
relaxed_struct_unsize,
rem,
rem_assign,
repr,
Expand Down
59 changes: 44 additions & 15 deletions compiler/rustc_trait_selection/src/traits/select/confirmation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -823,33 +823,62 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
},
};

// FIXME(eddyb) cache this (including computing `unsizing_params`)
// by putting it in a query; it would only need the `DefId` as it
// looks at declared field types, not anything substituted.

// The last field of the structure has to exist and contain type/const parameters.
let (tail_field, prefix_fields) =
def.non_enum_variant().fields.split_last().ok_or(Unimplemented)?;
let tail_field_ty = tcx.type_of(tail_field.did);

let mut unsizing_params = GrowableBitSet::new_empty();
for arg in tail_field_ty.walk() {
if let Some(i) = maybe_unsizing_param_idx(arg) {
unsizing_params.insert(i);
if tcx.features().relaxed_struct_unsize {
for arg in tail_field_ty.walk() {
if let Some(i) = maybe_unsizing_param_idx(arg) {
unsizing_params.insert(i);
}
}
}

// Ensure none of the other fields mention the parameters used
// in unsizing.
// FIXME(eddyb) cache this (including computing `unsizing_params`)
// by putting it in a query; it would only need the `DefId` as it
// looks at declared field types, not anything substituted.
for field in prefix_fields {
for arg in tcx.type_of(field.did).walk() {
// Ensure none of the other fields mention the parameters used
// in unsizing.
for field in prefix_fields {
for arg in tcx.type_of(field.did).walk() {
if let Some(i) = maybe_unsizing_param_idx(arg) {
unsizing_params.remove(i);
}
}
}

if unsizing_params.is_empty() {
return Err(Unimplemented);
}
} else {
let mut found = false;
for arg in tail_field_ty.walk() {
if let Some(i) = maybe_unsizing_param_idx(arg) {
unsizing_params.remove(i);
unsizing_params.insert(i);
found = true;
}
}
}
if !found {
return Err(Unimplemented);
}

if unsizing_params.is_empty() {
return Err(Unimplemented);
// Ensure none of the other fields mention the parameters used
// in unsizing.
// FIXME(eddyb) cache this (including computing `unsizing_params`)
// by putting it in a query; it would only need the `DefId` as it
// looks at declared field types, not anything substituted.
for field in prefix_fields {
for arg in tcx.type_of(field.did).walk() {
if let Some(i) = maybe_unsizing_param_idx(arg) {
if unsizing_params.contains(i) {
return Err(Unimplemented);
}
}
}
}
}

// Extract `TailField<T>` and `TailField<U>` from `Struct<T>` and `Struct<U>`.
Expand Down
10 changes: 10 additions & 0 deletions src/test/ui/feature-gates/feature-gate-relaxed_struct_unsize.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Test that we allow unsizing even if there is an unchanged param in the
// field getting unsized.
struct A<T, U: ?Sized + 'static>(T, B<T, U>);
struct B<T, U: ?Sized>(T, U);

fn main() {
let x: A<[u32; 1], [u32; 1]> = A([0; 1], B([0; 1], [0; 1]));
let y: &A<[u32; 1], [u32]> = &x; //~ ERROR mismatched types
assert_eq!(y.1.1.len(), 1);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
error[E0308]: mismatched types
--> $DIR/feature-gate-relaxed_struct_unsize.rs:8:34
|
LL | let y: &A<[u32; 1], [u32]> = &x;
| ------------------- ^^ expected slice `[u32]`, found array `[u32; 1]`
| |
| expected due to this
|
= note: expected reference `&A<[u32; 1], [u32]>`
found reference `&A<[u32; 1], [u32; 1]>`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
1 change: 1 addition & 0 deletions src/test/ui/unsized/unchanged-param.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![feature(relaxed_struct_unsize)]
// run-pass
// Test that we allow unsizing even if there is an unchanged param in the
// field getting unsized.
Expand Down

0 comments on commit 031cce8

Please sign in to comment.