Skip to content

Linker error from symbols containing unevaluated const generics when generic_const_exprs is enabled #97186

@agausmann

Description

@agausmann
Contributor

Minimal example:

#![feature(generic_const_exprs)]

fn main() {
    let mut system = System {
        foo_provider: { SomeFooProvider { some_foo: SomeFoo } },
    };
    system.poll();
}

struct System<FP, const A: usize> {
    foo_provider: FP,
}

impl<FP, const A: usize> System<FP, A>
where
    FP: FooProvider<A>,
{
    fn poll(&mut self) {
        self.foo_provider.get_foo().foo();
    }
}

trait FooProvider<const A: usize> {
    type Foo: Foo<A>;

    fn get_foo(&mut self) -> &mut Self::Foo;
}

trait Foo<const A: usize> {
    fn foo(&mut self);
}

const SOME_A: usize = 4;

struct SomeFooProvider {
    some_foo: SomeFoo<SOME_A>,
}

impl FooProvider<SOME_A> for SomeFooProvider {
    type Foo = SomeFoo<SOME_A>;

    fn get_foo(&mut self) -> &mut Self::Foo {
        &mut self.some_foo
    }
}

struct SomeFoo<const A: usize>;

impl<const A: usize> Foo<A> for SomeFoo<A> {
    fn foo(&mut self) {}
}

(I know this snippet technically doesn't need generic_const_exprs, but it is needed in the code that this example was derived from. If I remove generic_const_exprs, this compiles and links without error.)

When trying to compile this on nightly (cd282d7 2022-05-18), I get a linker error:

error: linking with `cc` failed: exit status: 1
  |
  = note: "cc" "-m64" "/tmp/rustcuiY5st/symbols.o" "/home/goose/dev/repro/target/debug/deps/kbforge-b2301669cf56257f.1a6r6rnhxoxl4aig.rcgu.o" "/home/goose/dev/repro/target/debug/deps/kbforge-b2301669cf56257f.1mo9bmmn3yns06xc.rcgu.o" "/home/goose/dev/repro/target/debug/deps/kbforge-b2301669cf56257f.1tzpn02gnyhtnyd0.rcgu.o" "/home/goose/dev/repro/target/debug/deps/kbforge-b2301669cf56257f.3ang6wmbioxxlivr.rcgu.o" "/home/goose/dev/repro/target/debug/deps/kbforge-b2301669cf56257f.58taiyi7v1inhtj0.rcgu.o" "/home/goose/dev/repro/target/debug/deps/kbforge-b2301669cf56257f.5o1onfyjfdooa3s.rcgu.o" "/home/goose/dev/repro/target/debug/deps/kbforge-b2301669cf56257f.k1atrq8i0a2zdp1.rcgu.o" "/home/goose/dev/repro/target/debug/deps/kbforge-b2301669cf56257f.o47vn73rhzjhmj7.rcgu.o" "/home/goose/dev/repro/target/debug/deps/kbforge-b2301669cf56257f.991r8hrtqfpskke.rcgu.o" "-Wl,--as-needed" "-L" "/home/goose/dev/repro/target/debug/deps" "-L" "/home/goose/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-Wl,--start-group" "-Wl,-Bstatic" "/home/goose/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-977ece543e1e3d2f.rlib" "/home/goose/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libpanic_unwind-1141b5caaf7b2195.rlib" "/home/goose/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libobject-93491bde8b3642ba.rlib" "/home/goose/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libmemchr-d338f5690e3fda2f.rlib" "/home/goose/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libaddr2line-2cd7f06709609788.rlib" "/home/goose/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libgimli-05bd833c6cc845b5.rlib" "/home/goose/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_demangle-5543e955d2b2e107.rlib" "/home/goose/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd_detect-9961a029e2fb69de.rlib" "/home/goose/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libhashbrown-626bd4749ba5679b.rlib" "/home/goose/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libminiz_oxide-1c5c08d77aa4ee1f.rlib" "/home/goose/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libadler-43c97e136c6f66b3.rlib" "/home/goose/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_alloc-3ad551729ddf5bdf.rlib" "/home/goose/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libunwind-cb0068802dd8f031.rlib" "/home/goose/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcfg_if-aa03de290f9594ce.rlib" "/home/goose/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liblibc-e534461cfee9dab8.rlib" "/home/goose/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liballoc-89782a6344bc3ddf.rlib" "/home/goose/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_core-2a6a2797f7a73818.rlib" "/home/goose/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcore-0e3656b1fda5fd7b.rlib" "-Wl,--end-group" "/home/goose/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcompiler_builtins-16d69221f10b0282.rlib" "-Wl,-Bdynamic" "-lgcc_s" "-lutil" "-lrt" "-lpthread" "-lm" "-ldl" "-lc" "-Wl,--eh-frame-hdr" "-Wl,-znoexecstack" "-L" "/home/goose/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-o" "/home/goose/dev/repro/target/debug/deps/kbforge-b2301669cf56257f" "-Wl,--gc-sections" "-pie" "-Wl,-zrelro,-znow" "-nodefaultlibs"
  = note: /bin/ld: /home/goose/dev/repro/target/debug/deps/kbforge-b2301669cf56257f.3ang6wmbioxxlivr.rcgu.o: in function `kbforge::System<FP,_>::poll':
          /home/goose/dev/repro/src/main.rs:19: undefined reference to `<kbforge::SomeFoo<_> as kbforge::Foo<_>>::foo'
          /bin/ld: /home/goose/dev/repro/target/debug/deps/kbforge-b2301669cf56257f: hidden symbol `_ZN67_$LT$kbforge..SomeFoo$LT$_$GT$$u20$as$u20$kbforge..Foo$LT$_$GT$$GT$3foo17h9ad525154ed3e997E' isn't defined
          /bin/ld: final link failed: bad value
          collect2: error: ld returned 1 exit status

Meta

This may be related to #96699

I had originally tested this with other linkers (mold and avr-gcc) and seen similar error messages, so it doesn't seem to be linker-specific.

rustc --version --verbose:

rustc 1.63.0-nightly (cd282d7f7 2022-05-18)
binary: rustc
commit-hash: cd282d7f75da9080fda0f1740a729516e7fbec68
commit-date: 2022-05-18
host: x86_64-unknown-linux-gnu
release: 1.63.0-nightly
LLVM version: 14.0.4

Activity

agausmann

agausmann commented on May 19, 2022

@agausmann
ContributorAuthor

I'd like to help tackle this but I'm not very familiar with compiler internals.
Maybe some kind of differential analysis/tracing would be helpful, since a one-line feature toggle causes this to break?

Here's some logs that that might be interesting to diff. Produced with cargo clean; RUSTC_LOG=trace cargo b, one with the feature flag and another with it commented out:

error_with_gce.log
ok_without_gce.log

agausmann

agausmann commented on May 20, 2022

@agausmann
ContributorAuthor

Output of rustc --emit llvm-ir repro.rs: repro.ll

Notably, there is a <SomeFoo<_> as Foo<_>>::foo emitted & defined, but with a different suffix than the one called in System<FP,_>::poll, and the one called is declared as a hidden symbol as the original error message suggested:

; inside repro::System<FP,_>::poll:
; ...
  call void @"_ZN63_$LT$repro..SomeFoo$LT$_$GT$$u20$as$u20$repro..Foo$LT$_$GT$$GT$3foo17he0a8b10f80c417d4E"
; ...

; <repro::SomeFoo<_> as repro::Foo<_>>::foo
; Function Attrs: nonlazybind uwtable
define internal void @"_ZN63_$LT$repro..SomeFoo$LT$_$GT$$u20$as$u20$repro..Foo$LT$_$GT$$GT$3foo17h0993b7b03477db6dE"(%"SomeFoo<4_usize>"* align 1 %self) unnamed_addr #1 {
start:
  ret void
}

; <repro::SomeFoo<_> as repro::Foo<_>>::foo
; Function Attrs: nonlazybind uwtable
declare hidden void @"_ZN63_$LT$repro..SomeFoo$LT$_$GT$$u20$as$u20$repro..Foo$LT$_$GT$$GT$3foo17he0a8b10f80c417d4E"(%"SomeFoo<4_usize>"* align 1) unnamed_addr #1
agausmann

agausmann commented on May 20, 2022

@agausmann
ContributorAuthor

@rustbot label +F-generic-const-exprs +T-compiler

agausmann

agausmann commented on May 20, 2022

@agausmann
ContributorAuthor

Added some debugging to rustc_symbol_mangling to look at how the hash is produced, and I noticed that SomeFoo::foo is getting hashed twice:

DEBUG rustc_symbol_mangling symbol_name(def_id=DefId(0:30 ~ repro[1a7c]::{impl#2}::foo), substs=[Const { ty: usize, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:36 ~ repro[1a7c]::{impl#1}::Foo::{constant#0}), const_param_did: Some(DefId(0:27 ~ repro[1a7c]::SomeFoo::A)) }, substs: [], promoted: None }) }])
DEBUG rustc_symbol_mangling::legacy get_symbol_hash(def_id=DefId(0:30 ~ repro[1a7c]::{impl#2}::foo), parameters=[Const { ty: usize, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:36 ~ repro[1a7c]::{impl#1}::Foo::{constant#0}), const_param_did: Some(DefId(0:27 ~ repro[1a7c]::SomeFoo::A)) }, substs: [], promoted: None }) }])
DEBUG rustc_symbol_mangling::legacy hashing substs [Const { ty: usize, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:36 ~ repro[1a7c]::{impl#1}::Foo::{constant#0}), const_param_did: Some(DefId(0:27 ~ repro[1a7c]::SomeFoo::A)) }, substs: [], promoted: None }) }]
DEBUG rustc_symbol_mangling::legacy hash: 46dc62e32e9b3ee8
...
DEBUG rustc_symbol_mangling symbol_name(def_id=DefId(0:30 ~ repro[1a7c]::{impl#2}::foo), substs=[Const { ty: usize, val: Value(Scalar(0x0000000000000004)) }])
DEBUG rustc_symbol_mangling::legacy get_symbol_hash(def_id=DefId(0:30 ~ repro[1a7c]::{impl#2}::foo), parameters=[Const { ty: usize, val: Value(Scalar(0x0000000000000004)) }])
DEBUG rustc_symbol_mangling::legacy hashing substs [Const { ty: usize, val: Value(Scalar(0x0000000000000004)) }]
DEBUG rustc_symbol_mangling::legacy hash: a3e1ed653bfd1112

The first time, it is hashing an Unevaluated const parameter, and the second time it hashes the evaluated const parameter. I believe this is the error! I'm pretty sure that hashing an Unevaluated is a logic error, at least in this case.

Relating this to the IR output from the same invocation - the hash with Unevaluated corresponds to the symbol of the function definition, and the hash with 4_usize corresponds to the symbol used at the call site.

changed the title [-]Linker error with generic_const_exprs[/-] [+]Linker error from unevaluated const generics in symbols when generic_const_exprs is enabled[/+] on May 20, 2022
changed the title [-]Linker error from unevaluated const generics in symbols when generic_const_exprs is enabled[/-] [+]Linker error from symbols containing unevaluated const generics when generic_const_exprs is enabled[/+] on May 20, 2022
agausmann

agausmann commented on May 20, 2022

@agausmann
ContributorAuthor

This seems to be more related to lazy normalization than generic_const_exprs specifically. Overriding TyCtxt::lazy_normalization() to return false makes the example compile & link without errors and run as expected.

agausmann

agausmann commented on May 21, 2022

@agausmann
ContributorAuthor

Related to (probably a dupe of) #83972

agausmann

agausmann commented on Aug 12, 2022

@agausmann
ContributorAuthor

Seems to be resolved by #100315

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: This is a bug.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @agausmann

        Issue actions

          Linker error from symbols containing unevaluated const generics when generic_const_exprs is enabled · Issue #97186 · rust-lang/rust