rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
97.98k stars 12.68k forks source link

const_generics: link fails with undefined reference, hidden symbol isn't defined #83972

Closed Dirbaio closed 2 years ago

Dirbaio commented 3 years ago

This code (playground)

#![feature(const_generics)]

pub trait Foo {
    fn foo(&self);
}

pub struct FooImpl<const N: usize>;
impl<const N: usize> Foo for FooImpl<N> {
    fn foo(&self) {}
}

pub trait Bar: 'static {
    type Foo: Foo;
    fn get() -> &'static Self::Foo;
}

struct BarImpl;
impl Bar for BarImpl {
    type Foo = FooImpl<{ 4 }>;
    fn get() -> &'static Self::Foo {
        &FooImpl
    }
}

pub fn boom<B: Bar>() {
    B::get().foo();
}

fn main() {
    boom::<BarImpl>();
}

fails to link with


error: linking with `cc` failed: exit status: 1
  |
  = note: "cc" "-m64" "-Wl,--eh-frame-hdr" "-Wl,-znoexecstack" "-Wl,--as-needed" "-L" "/playground/.rustup/toolchains/nightly-x86_*snip*own-linux-gnu/lib/libcompiler_builtins-8b33f9cbbc9652fe.rlib" "-Wl,-Bdynamic" "-lgcc_s" "-lutil" "-lrt" "-lpthread" "-lm" "-ldl" "-lc"
  = note: /usr/bin/ld: /playground/target/debug/deps/playground-dea6a74639071602.playground.27snrtcg-cgu.0.rcgu.o: in function `playground::boom':
          /playground/src/main.rs:26: undefined reference to `<playground::FooImpl<_> as playground::Foo>::foo'
          /usr/bin/ld: /playground/target/debug/deps/playground-dea6a74639071602: hidden symbol `_ZN64_$LT$playground..FooImpl$LT$_$GT$$u20$as$u20$playground..Foo$GT$3foo17hc9e5ef50b3fc24d9E' isn't defined
          /usr/bin/ld: final link failed: bad value
          collect2: error: ld returned 1 exit status

rustc --version --verbose:

rustc 1.53.0-nightly (c051c5ddd 2021-04-06)
binary: rustc
commit-hash: c051c5ddda79f45fad196ca3a4690251e377d043
commit-date: 2021-04-06
host: x86_64-unknown-linux-gnu
release: 1.53.0-nightly
LLVM version: 12.0.0
Dirbaio commented 3 years ago

Builds correctly with rustc 1.53.0-nightly (5e65467ef 2021-03-26) Fails with rustc 1.53.0-nightly (9b0edb7fd 2021-03-27)

eggyal commented 3 years ago

Fails with rustc 1.53.0-nightly (9b0edb7fd 2021-03-27)

@Dirbaio 9b0edb7fd appears to be nightly-2021-03-28, which I agree is the first regression.

searched nightlies: from nightly-2021-03-26 to nightly-2021-04-07 regressed nightly: nightly-2021-03-28 searched commits: from https://github.com/rust-lang/rust/commit/5e65467eff3d1da4712586d8402d1d2e1d6654bc to https://github.com/rust-lang/rust/commit/9b0edb7fddacd6a60a380c1ce59159de597ab270 regressed commit: https://github.com/rust-lang/rust/commit/9b0edb7fddacd6a60a380c1ce59159de597ab270

bisected with cargo-bisect-rustc v0.6.0 Host triple: x86_64-unknown-linux-gnu Reproduce with: ```bash cargo bisect-rustc --start 2021-03-26 ```
Dirbaio commented 3 years ago

The code I originally found this in does require #![feature(const_generics)] and #![feature(const_evaluatable_checked)], but while minimizing it I arrived to this.

The error also disappears when removing the braces in { 4 }

tmiasko commented 3 years ago

const_generics feature enables lazy normalization. It seems that in one place a symbol name is constructed using an unevaluated const, while the other uses the evaluated one. This crates a mismatch in legacy symbol mangling scheme. The issue also disappears in -Zsymbol-mangling-version=v0 which evaluates the const during mangling.

$ rustc -Zprint-mono-items=lazy -Zverbose ...
MONO_ITEM fn <FooImpl<Const(Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:18 ~ a[317d]::{impl#1}::Foo::{constant#0}), const_param_did: Some(DefId(0:7 ~ a[317d]::FooImpl::N)) }, substs: [], promoted: None }): usize)> as Foo>::foo @@ a.7rcbfp3g-cgu.0[Internal]
input to MirNeighborCollector::monomorphize    for<'r> fn(&'r <B as Bar>::Foo) {<<B as Bar>::Foo as Foo>::foo}
after subst_mir_and_normalize_erasing_regions  for<'r> fn(&'r FooImpl<{ 4 }>) {<FooImpl<{ 4 }> as Foo>::foo}
after an exra normalize_erasing_regions (*)    for<'r> fn(&'r FooImpl<4_usize>) {<FooImpl<4_usize> as Foo>::foo}

Verbose:

input to MirNeighborCollector::monomorphize    for<'r> fn(&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) <B as Bar>::Foo) {<<B as Bar>::Foo as Foo>::foo}
after subst_mir_and_normalize_erasing_regions  for<'r> fn(&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) FooImpl<Const(Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:18 ~ a[317d]::{impl#1}::Foo::{constant#0}), const_param_did: Some(DefId(0:7 ~ a[317d]::FooImpl::N)) }, substs: [], promoted: None }): usize)>) {<FooImpl<Const(Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:18 ~ a[317d]::{impl#1}::Foo::{constant#0}), const_param_did: Some(DefId(0:7 ~ a[317d]::FooImpl::N)) }, substs: [], promoted: None }): usize)> as Foo>::foo}
after an extra normalize_erasing_regions (*)   for<'r> fn(&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed('r) }) FooImpl<Const(Value(Scalar(0x0000000000000004)): usize)>) {<FooImpl<Const(Value(Scalar(0x0000000000000004)): usize)> as Foo>::foo}
agausmann commented 2 years ago

I'm seeing a similar error: #97186, with a very similar example!

It seems that Unevaluated generic const parameters are making their way through monomorphization and into symbol mangling, which should definitely be fixed.

Passing -Zsymbol-mangling-version=v0 also fixes the linker error in my issue.

BoxyUwU commented 2 years ago
#![feature(generic_const_exprs)]

pub trait Foo {
    fn foo(&self);
}

pub struct FooImpl<const N: usize>;
impl<const N: usize> Foo for FooImpl<N> {
    fn foo(&self) {}
}

pub trait Bar: 'static {
    type Foo: Foo;
    fn get() -> &'static Self::Foo;
}

struct BarImpl;
impl Bar for BarImpl {
    type Foo = FooImpl<{{ 4 }}>;
    fn get() -> &'static Self::Foo {
        &FooImpl
    }
}

pub fn boom<B: Bar>() {
    B::get().foo();
}

fn main() {
    boom::<BarImpl>();
}

still an issue but the repro is slightly different (added some {} around { 4 } and updated feature gate)

lcnr commented 2 years ago

It seems that Unevaluated generic const parameters are making their way though monomorphization and into symbol mangling, which should definitely be fixed.

jup, should definitely be fixed