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

[temp.over.link] Referring to member functions distinguished by non-functionally-equivalent constraints #256

Open
ecatmur opened this issue Mar 8, 2023 · 2 comments

Comments

@ecatmur
Copy link

ecatmur commented Mar 8, 2023

[temp.over.link]/5 Example 4 demonstrates that the following is well-formed:

template<int I> concept C = true;
template<typename T> struct A {
  void f() requires C<42>;      // #1
  void f() requires true;       // OK, different functions
};

This is OK since the two constraints are unevaluated operands and so functional equivalence is considered operationally.

However, changing return types allows us to refer to the two member functions separately:

template<int I> concept C = true;
template<typename T> struct A {
    int f() requires C<42> { return 1; }  // #1
    unsigned f() requires true { return 2u; }  // #2
};
int main() {
    int (A<int>::*p)() = &A<int>::f;
    unsigned (A<int>::*q)() = &A<int>::f;
    return (A<int>().*p)() + (A<int>().*q)();
}

There is implementation divergence; clang errors ("definition with same mangled name '_ZN1AIiE1fEv' as another definition"), gcc errors ("Two symbols with same comdat_group are not linked by the same_comdat_group list") and then ices ("symtab_node::verify failed") while MSVC accepts (helped by the ABI mangling return types).

If the return types are changed to auto (auto f() requires C<42> { return 1; } etc.), clang accepts erroneously, calling #.2 both times, gcc continues to error and ice, and MSVC rejects C2440 ("initializing': cannot convert from 'overloaded-function' to 'int (__cdecl A::* )(void)'", etc.)

I'm not sure what the right fix is. It seems like it'd be best for #.1 and #.2 to be determined to be incompatible overloads at the time of class template instantiation, but maybe that'd come with other issues.

@jensmaurer
Copy link
Member

I think the quoted section of the standard, including the example, is clear that we're talking about different functions here, and thus the mangling needs to cope with that. In particular, it seems the quoted rule requires mangling the constraint in its unevaluated expression form. I'm not seeing a defect in the standard, but plenty of bugs in implementations. May I suggest that you send bug reports to the respective implementations?

@ecatmur
Copy link
Author

ecatmur commented Mar 8, 2023

In particular, it seems the quoted rule requires mangling the constraint in its unevaluated expression form.

Yes, I thought so too. Mangling the constraint feels like a non starter, since it would break ABI and imply that future (tightening, relaxing, or extensionally equivalent) changes to constraints would also be ABI breaking. We don't require mangling constraints anywhere else.

Related: CWG 2488, CWG 2421, CWG 2501.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants