<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/54705>54705</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            Clang reports that `__is_array(T[0])` is true
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            clang:frontend
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          ldionne
      </td>
    </tr>
</table>

<pre>
    Clang currently reports that `__is_array(T[0])` is true, which leads to `std::is_array<T[0]>` being true as well.

- GCC says it's false, MSVC says it's true (see [Godbolt](https://godbolt.org/z/8jadodMs1)).
- The Standard says that `T[0]` is downright ill-formed: http://eel.is/c++draft/dcl.array#1

Since it's ill-formed, I guess Clang is technically conforming, however it still leads to code like this surprisingly compiling with Clang:

```
static_assert(!std::is_bounded_array_v<T[0]>);
static_assert(!std::is_unbounded_array_v<T[0]>);
static_assert(std::is_array_v<T[0]>);
```

So it looks like `T[0]` is neither a bounded array nor an unbounded array, but it *is* an array, which is quite confusing. I would suggest Clang either:
1. Errors out when we try to form `T[0]` since it's ill-formed, or
2. At least not report that `T[0]` is an array from its `__is_array` builtin (patch provided for this)

Also note that Clang will not match a partial specialization like `template <class T, size_t N> struct foo<T[N]> { ... };` when instantiating it with `T[0]`, which seems to support the fact that we really don't want to treat `T[0]` as an array type.

Here's a potential patch that changes `__is_array(T[0])` to `false`, but I suspect we may want a deeper fix in the compiler.

```diff
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index f360dc6e1a23..c7178e097213 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -4870,6 +4870,9 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
   case UTT_IsFloatingPoint:
     return T->isFloatingType();
   case UTT_IsArray:
+    // We don't want to report T[0] as being an array type.
+    if (ConstantArrayType const* CAT = C.getAsConstantArrayType(T))
+      return CAT->getSize() != 0;
     return T->isArrayType();
   case UTT_IsPointer:
     return T->isAnyPointerType();
diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp
index d576e4388d6f..ce45d1857179 100644
--- a/clang/test/SemaCXX/type-traits.cpp
+++ b/clang/test/SemaCXX/type-traits.cpp
@@ -23,6 +23,7 @@ typedef Empty EmptyArMB[1][2];
 typedef int Int;
 typedef Int IntAr[10];
 typedef Int IntArNB[];
+typedef Int IntArZero[0];
 class Statics { static int priv; static NonPOD np; };
 union EmptyUnion {};
 union IncompleteUnion; // expected-note {{forward declaration of 'IncompleteUnion'}}
@@ -673,7 +674,8 @@ void is_array()
 {
   int t01[T(__is_array(IntAr))];
   int t02[T(__is_array(IntArNB))];
-  int t03[T(__is_array(UnionAr))];
+  int t03[F(__is_array(IntArZero))];
+  int t04[T(__is_array(UnionAr))];
 
   int t10[F(__is_array(void))];
   int t11[F(__is_array(cvoid))];
```
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJydV0tz4jgQ_jVwUeGyzcNw4AAkmc1hslMVsju1l5SwG9CMkLySHML8-u2WbIdXZjOTcrAtqd_f15JXujhMF5KrDcsrY0A5eWAGSm2cZW7LHeuM4udnYZ-5MfzQScfLznAed4Y3nXSCU0zgMlNBJ12w_VbkWyaBFzimSdC6otOf4dXK9xetfP-W5Fcg0DapYNyyPUgZdeKbTjwLvz32abFglh8sE66TZpatubTe3OfHv05nvBL00ALehvNPulhp6byr461zpSVf0ju8NmEq0maDbz_wf_yNF7r4bBMKK51EjfXlFtij46rgpgjGmqS0cYQkFHqvjNhsHRNS9tba7IBiZ2S4tQsgI2HxIe-kc7wKw9fo-12Ry6jObz85Dv9RqBya-I4UY_j3bFOBtSwUj8oA-VaJnEusYK4VrcTU0tKt3sMLGNTDrEMtbzXKdQFMiu-AYaEKW5nSCItiXseuFJKqsxduG-xQJEfuYez15V-t407kz9xaMOjyuJMmxwhY6UoVUAQkPL-cYQHz3p9_SE-lflvTBSB_JnwWXV0RTWmUWn-3IXGXUFCA-cJ0c1b7ybwppjSOKda6z-qSL9iqcqS1k84IHTNa1c4FVqHafyvhwFe2ogpFiIC9riTCstpswLoaCcF4W6gkYrfGaGOZRiP7LSgkGVLlQOUnjJwHYN-HnDZBZxqxmSMQoVGlXd0v3mNGEwxbG71DxfaspVATqIR0QhF5S-4w3NLoF0EpQuMemlSXoyrMpNVkGoLREPmeoE3-7LwOzkpunOCS2RJyvIsfCAat2rI52JWSow6EQC4RI2xJUVrxA54de0A0IF1MlTv0QtcweQgwYZ1szqIowvsN4QVj8KkVChGn0Kgj3mBJPXVOc_JWVGxUO09DW5V1BgH7W16nEutkwNO50ArLgSOom9Y7HL9INT9KtTuUcNJH_wADvqKYFUyb8nkJufa28i1mEM5Lc9HtQ1sPLThEQtC9xwAox97lHZr3fnJWAJTIg7V4xcT44EJPARNd7SKFWK_DED2xXm-DGeTULn3vSe-kWOHvI-x4fbt9Lc3i69coL0u2-uDCYEEgA1_Zuo9W8xEkPO1HUZ4l2RjiSZYmfZbE8WgwqPeBXu_DftQx-f6O1y-61RnEeLHeYJxRekdIiXn9PGH1ZGhq2Fy0ZLcvXFaI4SfFzWGJVV8aTtwdk3YUHj2CXFOd2jn2tCSYB3OMsZxboLHne3sntQfuFy2UazsIoz8DrjKKLXsIftEuJKW-P781zVONs7Dpz9qkkK6wF7K_4QLXdSNpQEeQDueDq8AO2sSa2sZCB-Z5g-QWNUrrqJkuZktk-A1bRBtwM3ux0qPc7_onetuYUZ6iRuFH7AwhXDSZkM74OO7zLB1beD9FPtlHDfuaInWoV13R9g5VHFD0HmQIMBpA0Z4jBNgLuvzf4mPKFMNsBIP-eFyM1kgZGAyLZDxE5kx-SpmPmbhOmw_K1tRJ-w1x_FPW0IaECliz213pDuF3Zj7PEWsJNbjhPPW9vSlSsxzzzu6JDucT92FiZkhDfFW2XfJAZo6XoHcXi_4Bo9uTSKMqbEyPnvLWbzs1_ckvPKzh-aUdetDqy583TJU0Vu9MQUulaOPzMT_5R1R0ZcG9ogYtgfoJvns1gazwSv0dip7fdL30HPfmPR2LC0AnTdhbNbExO9eTZmQMr5NCjbK6Pul8lA3wcdyU6kWLgh3tQi03veWGJpQBF2Px5sjf8cm2FeoSSH2czUYofVcIK3Uh1mvE-tfEfIjXrPlG8iZ4d9WeL_rPRAe_ZJOdBkq4vDRM6X0_OUlyTSa_LtTu3d1i2i8m_QnvOuEk1N-Uv_El2a2MnJ59ruEhqlpFiCnaQ-VLc-vhMfEbwhJfhbX4NYQPw0EWD7vb6TCO18M8GeWTQZrGfDjik3iVxfkakkm2hrwr-QqknRIv0zSvP27wiIptVmGg1Ay6YprGKD2Ik2TSz_CIkI0m-XgwjidFkSQZfqsNYmxKQkbkDn1Ods3Ue7aqNhYnpbDYotpJpLLYKIBp6AZdXrmtRokCq6mg64OY-gj-A_tFtF8">