Quuxplusone / LLVMBugzillaTest

0 stars 0 forks source link

Unsized temporary array problem inside template function #43508

Open Quuxplusone opened 4 years ago

Quuxplusone commented 4 years ago
Bugzilla Link PR44538
Status NEW
Importance P normal
Reported by Maciej Cencora (m.cencora@gmail.com)
Reported on 2020-01-14 02:56:01 -0800
Last modified on 2021-10-26 05:09:56 -0700
Version unspecified
Hardware All All
CC blitzrakete@gmail.com, dgregor@apple.com, erik.pilkington@gmail.com, llvm-bugs@lists.llvm.org, richard-llvm@metafoo.co.uk
Fixed by commit(s)
Attachments
Blocks
Blocked by
See also
Temporary unsized arrays declared inside function template, are treated as
unsized in some contexts, and as sized in others.
I.e. decltype always returns int (&&)[3], but range based for-loop sometimes
treats it as unsized (and incomplete).

Reproducer:

#include <type_traits>

using Array = int[];

template <typename ...Ts>
void bar1(Ts ...values)
{
    auto && array1 = Array{ 1, 2, 3 };
    auto && array2 = Array{ values...};

    static_assert(std::is_same<int (&&)[3], decltype(array1)>{}, "");      // ok
    static_assert(std::is_same<decltype(array1), decltype(array2)>{}, ""); // ok

    for (auto c : array1) {} // ok
    for (auto c : array2) {} // does not compile, says array2 has incomplete type int[]
}

template <typename T1, typename T2, typename T3>
void bar2(T1 v1, T2 v2, T3 v3)
{
    auto && array1 = Array{ 1, 2, 3 };
    auto && array2 = Array{ v1, v2, v3 };
    auto && array3 = Array{ (int)v1, (int) v2, (int)v3 };

    static_assert(std::is_same<int (&&)[3], decltype(array1)>{}, "");      // ok
    static_assert(std::is_same<decltype(array1), decltype(array2)>{}, ""); // ok
    static_assert(std::is_same<decltype(array1), decltype(array3)>{}, ""); // ok

    for (auto c : array1) {} // ok
    for (auto c : array2) {} // does not compile, says array2 has incomplete type int[]
    for (auto c : array3) {} // ok
}

void bar3(int a, int b, int c)
{
    auto && array1 = Array{ 1, 2, 3 };
    auto && array2 = Array{ a, b, c };

    static_assert(std::is_same<int (&&)[3], decltype(array1)>{}, "");      // ok
    static_assert(std::is_same<decltype(array1), decltype(array2)>{}, ""); // ok

    for (auto c : array1) {} // ok
    for (auto c : array2) {} // ok
}

int main()
{
    bar1<int, int, int>(1, 2, 3);
    bar2<int, int, int>(1, 2, 3);
    bar3(1, 2, 3);
}
Quuxplusone commented 3 years ago

Still fails on clang 11.0.1 and trunk

Quuxplusone commented 3 years ago
I think the problem here is that we treat

    Array{ <blah> }

as being a non-type-dependent expression, with type `Array`. As a consequence,
we reject the range-based for loop when parsing the template, even though the
instantiation is valid.
Quuxplusone commented 3 years ago
We're not following the standard rules here, but the standard rules are also
wrong. I've contacted the C++ committee about that. I'd suggest for now that we
say

    T( <blah> )
    T{ <blah> }

are type-dependent if either T is a dependent type or if T is an array of
unknown bound and <blah> is type-dependent.
Quuxplusone commented 3 years ago
Still fails on trunk.

Is there a CWG issue created for this?
Where can I find up-to-date CWG issues list? This one http://www.open-
std.org/jtc1/sc22/wg21/docs/cwg_active.html seems old (February 2021)