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

clang rejects valid friend template function declaration with noexcept specifier in template class #101330

Open
Rush10233 opened this issue Jul 31, 2024 · 1 comment · May be fixed by #111561
Open
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" rejects-valid

Comments

@Rush10233
Copy link

The following code is rejected by clang for the mismatch of the noexcept specifier between the friend declaration and definition of func:

template <typename T>
struct C {
    template <int N>
    friend void func() noexcept(N == 0);
};

template <int N>
void func() noexcept(N == 0) {}

int main() {
    C<int> t;
    return 0;
}

The diagnostic says that:

<source>:4:17: error: exception specification in declaration does not match the previous declaration
    4 |     friend void func() noexcept(N == 0);
      |                 ^
<source>:11:12: note: in instantiation of template class 'C<int>' requested here
   11 |     C<int> t;
      |            ^
<source>:8:6: note: previous declaration is here
    8 | void func() noexcept(N == 0) {}

That is quite unreasonable. It should be clear that the noexcept expression of func keeps identical between the friend declaration and definition statement. Removing the dependent name N in the noexcept expression or replacing template class C with a non-template one can eliminate the diagnostic.

https://godbolt.org/z/rPh84Phzn

@github-actions github-actions bot added the clang Clang issues not falling into any other category label Jul 31, 2024
@EugeneZelenko EugeneZelenko added clang:frontend Language frontend issues, e.g. anything involving "Sema" rejects-valid and removed clang Clang issues not falling into any other category labels Jul 31, 2024
@llvmbot
Copy link
Collaborator

llvmbot commented Jul 31, 2024

@llvm/issue-subscribers-clang-frontend

Author: None (Rush10233)

The following code is rejected by clang for the mismatch of the `noexcept` specifier between the friend declaration and definition of `func`:
template &lt;typename T&gt;
struct C {
    template &lt;int N&gt;
    friend void func() noexcept(N == 0);
};

template &lt;int N&gt;
void func() noexcept(N == 0) {}

int main() {
    C&lt;int&gt; t;
    return 0;
}

The diagnostic says that:

&lt;source&gt;:4:17: error: exception specification in declaration does not match the previous declaration
    4 |     friend void func() noexcept(N == 0);
      |                 ^
&lt;source&gt;:11:12: note: in instantiation of template class 'C&lt;int&gt;' requested here
   11 |     C&lt;int&gt; t;
      |            ^
&lt;source&gt;:8:6: note: previous declaration is here
    8 | void func() noexcept(N == 0) {}

That is quite unreasonable. It should be clear that the noexcept expression of func keeps identical between the friend declaration and definition statement. Removing the dependent name N in the noexcept expression or replacing template class C with a non-template one can eliminate the diagnostic.

https://godbolt.org/z/rPh84Phzn

sdkrystian added a commit that referenced this issue Sep 20, 2024
…sts (#106585)

Currently, clang rejects the following explicit specialization of `f`
due to the constraints not being equivalent:
```
template<typename T>
struct A
{
    template<bool B>
    void f() requires B;
};

template<>
template<bool B>
void A<int>::f() requires B { }
```
This happens because, in most cases, we do not set the flag indicating
whether a `RedeclarableTemplate` is an explicit specialization of a
member of an implicitly instantiated class template specialization until
_after_ we compare constraints for equivalence. This patch addresses the
issue (and a number of other issues) by:
- storing the flag indicating whether a declaration is a member
specialization on a per declaration basis, and
- significantly refactoring `Sema::getTemplateInstantiationArgs` so we
collect the right set of template argument in all cases.

Many of our declaration matching & constraint evaluation woes can be
traced back to bugs in `Sema::getTemplateInstantiationArgs`. This
change/refactor should fix a lot of them. It also paves the way for
fixing #101330 and #105462 per my suggestion in #102267 (which I have
implemented on top of this patch but will merge in a subsequent PR).
xgupta pushed a commit to xgupta/llvm-project that referenced this issue Oct 4, 2024
…sts (llvm#106585)

Currently, clang rejects the following explicit specialization of `f`
due to the constraints not being equivalent:
```
template<typename T>
struct A
{
    template<bool B>
    void f() requires B;
};

template<>
template<bool B>
void A<int>::f() requires B { }
```
This happens because, in most cases, we do not set the flag indicating
whether a `RedeclarableTemplate` is an explicit specialization of a
member of an implicitly instantiated class template specialization until
_after_ we compare constraints for equivalence. This patch addresses the
issue (and a number of other issues) by:
- storing the flag indicating whether a declaration is a member
specialization on a per declaration basis, and
- significantly refactoring `Sema::getTemplateInstantiationArgs` so we
collect the right set of template argument in all cases.

Many of our declaration matching & constraint evaluation woes can be
traced back to bugs in `Sema::getTemplateInstantiationArgs`. This
change/refactor should fix a lot of them. It also paves the way for
fixing llvm#101330 and llvm#105462 per my suggestion in llvm#102267 (which I have
implemented on top of this patch but will merge in a subsequent PR).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" rejects-valid
Projects
None yet
3 participants