Skip to content

[NLL] A rejects-valid (a NLL regression) #48180

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
leonardo-m opened this issue Feb 13, 2018 · 3 comments
Closed

[NLL] A rejects-valid (a NLL regression) #48180

leonardo-m opened this issue Feb 13, 2018 · 3 comments
Labels
A-NLL Area: Non-lexical lifetimes (NLL) C-bug Category: This is a bug.

Comments

@leonardo-m
Copy link

This code compiles and runs correctly if I don't use the NLL feature:

#![feature(nll)]

use std::ops::{ShrAssign, BitOr, Shl, SubAssign};
use std::mem::swap;

trait HasTrailingZeros {
    #[inline(always)]
    fn trailing_zeros(self) -> u32;
}
impl HasTrailingZeros for u32 {
    #[inline(always)]
    fn trailing_zeros(self) -> u32 { self.trailing_zeros() }
}

fn gcd<T>(mut u: T, mut v: T) -> T
where T: PartialEq +
         Copy +
         From<u8> +
         PartialOrd +
         BitOr<Output=T> +
         Shl<u32, Output=T> +
         ShrAssign<u32> +
         SubAssign +
         HasTrailingZeros {
    if u == 0.into() { return v; }
    if v == 0.into() { return u; }
    let shift = (u | v).trailing_zeros();
    u >>= u.trailing_zeros();
    loop {
        v >>= v.trailing_zeros();
        if u > v {
            swap(&mut u, &mut v);
        }
        v -= u;
        if v == 0.into() { break; }
    }
    u << shift
}

fn main() {
    println!("{}", gcd(20u32, 10u32));
}

With the NLL feature it gives (it used to compile with NLL):

error[E0503]: cannot use `u` because it was mutably borrowed
  --> ...\test.rs:28:11
   |
28 |     u >>= u.trailing_zeros();
   |     -     ^ use of borrowed `u`
   |     |
   |     borrow of `u` occurs here

error[E0503]: cannot use `v` because it was mutably borrowed
  --> ...\test.rs:30:15
   |
30 |         v >>= v.trailing_zeros();
   |         -     ^ use of borrowed `v`
   |         |
   |         borrow of `v` occurs here

error: aborting due to 2 previous errors
...>rustc -vV
rustc 1.25.0-nightly (16362c737 2018-02-12)
binary: rustc
commit-hash: 16362c737fe740f630ada06349fa9004e2a51bb7
commit-date: 2018-02-12
host: x86_64-pc-windows-gnu
release: 1.25.0-nightly
LLVM version: 6.0
@pietroalbini pietroalbini added A-NLL Area: Non-lexical lifetimes (NLL) C-bug Category: This is a bug. WG-compiler-nll labels Feb 13, 2018
@pietroalbini
Copy link
Member

cc @nikomatsakis

@Aaron1011
Copy link
Member

I believe this is a duplicate of #48129

@sapphire-arches
Copy link
Contributor

Reduced example:

#![feature(nll)]

use std::ops::{ShrAssign, AddAssign};

trait HasTrailingZeros {
    #[inline(always)]
    fn trailing_zeros(self) -> u32;
}
impl HasTrailingZeros for u32 {
    #[inline(always)]
    fn trailing_zeros(self) -> u32 { self.trailing_zeros() }
}

fn gcd<T>(mut u: T, mut v: T) -> T
where T: Copy +
    ShrAssign<u32> +
    HasTrailingZeros {
    v >>= v.trailing_zeros();
    v
}

// Not necessary for repro, but useful for comparison to #48129
fn add_self<T>(mut v: T) -> T
where T: AddAssign + Copy + AddAssign {
    v += v;
    v
}

fn main() {
    println!("{}", gcd(20u32, 10u32));
}

The MIR generated by gcd and add_self are similar enough that I'm pretty sure this is a duplicate of #48129.

`gcd` MIR
// MIR for `gcd`
// source = MirSource { def_id: DefId(0/0:14 ~ bug[317d]::gcd[0]), promoted: None }
// pass_name = nll
// disambiguator = 0

| Free Region Mapping
| '_#0r    | Global   | ['_#0r, '_#1r]
| '_#1r    | Local    | ['_#1r]
|
| Inferred Region Values
| '_#0r    | {'_#0r, bb0[0..=5], bb1[0], bb2[0..=1], bb3[0..=7]}
| '_#1r    | {'_#1r, bb0[0..=5], bb1[0], bb2[0..=1], bb3[0..=7]}
| '_#2r    | {bb0[1..=5], bb2[0..=1]}
| '_#3r    | {bb0[2..=5], bb2[0..=1]}
| '_#4r    | {bb2[1]}
|
| Inference Constraints
| '_#0r live at {'_#0r, bb0[0..=5], bb1[0], bb2[0..=1], bb3[0..=7]}
| '_#1r live at {'_#1r, bb0[0..=5], bb1[0], bb2[0..=1], bb3[0..=7]}
| '_#2r live at {bb0[1]}
| '_#3r live at {bb0[2..=5], bb2[0..=1]}
| '_#4r live at {bb2[1]}
| '_#2r: '_#3r @ bb0[2] due to bug.rs:22:5: 22:6
| '_#3r: '_#4r @ bb2[1] due to bug.rs:22:5: 22:29
fn gcd(_1: T, _2: T) -> T{
    let mut _0: T;                       // return place
    let mut _3: ();
    let mut _4: &mut T;
    let mut _5: u32;
    let mut _6: T;
    let mut _7: T;

    | Live variables on entry to bb0: [_2]
    bb0: {                              
                                         | Live variables on entry to bb0[0]: [_2]
        StorageLive(_4);                 // bb0[0]: scope 0 at bug.rs:22:5: 22:6
                                         | Live variables on entry to bb0[1]: [_2]
        _4 = &mut _2;                    // bb0[1]: scope 0 at bug.rs:22:5: 22:6
                                         | Live variables on entry to bb0[2]: [_2, _4]
        StorageLive(_5);                 // bb0[2]: scope 0 at bug.rs:22:11: 22:29
                                         | Live variables on entry to bb0[3]: [_2, _4]
        StorageLive(_6);                 // bb0[3]: scope 0 at bug.rs:22:11: 22:12
                                         | Live variables on entry to bb0[4]: [_2, _4]
        _6 = _2;                         // bb0[4]: scope 0 at bug.rs:22:11: 22:12
                                         | Live variables on entry to bb0[5]: [_2, _4, _6]
        _5 = const HasTrailingZeros::trailing_zeros(move _6) -> [return: bb2, unwind: bb1]; // bb0[5]: scope 0 at bug.rs:22:11: 22:29
                                         // ty::Const
                                         // + ty: fn(T) -> u32 {<T as HasTrailingZeros>::trailing_zeros}
                                         // + val: Function(DefId(0/0:11 ~ bug[317d]::HasTrailingZeros[0]::trailing_zeros[0]), Slice([T]))
                                         // mir::Constant
                                         // + span: bug.rs:22:11: 22:29
                                         // + ty: fn(T) -> u32 {<T as HasTrailingZeros>::trailing_zeros}
                                         // + literal: const HasTrailingZeros::trailing_zeros
    }

    | Live variables on entry to bb1: []
    bb1: {                               // cleanup
                                         | Live variables on entry to bb1[0]: []
        resume;                          // bb1[0]: scope 0 at bug.rs:15:1: 25:2
    }

    | Live variables on entry to bb2: [_2, _4, _5]
    bb2: {                              
                                         | Live variables on entry to bb2[0]: [_2, _4, _5]
        StorageDead(_6);                 // bb2[0]: scope 0 at bug.rs:22:28: 22:29
                                         | Live variables on entry to bb2[1]: [_2, _4, _5]
        _3 = const std::ops::ShrAssign::shr_assign(move _4, move _5) -> [return: bb3, unwind: bb1]; // bb2[1]: scope 0 at bug.rs:22:5: 22:29
                                         // ty::Const
                                         // + ty: for<'r> fn(&'r mut T, u32) {<T as std::ops::ShrAssign<u32>>::shr_assign}
                                         // + val: Function(DefId(2/0:967 ~ core[d915]::ops[0]::bit[0]::ShrAssign[0]::shr_assign[0]), Slice([T, u32]))
                                         // mir::Constant
                                         // + span: bug.rs:22:5: 22:29
                                         // + ty: for<'r> fn(&'r mut T, u32) {<T as std::ops::ShrAssign<u32>>::shr_assign}
                                         // + literal: const std::ops::ShrAssign::shr_assign
    }

    | Live variables on entry to bb3: [_2]
    bb3: {                              
                                         | Live variables on entry to bb3[0]: [_2]
        nop;                             // bb3[0]: scope 0 at bug.rs:22:5: 22:29
                                         | Live variables on entry to bb3[1]: [_2]
        StorageDead(_5);                 // bb3[1]: scope 0 at bug.rs:22:28: 22:29
                                         | Live variables on entry to bb3[2]: [_2]
        StorageDead(_4);                 // bb3[2]: scope 0 at bug.rs:22:28: 22:29
                                         | Live variables on entry to bb3[3]: [_2]
        StorageLive(_7);                 // bb3[3]: scope 0 at bug.rs:24:5: 24:6
                                         | Live variables on entry to bb3[4]: [_2]
        _7 = _2;                         // bb3[4]: scope 0 at bug.rs:24:5: 24:6
                                         | Live variables on entry to bb3[5]: [_7]
        _0 = move _7;                    // bb3[5]: scope 0 at bug.rs:24:5: 24:6
                                         | Live variables on entry to bb3[6]: []
        StorageDead(_7);                 // bb3[6]: scope 0 at bug.rs:24:5: 24:6
                                         | Live variables on entry to bb3[7]: []
        return;                          // bb3[7]: scope 0 at bug.rs:25:2: 25:2
    }
}

`add_self` example
// MIR for `add_self`
// source = MirSource { def_id: DefId(0/0:11 ~ bug[317d]::add_self[0]), promoted: None }
// pass_name = nll
// disambiguator = 0

| Free Region Mapping
| '_#0r    | Global   | ['_#0r, '_#1r]
| '_#1r    | Local    | ['_#1r]
|
| Inferred Region Values
| '_#0r    | {'_#0r, bb0[0..=4], bb1[0], bb2[0..=7]}
| '_#1r    | {'_#1r, bb0[0..=4], bb1[0], bb2[0..=7]}
| '_#2r    | {bb0[1..=4]}
| '_#3r    | {bb0[2..=4]}
| '_#4r    | {bb0[4]}
|
| Inference Constraints
| '_#0r live at {'_#0r, bb0[0..=4], bb1[0], bb2[0..=7]}
| '_#1r live at {'_#1r, bb0[0..=4], bb1[0], bb2[0..=7]}
| '_#2r live at {bb0[1]}
| '_#3r live at {bb0[2..=4]}
| '_#4r live at {bb0[4]}
| '_#2r: '_#3r @ bb0[2] due to bug.rs:24:5: 24:6
| '_#3r: '_#4r @ bb0[4] due to bug.rs:24:5: 24:11
fn add_self(_1: T) -> T{
    let mut _0: T;                       // return place
    let mut _2: ();
    let mut _3: &mut T;
    let mut _4: T;
    let mut _5: T;

    | Live variables on entry to bb0: [_1]
    bb0: {                              
                                         | Live variables on entry to bb0[0]: [_1]
        StorageLive(_3);                 // bb0[0]: scope 0 at bug.rs:24:5: 24:6
                                         | Live variables on entry to bb0[1]: [_1]
        _3 = &mut _1;                    // bb0[1]: scope 0 at bug.rs:24:5: 24:6
                                         | Live variables on entry to bb0[2]: [_1, _3]
        StorageLive(_4);                 // bb0[2]: scope 0 at bug.rs:24:10: 24:11
                                         | Live variables on entry to bb0[3]: [_1, _3]
        _4 = _1;                         // bb0[3]: scope 0 at bug.rs:24:10: 24:11
                                         | Live variables on entry to bb0[4]: [_1, _3, _4]
        _2 = const std::ops::AddAssign::add_assign(move _3, move _4) -> [return: bb2, unwind: bb1]; // bb0[4]: scope 0 at bug.rs:24:5: 24:11
                                         // ty::Const
                                         // + ty: for<'r> fn(&'r mut T, T) {<T as std::ops::AddAssign>::add_assign}
                                         // + val: Function(DefId(2/0:912 ~ core[d915]::ops[0]::arith[0]::AddAssign[0]::add_assign[0]), Slice([T, T]))
                                         // mir::Constant
                                         // + span: bug.rs:24:5: 24:11
                                         // + ty: for<'r> fn(&'r mut T, T) {<T as std::ops::AddAssign>::add_assign}
                                         // + literal: const std::ops::AddAssign::add_assign
    }

    | Live variables on entry to bb1: []
    bb1: {                               // cleanup
                                         | Live variables on entry to bb1[0]: []
        resume;                          // bb1[0]: scope 0 at bug.rs:22:1: 26:2
    }

    | Live variables on entry to bb2: [_1]
    bb2: {                              
                                         | Live variables on entry to bb2[0]: [_1]
        nop;                             // bb2[0]: scope 0 at bug.rs:24:5: 24:11
                                         | Live variables on entry to bb2[1]: [_1]
        StorageDead(_4);                 // bb2[1]: scope 0 at bug.rs:24:10: 24:11
                                         | Live variables on entry to bb2[2]: [_1]
        StorageDead(_3);                 // bb2[2]: scope 0 at bug.rs:24:10: 24:11
                                         | Live variables on entry to bb2[3]: [_1]
        StorageLive(_5);                 // bb2[3]: scope 0 at bug.rs:25:5: 25:6
                                         | Live variables on entry to bb2[4]: [_1]
        _5 = _1;                         // bb2[4]: scope 0 at bug.rs:25:5: 25:6
                                         | Live variables on entry to bb2[5]: [_5]
        _0 = move _5;                    // bb2[5]: scope 0 at bug.rs:25:5: 25:6
                                         | Live variables on entry to bb2[6]: []
        StorageDead(_5);                 // bb2[6]: scope 0 at bug.rs:25:5: 25:6
                                         | Live variables on entry to bb2[7]: []
        return;                          // bb2[7]: scope 0 at bug.rs:26:2: 26:2
    }
}

so I'm going to close this. @leonardo-m feel free to reopen if you disagree 😄.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-NLL Area: Non-lexical lifetimes (NLL) C-bug Category: This is a bug.
Projects
None yet
Development

No branches or pull requests

4 participants