Rollup merge of #67015 - osa1:issue66971, r=wesleywiser

Fix constant propagation for scalar pairs

We now only propagate a scalar pair if the Rvalue is a tuple with two scalars. This for example avoids propagating a (u8, u8) value when Rvalue has type `((), u8, u8)` (see the regression test). While this is a correct thing to do, implementation is tricky and will be done later.

Fixes #66971
Fixes #66339
Fixes #67019
This commit is contained in:
Mazdak Farrokhzad 2019-12-11 10:10:42 +01:00 committed by GitHub
commit 04e0512c7a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 130 additions and 11 deletions

View File

@ -636,19 +636,45 @@ fn replace_with_const(
ScalarMaybeUndef::Scalar(one),
ScalarMaybeUndef::Scalar(two)
) => {
// Found a value represented as a pair. For now only do cont-prop if type of
// Rvalue is also a pair with two scalars. The more general case is more
// complicated to implement so we'll do it later.
let ty = &value.layout.ty.kind;
// Only do it for tuples
if let ty::Tuple(substs) = ty {
*rval = Rvalue::Aggregate(
Box::new(AggregateKind::Tuple),
vec![
self.operand_from_scalar(
one, substs[0].expect_ty(), source_info.span
),
self.operand_from_scalar(
two, substs[1].expect_ty(), source_info.span
),
],
);
// Only do it if tuple is also a pair with two scalars
if substs.len() == 2 {
let opt_ty1_ty2 = self.use_ecx(source_info, |this| {
let ty1 = substs[0].expect_ty();
let ty2 = substs[1].expect_ty();
let ty_is_scalar = |ty| {
this.ecx
.layout_of(ty)
.ok()
.map(|ty| ty.details.abi.is_scalar())
== Some(true)
};
if ty_is_scalar(ty1) && ty_is_scalar(ty2) {
Ok(Some((ty1, ty2)))
} else {
Ok(None)
}
});
if let Some(Some((ty1, ty2))) = opt_ty1_ty2 {
*rval = Rvalue::Aggregate(
Box::new(AggregateKind::Tuple),
vec![
self.operand_from_scalar(
one, ty1, source_info.span
),
self.operand_from_scalar(
two, ty2, source_info.span
),
],
);
}
}
}
},
_ => { }

View File

@ -802,6 +802,14 @@ pub fn is_uninhabited(&self) -> bool {
_ => false,
}
}
/// Returns `true` is this is a scalar type
pub fn is_scalar(&self) -> bool {
match *self {
Abi::Scalar(_) => true,
_ => false,
}
}
}
rustc_index::newtype_index! {

View File

@ -0,0 +1,38 @@
// compile-flags: -Z mir-opt-level=2
// Due to a bug in propagating scalar pairs the assertion below used to fail. In the expected
// outputs below, after ConstProp this is how _2 would look like with the bug:
//
// _2 = (const Scalar(0x00) : (), const 0u8);
//
// Which has the wrong type.
fn encode(this: ((), u8, u8)) {
assert!(this.2 == 0);
}
fn main() {
encode(((), 0, 0));
}
// END RUST SOURCE
// START rustc.main.ConstProp.before.mir
// bb0: {
// ...
// _3 = ();
// _2 = (move _3, const 0u8, const 0u8);
// ...
// _1 = const encode(move _2) -> bb1;
// ...
// }
// END rustc.main.ConstProp.before.mir
// START rustc.main.ConstProp.after.mir
// bb0: {
// ...
// _3 = const Scalar(<ZST>) : ();
// _2 = (move _3, const 0u8, const 0u8);
// ...
// _1 = const encode(move _2) -> bb1;
// ...
// }
// END rustc.main.ConstProp.after.mir

View File

@ -0,0 +1,34 @@
// compile-flags: -Z mir-opt-level=2
// This used to ICE in const-prop
fn test(this: ((u8, u8),)) {
assert!((this.0).0 == 1);
}
fn main() {
test(((1, 2),));
}
// Important bit is parameter passing so we only check that below
// END RUST SOURCE
// START rustc.main.ConstProp.before.mir
// bb0: {
// ...
// _3 = (const 1u8, const 2u8);
// _2 = (move _3,);
// ...
// _1 = const test(move _2) -> bb1;
// ...
// }
// END rustc.main.ConstProp.before.mir
// START rustc.main.ConstProp.after.mir
// bb0: {
// ...
// _3 = (const 1u8, const 2u8);
// _2 = (move _3,);
// ...
// _1 = const test(move _2) -> bb1;
// ...
// }
// END rustc.main.ConstProp.after.mir

View File

@ -0,0 +1,13 @@
// compile-flags: -Z mir-opt-level=2
// build-pass
// This used to ICE in const-prop
fn foo() {
let bar = |_| { };
let _ = bar("a");
}
fn main() {
foo();
}