Skip to content

Value mangling #61486

Description

@varkor

For const generics, we will eventually allow arbitrary structural_match values as generic arguments. Thus, we need to figure out how to mangle them. At the moment, only unsigned integers are supported.

min_const_generics

adt_const_params

  • Tuples and arrays
  • Complex data types

cc @eddyb @yodaldevoid

Activity

  1. eddyb commented on Jun 3, 2019

    @eddyb
    Contributor
  2. est31 commented on Jun 3, 2019

    @est31
    Member

    At the moment, only unsigned integers are supported.

    bools work too, don't they? #61383 (comment)

  3. varkor commented on Jun 3, 2019

    @varkor
    ContributorAuthor

    @est31: the current implementation of const generics supports more types than the mangle supports, which is something we need to address.

  4. est31 commented on Jun 3, 2019

    @est31
    Member

    @varkor I see. As you are special casing bools already in #61409 do you think they should be allowed in the initial version of const generics, too? Mangling schemes for them are straightforward.

  5. varkor commented on Jun 3, 2019

    @varkor
    ContributorAuthor

    It's unclear what "initial version of const generics" means at this point. We're not ready to talk about stabilisation yet. Hopefully we'll be able to discuss proper mangling soon. I know @eddyb already has some ideas.

  6. yodaldevoid commented on Jun 3, 2019

    @yodaldevoid
    Contributor

    Quoting @eddyb from Discord channel #compiler for my own benefit if nothing else:

    unsigned integers is really what people want, IMO. but I have an idea of how to encode arbitrary ADTs into the symbol mangling, so it shouldn't be too bad

    (basically something like std::fmt::Formatter::debug_{list,struct,tuple}, and the struct/tuple forms can take a path that's the path of the variant in an enum, for enum values)

    lol I didn't finish my thought: you'd encode Some(0i32) as something like TNvINt...6OptioniE4Somei0_E
    that is, ...::Option<i32>::Some(0i32)

  7. added
    C-enhancementCategory: An issue proposing an enhancement or a PR with one.
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    on Jun 9, 2019
  8. added
    requires-nightlyThis issue requires a nightly compiler in some way. When possible, use a F-* label instead.
    on Aug 6, 2019
  9. oli-obk commented on Jan 24, 2020

    @oli-obk
    Contributor

    Such printing should probably share the walking logic with the const validator (https://github.com/rust-lang/rust/blob/master/src/librustc_mir/interpret/validity.rs), because both need to do the same thing.

  10. eddyb commented on Mar 14, 2020

    @eddyb
    Contributor

    These tests fail with -Zsymbol-mangling-version=v0:

        [ui] ui/const-generics/fn-const-param-call.rs
        [ui] ui/const-generics/issues/issue-61432.rs
        [ui] ui/const-generics/issues/issue-62579-no-match.rs
        [ui] ui/const-generics/raw-ptr-const-param-deref.rs
        [ui] ui/const-generics/slice-const-param.rs
    

    Maybe we should start adding revisions that use -Zsymbol-mangling-version=v0 to all const generic tests and FIXMEs pointing to this issue for the ones that don't work?


    More specifically, what I did to test this was replace Legacy with V0 here:

    symbol_mangling_version: SymbolManglingVersion = (SymbolManglingVersion::Legacy,

  11. eddyb commented on Mar 14, 2020

    @eddyb
    Contributor

    I've just noticed a potential issue with the syntax:
    We support p after the "basic type" (currently only unsigned integers).

    As a type, p means "placeholder" and is printed as _.
    This is useful for e.g. a static inside an impl method, because it doesn't depend on the impls's parameters, so we end up with e.g. <Foo<_>>::foo::BAR.

    But for a constant integer, we encode a similar situation (e.g. <ArrayVec<_, _>>::foo::BAR) using, for the const generic arg, jp (j is the type usize) - so more like _: usize than just _.
    (For completeness, 42: usize is encoded as j2a_ - i.e. we use the value in hex)

    Now, jp vs just p (which is not supported as a constant right now) is harmless, even if a bit longer, and the ability to print _: usize in verbose mode is neat.

    But if we start including ADTs, we might need, for const generics of type (usize, usize), to encode TjpjpE, i.e. (_: usize, _: usize), printed as (_, _) by default.
    This is starting to get weird, but it's still manageable, the real problem is enums.

    How would you encode an erased Option<usize>? Normal values of that type would be rely on either Option::<usize>::Some or Option::<usize>::None, but for placeholders we can't choose.


    The good news is we can still add a general placeholder, either just p as a constant, or p followed by its type (if we want to be able to print a type).
    However, since the type of a constant must be monomorphic (or maybe in the future, determined by type parameters in scope), we don't have to encode it.

    Speaking of which, the current syntax is also redundant in that we print all the integers the same, so we don't really need to encode which one it is, just that the hex nibbles should be printed as an integer.

  12. added a commit that references this issue on Apr 20, 2020
  13. 1 remaining item

  14. self-assigned this
    on Oct 4, 2020
  15. varkor commented on Oct 22, 2020

    @varkor
    ContributorAuthor

    Signed integers and char are now supported: #77554, so marking this as unblocking.

  16. michaelwoerister commented on Apr 21, 2021

    @michaelwoerister
    Member

    @eddyb I'm trying to understand the issue you mentioned above. Can you give a concrete example that is not covered by the <const> = <type> "p" production? Right now I don't understand what the specific problem is.

  17. eddyb commented on Apr 30, 2021

    @eddyb
    Contributor

    @michaelwoerister It's been resolved already (as part of #77554):

    if let Some(bits) = val {
    // We only print the type if the const can be evaluated.
    self = ct.ty.print(self)?;
    let _ = write!(self.out, "{}{:x}_", if neg { "n" } else { "" }, bits);
    } else {
    // NOTE(eddyb) despite having the path, we need to
    // encode a placeholder, as the path could refer
    // back to e.g. an `impl` using the constant.
    self.push("p");
    }

    That p doesn't have a type before it. So we're now using the "improved" approach I was describing in that comment.

    EDIT: the grammar should be updated too.

  18. eddyb commented on Apr 30, 2021

    @eddyb
    Contributor

    @michaelwoerister Actually, to answer the more interesting question: <const> = <type> "p" is wrong and largely unworkable - <const> cannot start with <type> without severely overcomplicating the encoding of ADT constants.

    So the current implementation only supports <const> starting with <basic-type>. And ideally we'd reuse the non-basic type constructor letters for values. Say, Ai1_i2_i3_E for [1, 2, 3].

    Before I realized we'd more or less have to encode "a tree of ADT constructors" for more interesting values, I still thought we could generally do <type> {<hex-nibble>} "_" to encode arbitrary data, but that's flawed.

    There are too many factors that make it almost impossible, and also quite undesireable, to have demanglers understand how data is laid out. So only bool, char & integers (and maybe strs in the future) can use raw bytes.

  19. eddyb commented on Jul 13, 2021

    @eddyb
    Contributor

    In #87082 (comment) I wrote this, which seems like it would be useful to have in this thread:

    We only want to ever allow type-level constants (such as those passed to const params) to be one of:

    1. integer leaves (iN, uN, and also bool and char)
    • if we allow raw pointers, they would only be allowed here, with integer addresses
    • maybe str and [u8] would also go in here for efficiency, unsure yet about that
    1. ADTs of other type-level constants (struct, enum, tuples, arrays, slices, etc.)
    • no C unions, since we can't guarantee we can describe them as pure values
    • any user-defined ADTs have to have be "structurally matchable" (i.e. auto-derived PartialEq+Eq)
    • arguably this includes &T too - even if they are normally thought of as indirection, at the type-level &value acts as a newtype of value, as &T has structural equality that makes it isomorphic to T

    (cc @oli-obk - did I miss anything?)

    We already have the leaves, what's lacking in the mangling is the second part (the ADTs) - it's not that much design space, since e.g. enum variants can be treated as just structs (i.e. we encode the path to the variant and pretend it's a struct path) - the tricky parts how much aesthetic detail we put in, like whether we encode field names, how differently to encode tuple structs (make them like regular structs or like tuples?), whether we add a special case for str to avoid encoding it as an array, etc. etc.

  20. eddyb commented on Jul 16, 2021

    @eddyb
    Contributor

    First attempt at previously suggested constant value mangling approaches, is now up at #87194 (including grammar).

  21. lcnr commented on Jun 24, 2022

    @lcnr
    Contributor

    to my knowledge this is now integrated in v0 mangling? @eddyb can this be closed?

  22. added and removed on Jun 24, 2022
  23. eddyb commented on Jun 24, 2022

    @eddyb
    Contributor

    An implementation is complete, but I would block this on the RFC PR getting merged (see its discussion):

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

Metadata

Metadata

Assignees

Labels

A-const-genericsArea: const generics (parameters and arguments)C-enhancementCategory: An issue proposing an enhancement or a PR with one.F-adt_const_params`#![feature(adt_const_params)]`T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.requires-nightlyThis issue requires a nightly compiler in some way. When possible, use a F-* label instead.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions