Skip to content

mangling for constrained templates #24

Open

Description

@zygoloid

p0734r0 added new forms of overloadable declaration that we need to mangle. For instance, we now need to distinguish:

template<typename T> concept A = ...
template<typename T> concept B = ...
template<A T> void f(T); // f1
template<B T> void f(T); // f2
template<typename T> requires A<T> void g(T); // g1
template<typename T> requires B<T> void g(T); // g2

It is permissible (but not necessary) for the mangling of f1 and g1 to be the same (other than the name).

(There are also requires-clauses on non-template functions, but I don't believe there is any need to mangle those since at most one such function can have its requires-clause evaluate to true, and the rest are never emitted.)

As a general model, I suggest we include "extra information" about a template-parameter (for a function template -- we don't need this for non-overloadable templates) as a prefix on the template-arg mangling. (We should also consider extending this to the case where the the template parameter is a template template parameter and the template argument does not have an identical template-parameter-list, to handle the case described in http://sourcerytools.com/pipermail/cxx-abi-dev/2014-December/002791.html)

I suggest we affix the constraint expression from the requires-clause (if any) to the template-args, and do not perform any expansion or canonicalization of the as-written form of the template declaration. Strawman mangling suggestion:

<template-arg> ::= C <concept name> <template-arg>
<template-args> ::= I <template-arg>+ Q <requires-clause expr> E

Example:

template<A T, B U> requires C<T, U> void f();
f<int, 3>(); // _Z1fIC1AiC1BLi3EQ1CIT_T0_EEvv

Activity

  1. rjmccall commented on Jul 26, 2017

    @rjmccall
    Collaborator

    Is your statement about non-template functions true in the case that not all such functions are declared in the same translation unit? Or is that impossible because such functions must be defined within templates?

  2. rjmccall commented on Jul 26, 2017

    @rjmccall
    Collaborator

    Does the standard consider these to be different declarations for the purposes of the ODR?

      template <A T> void foo();
      template <class T> requires A<T> void foo();
    

    Oh, I see you answered that: it's unspecified.

    I feel like it would be responsible for us to do some minimal canonicalization here.

  3. thiagomacieira commented on Jul 26, 2017

    @thiagomacieira

    Similarly, does it consider these two to be two different functions, even if both concepts are exactly the same (same requirements, literally)?

      template<typename T> concept A = ...
      template<typename T> concept B = ...
      template<A T> void f(T); // f1
      template<B T> void f(T); // f2
    

    If that is the case, trying to call f with any argument that matches the concepts is an ambiguous overload, correct?

    But if I split the two in two different translation units, could I call two different functions and not violate ODR?

    And what happens if two different TUs have differing concepts that have the same name? ODR violation?

  4. daveedvdv commented on Jul 26, 2017

    @daveedvdv
  5. daveedvdv commented on Jul 26, 2017

    @daveedvdv
  6. thiagomacieira commented on Jul 26, 2017

    @thiagomacieira

    Please note that your reply removed everything between the angle brackets, so you removed important information. But to be clear, I'm asking:
    a.cpp:

    template<typename T> concept A = { something here; };
    template<A T> void f(T) {}

    b.cpp:

    template<typename T> concept B = { something here; };
    template<B T> void f(T) {}

    Specifically, aside from the change of A to B, the rest is exactly the same, literally so for the concept declaration. In other words: what defines a concept: the name or the requirements?

    And as a corollary, in c.cpp:

    template<typename T> concept A = { something very different here; };
    template<A T> void f(T) {}

    If concepts are identified by name, then the above is must be ODR violation (no diagnostic required). Is this understanding correct?

  7. daveedvdv commented on Jul 26, 2017

    @daveedvdv
  8. thiagomacieira commented on Jul 26, 2017

    @thiagomacieira

    I believe concepts have linkage, and therefore, yes, that would be an ODR violation (even without the declaration of f).

    If they have linkage, we need to mangle that too.

    Why do they have to have linkage?

  9. rjmccall commented on Jul 26, 2017

    @rjmccall
    Collaborator

    It looks like concepts with the same name are required to be defined the same way in different translation units. I don't know if there's a way of giving a concept "linkage" per se.

  10. thiagomacieira commented on Jul 26, 2017

    @thiagomacieira

    Something like IFNDR then.

  11. rjmccall commented on Jul 26, 2017

    @rjmccall
    Collaborator

    It looks like Daveed's statement is correct: two template-heads (template parameter list + requires clause) are equivalent only if they are written in exactly the same way, but they are functionally equivalent if they accept the same set of template arguments. So we are allowed but not required to treat those as distinct templates. (Exactly like Richard said.)

  12. rjmccall commented on Jul 26, 2017

    @rjmccall
    Collaborator

    I feel like people would probably be surprised by trivial differences breaking ABI, but on the other that's already true of function templates, and it mostly doesn't matter because:

    • depending on function pointer equality is extremely rare (and foolish) and
    • depending on the address/uniqueness of a static variable within a function template is rare, albeit less so (and most justifiable) than depending on function pointer equality.

    So Richard's idea of not doing any canonicalization is appealing. But if anything about concepts requires us to mangle template-heads for something besides identifying a function template, we'll be in more trouble.

  13. tahonermann commented on Jul 26, 2017

    @tahonermann
    Contributor

    (There are also requires-clauses on non-template functions, but I don't believe there is any need to mangle those since at most one such function can have its requires-clause evaluate to true, and the rest are never emitted.)

    For tool vendors such as Synopsys/Coverity, having different mangled names for each distinct declaration is useful, even if only one of them can ever be "activated" within a TU. However, this is a niche requirement and we can resort to vendor extensions (as we have in other cases such as "conflicting" inline friend function definitions in different class templates) if including mangling would be at all problematic for other implementors.

  14. zygoloid commented on Jul 26, 2017

    @zygoloid
    ContributorAuthor

    Is your statement about non-template functions true in the case that not all such functions are declared in the same translation unit?

    The wording in this area is unclear, and we have an open issue on it. Example:

    // translation unit 1
    struct A {};
    struct B;
    template<typename T> concept bool Complete = requires { sizeof(T); };
    inline void f() requires Complete<A> {};
    inline void f() requires Complete<B> {};
    
    // translation unit 2
    struct A;
    struct B {};
    template<typename T> concept bool Complete = requires { sizeof(T); };
    inline void f() requires Complete<A> {};
    inline void f() requires Complete<B> {};
    

    It's not clear whether this program is valid, or (if valid) what it means. And the same situation can arise even within a TU:

    struct A;
    struct B;
    template<typename T> concept bool Complete = requires { sizeof(T); };
    inline void f() requires !Complete<A> || Complete<B> {}; // #1
    inline void f() requires Complete<A> && !Complete<B> {}; // #2
    void g() { f(); } // calls #1
    struct A {};
    void h() { f(); } // calls #2
    struct B {};
    void i() { f(); } // calls #1
    

    Or is that impossible because such functions must be defined within templates?

    There is no such requirement... yet.

    If nothing else, I'd say the underspecification in this area and the likelihood of changes suggests that we shouldn't commit to a mangling for this construct yet.

  15. rjmccall commented on Jul 27, 2017

    @rjmccall
    Collaborator

    Interesting, alright.

  16. 18 remaining items

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

    pending committee feedbackThe issue is blocked waiting for a response from the committee.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions