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] CTAD deduces alias template that does not satisfy the condition of the alias template #85192

Closed
ImpleLee opened this issue Mar 14, 2024 · 7 comments · Fixed by #89358
Closed
Assignees
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema"

Comments

@ImpleLee
Copy link

The following code snippet fails static_assert, and the type of i2 is inferred to be (as reported in the diagnostic message) std::array<std::array<int, 3>, 1>, which does not even constitute a legal my_ints.

Godbolt link: https://godbolt.org/z/1Mo9hz4W7 .

#include <array>
#include <type_traits>

template <int N>
using my_ints = std::array<int, N>;

int main() {
    my_ints i = {1, 2, 3};
    my_ints i2 = {i};
    static_assert(std::is_same_v<decltype(i2), decltype(i)>);
    // error: static assertion failed due to requirement 'std::is_same_v<std::array<std::array<int, 3>, 1>, std::array<int, 3>>'
}
@github-actions github-actions bot added the clang Clang issues not falling into any other category label Mar 14, 2024
@ImpleLee
Copy link
Author

Probably related to #84492 , not sure whether this is a duplicate.

@EugeneZelenko EugeneZelenko added clang:frontend Language frontend issues, e.g. anything involving "Sema" and removed clang Clang issues not falling into any other category labels Mar 14, 2024
@llvmbot
Copy link
Collaborator

llvmbot commented Mar 14, 2024

@llvm/issue-subscribers-clang-frontend

Author: Imple Lee (ImpleLee)

The following code snippet fails `static_assert`, and the type of `i2` is inferred to be (as reported in the diagnostic message) `std::array<std::array<int, 3>, 1>`, which does not even constitute a legal `my_ints`.

Godbolt link: https://godbolt.org/z/1Mo9hz4W7 .

#include &lt;array&gt;
#include &lt;type_traits&gt;

template &lt;int N&gt;
using my_ints = std::array&lt;int, N&gt;;

int main() {
    my_ints i = {1, 2, 3};
    my_ints i2 = {i};
    static_assert(std::is_same_v&lt;decltype(i2), decltype(i)&gt;);
    // error: static assertion failed due to requirement 'std::is_same_v&lt;std::array&lt;std::array&lt;int, 3&gt;, 1&gt;, std::array&lt;int, 3&gt;&gt;'
}

@shafik
Copy link
Collaborator

shafik commented Mar 14, 2024

CC @hokein @ilya-biryukov

@ImpleLee
Copy link
Author

A more simple demo:

#include <array>
#include <type_traits>

template <std::size_t N>
using ints = std::array<int, N>;

ints m = {1., 2.};
static_assert(std::is_same_v<decltype(m), ints<2>>);
// error: static assertion failed due to requirement 'std::is_same_v<std::array<double, 2>, std::array<int, 2>>'

@ImpleLee
Copy link
Author

template <typename T>
struct A {
    T data;
};

using A_int = A<int>;
// A_int a = {1.0}; // error: type 'double' cannot be narrowed to 'int' in initializer list [-Wc++11-narrowing]

template <typename=void>
using A2_int = A<int>;
A2_int a2 = {1.0}; // passing

@hokein hokein self-assigned this Mar 18, 2024
@hokein hokein modified the milestones: Clang C++20, LLVM 19.X Release Mar 18, 2024
@hokein
Copy link
Collaborator

hokein commented Mar 19, 2024

I think it is a symptom of missing the is_deducible constraint for the synthesized deduction guides, #84492.

A simplified case

#include <array>
#include <type_traits>

template <int N>
using my_ints = std::array<int, N>;

int main() {
    std::array<int, 3> i;
    my_ints i2 = {i};
    static_assert(std::is_same_v<decltype(i2), decltype(i)>);
    // error: static assertion failed due to requirement 'std::is_same_v<std::array<std::array<int, 3>, 1>, std::array<int, 3>>'
}

When deducing template arguments for i2 in the function overload resolution, we have two interesting candidates in the overload set:

  1. deduction guide template<unsigned int N> array(std::array<int, N>)-> std::array<int, N> (from the array default copy constructor)
  2. deduction guide template<class _Tp, class ... _Up> std::array(_Tp, _Up ...)-> array<_Tp, (1 + sizeof... (_Up))> (from the explicit written deduction guide in <array>)

The function argument is i, whose type is std::array<int, std::size_t>. The candidate 1) is not viable because the std::size_t vs unsigned int for the non-type template parameters. And we end up with the candidate 2), which leads to the surprising deduced type array<array<int, 3>>.
(Changing the template parameter from int N to std::size_t N in the alias templates would make it work as excepted)

Ideally, And 2) should not be viable as well (gcc has the correct behavior), because we can not deduce the template argument of the alias my_ints from the deduced type array<array<int, 3>>, but this is_deducible part is missing in the current implementation.

@ImpleLee
Copy link
Author

I think it is a symptom of missing the is_deducible constraint for the synthesized deduction guides, #84492.

A simplified case

#include <array>
#include <type_traits>

template <int N>
using my_ints = std::array<int, N>;

int main() {
    std::array<int, 3> i;
    my_ints i2 = {i};
    static_assert(std::is_same_v<decltype(i2), decltype(i)>);
    // error: static assertion failed due to requirement 'std::is_same_v<std::array<std::array<int, 3>, 1>, std::array<int, 3>>'
}

When deducing template arguments for i2 in the function overload resolution, we have two interesting candidates in the overload set:

  1. deduction guide template<unsigned int N> array(std::array<int, N>)-> std::array<int, N> (from the array default copy constructor)
  2. deduction guide template<class _Tp, class ... _Up> std::array(_Tp, _Up ...)-> array<_Tp, (1 + sizeof... (_Up))> (from the explicit written deduction guide in <array>)

The function argument is i, whose type is std::array<int, std::size_t>. The candidate 1) is not viable because the std::size_t vs unsigned int for the non-type template parameters. And we end up with the candidate 2), which leads to the surprising deduced type array<array<int, 3>>. (Changing the template parameter from int N to std::size_t N in the alias templates would make it work as excepted)

Ideally, And 2) should not be viable as well (gcc has the correct behavior), because we can not deduce the template argument of the alias my_ints from the deduced type array<array<int, 3>>, but this is_deducible part is missing in the current implementation.

I can accept this explanation, and that does solve my question. I am okay if you choose to close this issue as duplicate, or just leave it open until you have implemented the is_deducible constraint.

hokein added a commit to hokein/llvm-project that referenced this issue Apr 19, 2024
hokein added a commit to hokein/llvm-project that referenced this issue Apr 22, 2024
hokein added a commit to hokein/llvm-project that referenced this issue Apr 24, 2024
hokein added a commit to hokein/llvm-project that referenced this issue May 7, 2024
hokein added a commit to hokein/llvm-project that referenced this issue May 13, 2024
…templates.

Fixes llvm#85192
Fixes llvm#84492

- rebase to main
- add release note for __is_deducible
- implement diagnostics for bad argument types for __is_deducible

Don't expose __is_deducible trait.

Refine the implementation of hiding __is_deducible type trait.

Apply approach 3.
hokein added a commit to hokein/llvm-project that referenced this issue May 15, 2024
…templates.

Fixes llvm#85192
Fixes llvm#84492

- rebase to main
- add release note for __is_deducible
- implement diagnostics for bad argument types for __is_deducible

Don't expose __is_deducible trait.

Refine the implementation of hiding __is_deducible type trait.

Apply approach 3.
hokein added a commit that referenced this issue May 16, 2024
…templates (#89358)

Fixes #85192
Fixes #84492

This patch implements the "IsDeducible" constraint where the template
arguments of the alias template can be deduced from the returned type of
the synthesized deduction guide, per C++ [over.match.class.deduct]p4. In
the implementation, we perform the deduction directly, which is more
efficient than the way specified in the standard.

Also update relevant CTAD tests which were incorrectly compiled due to
the missing constraint.
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"
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants