Skip to content

Commit ddbfe6f

Browse files
v01dXYZv01dxyzcor3ntin
authored
[Sema] Fix __array_rank instantiation (#124491)
The type being queried was left as a template type parameter, making the whole expression as dependent and thus not eligible to static_assert. Fixes #123498 Co-authored-by: v01dxyz <[email protected]> Co-authored-by: cor3ntin <[email protected]>
1 parent ac87d6b commit ddbfe6f

File tree

4 files changed

+133
-5
lines changed

4 files changed

+133
-5
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,6 +1002,8 @@ Bug Fixes to C++ Support
10021002
- Fixed assertions or false compiler diagnostics in the case of C++ modules for
10031003
lambda functions or inline friend functions defined inside templates (#GH122493).
10041004
- Clang now rejects declaring an alias template with the same name as its template parameter. (#GH123423)
1005+
- Fix type of expression when calling a template which returns an ``__array_rank`` querying a type depending on a
1006+
template parameter. Now, such expression can be used with ``static_assert`` and ``constexpr``. (#GH123498)
10051007
- Correctly determine the implicit constexprness of lambdas in dependent contexts. (#GH97958) (#GH114234)
10061008

10071009
Bug Fixes to AST Handling

clang/include/clang/AST/ExprCXX.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2847,8 +2847,8 @@ class TypeTraitExpr final
28472847
///
28482848
/// Example:
28492849
/// \code
2850-
/// __array_rank(int[10][20]) == 2
2851-
/// __array_extent(int, 1) == 20
2850+
/// __array_rank(int[10][20]) == 2
2851+
/// __array_extent(int[10][20], 1) == 20
28522852
/// \endcode
28532853
class ArrayTypeTraitExpr : public Expr {
28542854
/// The trait. An ArrayTypeTrait enum in MSVC compat unsigned.

clang/lib/Sema/TreeTransform.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14947,9 +14947,6 @@ TreeTransform<Derived>::TransformArrayTypeTraitExpr(ArrayTypeTraitExpr *E) {
1494714947
SubExpr = getDerived().TransformExpr(E->getDimensionExpression());
1494814948
if (SubExpr.isInvalid())
1494914949
return ExprError();
14950-
14951-
if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getDimensionExpression())
14952-
return E;
1495314950
}
1495414951

1495514952
return getDerived().RebuildArrayTypeTrait(E->getTrait(), E->getBeginLoc(), T,
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
// RUN: %clang_cc1 -fsyntax-only %s
2+
// RUN: %clang_cc1 -fsyntax-only -std=c++20 -DWITH_AUTO_FUNCTION_PARAMETER=1 %s
3+
4+
// When __array_rank is used with a template type parameter, this test
5+
// ensures clang considers the final expression could be used with
6+
// static_assert/constexpr.
7+
//
8+
// Although array_extent was handled well, we add it as a precaution.
9+
10+
template <typename T>
11+
using remove_reference_t = __remove_reference_t(T);
12+
13+
template <typename T, int N>
14+
constexpr int array_rank(T (&lhs)[N]) {
15+
return __array_rank(T[N]);
16+
}
17+
18+
template <int I, typename T, int N>
19+
constexpr int array_extent(T (&lhs)[N]) {
20+
return __array_extent(T[N], I);
21+
}
22+
23+
template <typename T>
24+
struct Rank {
25+
using ArrayT = remove_reference_t<T>;
26+
27+
template <int N>
28+
static constexpr int call(ArrayT (&lhs)[N]) {
29+
return __array_rank(ArrayT[N]);
30+
}
31+
};
32+
33+
template <typename T>
34+
struct Extent {
35+
using ArrayT = remove_reference_t<T>;
36+
37+
template <int I, int N>
38+
static constexpr int call(ArrayT (&lhs)[N]) {
39+
return __array_extent(ArrayT[N], I);
40+
}
41+
};
42+
43+
#ifdef WITH_AUTO_FUNCTION_PARAMETER
44+
template <int N>
45+
constexpr int array_rank_auto(auto (&lhs)[N]) {
46+
return __array_rank(remove_reference_t<decltype(lhs[0])>[N]);
47+
}
48+
49+
template <int I, int N>
50+
constexpr int array_extent_auto(auto (&lhs)[N]) {
51+
return __array_extent(remove_reference_t<decltype(lhs[0])>[N], I);
52+
}
53+
#endif
54+
55+
template <int N>
56+
constexpr int array_rank_int(const int (&lhs)[N]) {
57+
return __array_rank(const int[N]);
58+
}
59+
60+
template <int I, int N>
61+
constexpr int array_extent_int(const int (&lhs)[N]) {
62+
return __array_extent(const int[N], I);
63+
}
64+
65+
template <int M, int N>
66+
constexpr int array_rank_int(const int (&lhs)[M][N]) {
67+
return __array_rank(const int[M][N]);
68+
}
69+
70+
template <int I, int M, int N>
71+
constexpr int array_extent_int(const int (&lhs)[M][N]) {
72+
return __array_extent(const int[M][N], I);
73+
}
74+
75+
int main() {
76+
constexpr int vec[] = {0, 1, 2, 1};
77+
constexpr int mat[4][4] = {
78+
{1, 0, 0, 0},
79+
{0, 1, 0, 0},
80+
{0, 0, 1, 0},
81+
{0, 0, 0, 1}
82+
};
83+
84+
#define ATT_TESTS_WITH_ASSERT(ATT_ASSERT) \
85+
{ ATT_ASSERT(RANK(vec) == 1); } \
86+
{ ATT_ASSERT(RANK(mat) == 2); } \
87+
{ ATT_ASSERT(EXTENT(vec, 0) == 4); } \
88+
{ ATT_ASSERT(EXTENT(vec, 1) == 0); } \
89+
{ ATT_ASSERT(EXTENT(mat, 1) == 4); }
90+
91+
#define ATT_TESTS() \
92+
ATT_TESTS_WITH_ASSERT( constexpr bool cst = ) \
93+
ATT_TESTS_WITH_ASSERT( (void) ) \
94+
ATT_TESTS_WITH_ASSERT( static_assert )
95+
96+
{
97+
#define RANK(lhs) array_rank(lhs)
98+
#define EXTENT(lhs, i) array_extent<i>(lhs)
99+
ATT_TESTS();
100+
#undef RANK
101+
#undef EXTENT
102+
}
103+
104+
{
105+
#define RANK(lhs) Rank<decltype(lhs[0])>::call(lhs)
106+
#define EXTENT(lhs, i) Extent<decltype(lhs[0])>::call<i>(lhs)
107+
ATT_TESTS();
108+
#undef RANK
109+
#undef EXTENT
110+
}
111+
112+
#ifdef WITH_AUTO_FUNCTION_PARAMETER
113+
{
114+
#define RANK(lhs) array_rank_auto(lhs)
115+
#define EXTENT(lhs, i) array_extent_auto<i>(lhs)
116+
ATT_TESTS();
117+
#undef RANK
118+
#undef EXTENT
119+
}
120+
#endif
121+
122+
{
123+
#define RANK(lhs) array_rank_int(lhs)
124+
#define EXTENT(lhs, i) array_extent_int<i>(lhs)
125+
ATT_TESTS();
126+
#undef RANK
127+
#undef EXTENT
128+
}
129+
}

0 commit comments

Comments
 (0)