Change:
For program below, mangled symbol doesn't match specification nor can it be demangled with rustfilt or c++filt (with rust v0 support): <details<summaryPartial derivation</summary</details<!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
cc
The mangling was changed in cc
So, I'm not familiar at all with this (in fact, I didn't even realize we had a spec for symbol mangling until I saw this). But let's see. I'm just looking at It seems like where we expect the we instead next have which is a . didn't change that (essentially the mangling of at all). Did you actually bisect to or is that a guess?
Oh, I see what's happening, I think
I guess we're lowering to whereas it was before. This is a bit interesting, because the (slightly desugared) really is only one level of binder. But we could imagine something like (which is completely valid). This gets lowered into I have to think about this. The mangling is very much of the non-lowered version. There is an easy fix here: just don't print the binders of . This assumes that we always print the projections immediately after the relevant trait ref (but that assumption is already made). I am actually curious if the bound works out correctly. I'm assuming that when that gets lowered we just drop the . But I'm guessing that in mangling we now have an extra . So maybe we need to skip printing binders there too. I may or may not be able to get to this myself in the next couple days, but should be easy enough to fix for anyone interested; I can mentor as needed.
Which is the part of the code that prints the binder? I am potentially interested in implementing this :) claim
It's the call. So, it's not really clean, but you would have to only call that if the inner is a .
There's a single type with multiple bounds, so I would prefer keeping a single binder IMO (tho I can see us having to change the mangling if becomes a thing). You can basically work around having a different implementation, by having the bound-lifetime anonymizing process work for you. Any 's substs would effectively be required to match the ones of , at least after anonymization, which I believe should be trivially true if replicating the binder happens as a desugaring. cc
So does that mean I need a different approach from I haven't interacted with the trait-solving-related code that much, so I would appreciate if you could give me more detail on how I would implement what you're suggesting :) Alternatively, I could open a PR using 's approach since it seems like it should be very quick to implement, and then you can comment on what part you would like to be different.
I think what is saying roughly lines up with my comment. I think just open a PR with my approach. I imagine this is a "single binder" in the mangling, not in the predicate list. I don't quite follow this. Maybe this referring to multiple bound traits? Lifetimes bound in should always be the same as those bound under , since it's just a desugaring.
Right, sorry for the ambiguity. Sure, but how confident are you some kind of strange interaction can't create something that seems to be out of sync? Anyway, if we check instead of assuming it, it should be fine. This doesn't work, it will keep s outside the binder, and e.g. turn this: into I think you should move the where it was before (i.e. around the loop), but only pass the element of the list, and use for the other ones. I was worried this would mess with the anonymization but that doesn't seem to happen here (instead, mangling just assumes anonymization happened and will ICE if it didn't).
was inside the loop, around a . I think I'll open a PR with jackh726's approach, and then we can talk about some concrete code.

Discussion:
mut self, predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>, ) -> Result<Self::DynExistential, Self::Error> { <del> for predicate in predicates { self = self.in_binder(&predicate, |mut cx, predicate| { match predicate { </del> <ins> // Okay, so this is a bit tricky. Imagine we have a trait object like // `dyn for<'a> Foo<'a, Bar = &'a ()>`. When we mangle this, the // output looks really close to the syntax, where the `Bar = &'a ()` bit // is under the same binders (`['a]`) as the `Foo<'a>` bit. However, we // actually desugar these into two separate `ExistentialPredicate`s. We // can't enter/exit the "binder scope" twice though, because then we // would mangle the binders twice. (Also, side note, we merging these // two is kind of difficult, because of potential HRTBs in the Projection // predicate.) // // Also worth mentioning: imagine that we instead had // `dyn for<'a> Foo<'a, Bar = &'a ()> + Send`. In this case, `Send` is // under the same binders as `Foo`. Currently, this doesn't matter, // because only *auto traits* are allowed other than the principal trait // and all auto traits don't have any generics. Two things could // make this not an "okay" mangling: // 1) Instead of mangling only *used* // bound vars, we want to mangle *all* bound vars (`for<'b> Send` is a // valid trait predicate); // 2) We allow multiple "principal" traits in the future, or at least // allow in any form another trait predicate that can take generics. // // Here we assume that predicates have the following structure: // [<Trait> [{<Projection>}]] [{<Auto>}] // Since any predicates after the first one shouldn't change the binders, // just put them all in the binders of the first. self = self.in_binder(&predicates[0], |mut cx, _| { for predicate in predicates.iter() { // It would be nice to be able to validate bound vars here, but // projections can actually include bound vars from super traits // because of HRTBs (only in the `Self` type). Also, auto traits // could have different bound vars *anyways*. match predicate.as_ref().skip_binder() { </ins> ty::ExistentialPredicate::Trait(trait_ref) => { // Use a type that can't appear in defaults of type parameters. let dummy_self = cx.tcx.mk_ty_infer(ty::FreshTy(0));

cx = cx.print_def_path(*def_id, &[])?; } } <del> Ok(cx) })?; } </del> <ins> } Ok(cx) })?; </ins> self.push("E"); Ok(self) }

let auto_trait_predicates = auto_traits.into_iter().map(|trait_ref| { ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_ref.trait_ref().def_id())) }); <ins> // N.b. principal, projections, auto traits // FIXME: This is actually wrong with multiple principals in regards to symbol mangling </ins> let mut v = regular_trait_predicates <del> .chain(auto_trait_predicates) </del> .chain( existential_projections.map(|x| x.map_bound(ty::ExistentialPredicate::Projection)), ) <ins> .chain(auto_trait_predicates) </ins> .collect::<SmallVec<[_; 8]>>(); v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder())); v.dedup();

<ins> // Ensure that trait objects don't include more than one binder. See #83611 // build-fail // revisions: v0 //[v0]compile-flags: -Z symbol-mangling-version=v0 //[v0]normalize-stderr-test: "Cs.*?_" -> "CRATE_HASH" //[v0]normalize-stderr-test: "core[.*?]" -> "core[HASH]" #![feature(rustc_attrs)] trait Bar { fn method(&self) {} } impl Bar for &dyn FnMut(&u8) { #[rustc_symbol_name] //[v0]~^ ERROR symbol-name //[v0]~| ERROR demangling //[v0]~| ERROR demangling-alt fn method(&self) {} } trait Foo { fn method(&self) {} } impl Foo for &(dyn FnMut(&u8) + for<'b> Send) { #[rustc_symbol_name] //[v0]~^ ERROR symbol-name //[v0]~| ERROR demangling //[v0]~| ERROR demangling-alt fn method(&self) {} } trait Baz { fn method(&self) {} } impl Baz for &(dyn for<'b> Send + FnMut(&u8)) { #[rustc_symbol_name] //[v0]~^ ERROR symbol-name //[v0]~| ERROR demangling //[v0]~| ERROR demangling-alt fn method(&self) {} } fn main() { } </ins>

<ins> error: symbol-name(_RNvXCRATE_HASH13trait_objectsRDG_INtNtNtCRATE_HASH4core3ops8function5FnMutTRL0_hEEp6OutputuEL_NtB2_3Bar6method) --> $DIR/trait-objects.rs:16:5 | LL |     #[rustc_symbol_name] |     ^^^^^^^^^^^^^^^^^^^^ error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> as trait_objects[17891616a171812d]::Bar>::method) --> $DIR/trait-objects.rs:16:5 | LL |     #[rustc_symbol_name] |     ^^^^^^^^^^^^^^^^^^^^ error: demangling-alt(<&dyn for<'a> core::ops::function::FnMut<(&'a u8,), Output = ()> as trait_objects::Bar>::method) --> $DIR/trait-objects.rs:16:5 | LL |     #[rustc_symbol_name] |     ^^^^^^^^^^^^^^^^^^^^ error: symbol-name(_RNvXs_CRATE_HASH13trait_objectsRDG_INtNtNtCRATE_HASH4core3ops8function5FnMutTRL0_hEEp6OutputuNtNtBI_6marker4SendEL_NtB4_3Foo6method) --> $DIR/trait-objects.rs:28:5 | LL |     #[rustc_symbol_name] |     ^^^^^^^^^^^^^^^^^^^^ error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> + core[HASH]::marker::Send as trait_objects[17891616a171812d]::Foo>::method) --> $DIR/trait-objects.rs:28:5 | LL |     #[rustc_symbol_name] |     ^^^^^^^^^^^^^^^^^^^^ error: demangling-alt(<&dyn for<'a> core::ops::function::FnMut<(&'a u8,), Output = ()> + core::marker::Send as trait_objects::Foo>::method) --> $DIR/trait-objects.rs:28:5 | LL |     #[rustc_symbol_name] |     ^^^^^^^^^^^^^^^^^^^^ error: symbol-name(_RNvXs0_CRATE_HASH13trait_objectsRDG_INtNtNtCRATE_HASH4core3ops8function5FnMutTRL0_hEEp6OutputuNtNtBJ_6marker4SendEL_NtB5_3Baz6method) --> $DIR/trait-objects.rs:40:5 | LL |     #[rustc_symbol_name] |     ^^^^^^^^^^^^^^^^^^^^ error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> + core[HASH]::marker::Send as trait_objects[17891616a171812d]::Baz>::method) --> $DIR/trait-objects.rs:40:5 | LL |     #[rustc_symbol_name] |     ^^^^^^^^^^^^^^^^^^^^ error: demangling-alt(<&dyn for<'a> core::ops::function::FnMut<(&'a u8,), Output = ()> + core::marker::Send as trait_objects::Baz>::method) --> $DIR/trait-objects.rs:40:5 | LL |     #[rustc_symbol_name] |     ^^^^^^^^^^^^^^^^^^^^ error: aborting due to 9 previous errors </ins>