Skip to content
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

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

Closed
agausmann opened this issue May 19, 2022 · 7 comments
Labels
C-bug Category: This is a bug.

Comments

@agausmann
Copy link
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
@agausmann agausmann added the C-bug Category: This is a bug. label May 19, 2022
@agausmann
Copy link
Contributor Author

agausmann commented May 19, 2022

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
Copy link
Contributor Author

agausmann commented May 20, 2022

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
Copy link
Contributor Author

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

@agausmann
Copy link
Contributor Author

agausmann commented May 20, 2022

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.

@agausmann agausmann changed the title Linker error with generic_const_exprs Linker error from unevaluated const generics in symbols when generic_const_exprs is enabled May 20, 2022
@agausmann agausmann 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 May 20, 2022
@agausmann
Copy link
Contributor Author

agausmann commented May 20, 2022

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
Copy link
Contributor Author

Related to (probably a dupe of) #83972

@agausmann
Copy link
Contributor Author

Seems to be resolved by #100315

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug.
Projects
None yet
Development

No branches or pull requests

1 participant