<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/58872>58872</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
Incorrect `if constexpr` evaluation in nested generic lambda with explicit template parameters
</td>
</tr>
<tr>
<th>Labels</th>
<td>
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
cschreib
</td>
</tr>
</table>
<pre>
The test code below does not compile (in C++20 mode) with any version of clang I could test in Compiler Explorer (up to and including clang 15):
```c++
#include <type_traits>
// Generic type holder, for types that cannot be instanciated.
template<typename T>
struct type_holder {};
// Generic type to create a function with a given signature.
template<typename T>
struct foo;
template<typename R, typename ... Args>
struct foo<R(Args...)> {
static R bar(Args...) {}
};
// Offending code.
template<typename T, typename ... IArgs>
auto test(IArgs... inputs) {
[&]<typename R, typename... Args>(type_holder<R(Args...)>, Args... values) {
// This always works.
foo<T>::bar(values...);
// This does not always work.
if constexpr (std::is_same_v<R, void>) {
if constexpr (sizeof...(Args) > 0) {
foo<T>::bar(values...);
} else {
foo<T>::bar();
}
} else {
int return_value = 0;
if constexpr (sizeof...(Args) > 0) {
return_value = foo<T>::bar(values...);
} else {
return_value = foo<T>::bar();
}
}
}(type_holder<T>{}, inputs...);
}
int main() {
// <source>:35:32: error: assigning to 'int' from incompatible type 'void'
// return_value = foo<T>::bar();
// ^~~~~~~~~~~~~
test<void()>();
//<source>:28:29: error: too few arguments to function call, expected 1, have 0
// foo<T>::bar();
// ~~~~~~~~~~~ ^
test<void(int)>(1);
// works!
test<int()>();
//<source>:28:29: error: too few arguments to function call, expected 1, have 0
// foo<T>::bar();
// ~~~~~~~~~~~ ^
test<int(int)>(1);
return 0;
}
```
Test cases:
1. As you can see from the errors reported, `test<void()>()` generates an error inside an `if constexpr` branch that should not be entered. `std::is_same_v<R, void>` should be true, but it took (or at least, also tried to compile) the false branch.
2. Similar story with `test<void(int)>(1)`. There it took the correct branch for the return type, but then took the wrong branch for the arguments. `sizeof...(Args) > 0` should be true, but it took (or at least, also tried to compile) the false branch.
3. `test<int()>()` works fine, for some reason (it is the case that corresponds to the `else` branch for all `if constexpr` checks).
4. `test<int(int)>(1)` fails again and takes the wrong branch for the return value and the arguments.
Extra information:
- The code compiles if using `foo<R(Args...)>` instead of `foo<T>`, which should be equivalent. Weirdly enough, as this seems orthogonal to the `if constexpr` issue.
- The code always failed to compile with clang since generic lambda with explicit template parameters were added (clang 9 with `-std=c++2a`).
- The code compiles with GCC 8 (`-std=c++2a`) and above.
- The code compiles with MSVC 19.30 and above.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJztWE1z4jgQ_TXmohqXMQHMgUOGZKZy2NqqmdTuMSXbAmtHWKwkw2R__b6WbGLAJJPamdtSlINtdev1608l1-Xz8rESzAnrWKFLwXKh9IGVWlhWa3q23UklWJRmsmarKP2Ib5qwLdZG6YIdpKsYr5_ZXhgrdc30mhWK1xv2ANlGlUE1yQZNht1_3ylt8AM6mx1zGvIlVhSqKSUEg_h4CvXR5DZK7qLkNpol4VsEBO3TdBLEgG-ycs878eQMl85Gk_t2RbvuE77ss6iFkQWjhazSqhQmSldsrY1_ZJmrOCzmNRmeC0CyjteF5E6UcdDkxHancN9uV_OtYI_H3awzTeG8sqegn0Xzj9H8Lpp8fAsPaCiMgGrG2bqpC0dkBnbZRu5Fzazc1Nw1RrwHy1rrs82HxL4QD8e7OI7ZrdnYQV0rrM3oLVZ5D917G_06hg8oc7DpC8u5OVnZURGgXOPk9_Va1CEMEGGvWnoO-eEEM2_AKMUeQDy0KODRXYPoaMEcMUdTxNQsmt5d5aRPSZr1HDxECAl2O-65asTljn7XYPFjJS3j6sCfLTto883Gp8sC696xyIbJbeA16O22PGFySP8xn3sbne0jkbgaES--73xqWleGDaV9sqDgaR9sXbG9lqU3c8CoQU3yH6HXHqsnygsibpKrGt5pd18MkcWEsuK9il_Rd0brqxvI2jEjkKX1k4cKQ-9g6JDmn0PTxWa_jLcf3Ok9RPZSEDfnieU1h6KBqAu5ex7xx4Lir8T-lss6wDhL8pAO0Gt1YwoRYE-mdElxYcIYbegHt1RqqQahhETpHFpxZWujt9Sm0MdQ4nI0RV-48conRDq_2OsnMXhF29knmoKsH_ge1friOFkF8FlXurLhghIwnJGHxbgsTshzWrO1ODBuNs1W1M4SiceGVnClyJmIeVGgrbIx3VV8LxDmbxj8X8h6kxZP3xVqvP9bdsav0RPqd5SOLzR5Ff9zPMBxYOYHKA7J06ulL7nfDYd9kUc_0XKL5tsNkWyMJm7Zs25oyGNWiJDTDgOw59Zik5024IwYg8JXUmSWsA3NbxhL0L7roIBGRolpFPdY0C_wtD43mCarMGXayg_H7aQJHwqDIZOk3u67UNWKQxSjmaCXeYMp21FofKNmAizYRQlOA9AKbd9iGjIS0UCDZhjFqUSS7WtOdT-gi-HHQFYas69yKxU3mOm0eQ7D6AUpF56bJTFmDphzhEN7FNoYRGPHgZ-58bh1KhXSzgg8rl_kDkajDp9JHeM-EHa1b_5SolqaJnGPk4E0BwZfFdha1qI7bli9Jdu5RboSh0BkA00I2PYYQoTZna5Ln930ErqoQ_dCiXQh24eCrahEQbVo0QG9uQQ64DvYKBUCeoMu6s9ljn8T9rorWgeGlubXn_inn5H333E4Q4ZAdMupUr0k5geKmHD-bCm3NB41lpowUF05eRBeOqQJXtK587jwMbwjtg-VBNqXKBB_NxJgAS5mfwppSvWM7NPNpvLeJ0vhCpSGrWWoBJXe6JqrngfOeZbWNt05pW9HO2gTnSexFNIonHFhXiFCGcGRSfFtXvLwHtqVLChM26MP23GDYoAygeGdkouXJfSCkaBqcUzPD76A3LUH5ZR7IhYDCI9Me8nPqxXLSN9VFd69PNf7IXNPlf329Y8VGy_iSdITGonleDabZ4v5IstG5XJSLiYLPnLSKbF8qLsKMcCxoPDyIUP_SKgRwjD9vbSNGqOWlXM73xB8B9tApsljYMeNUvvuz4ed0X8BC269e5FGn6ZZNk9H1ZInQqSzIsmKm7yczbJpMsnSIlvzUuSzPJ2OFM-RpUs6U07vRnKZJmk6HidZkk0XN_N4PbspsnzGCzGfzmfZIrpJBEZWFdPGsTabkVl6DHmDUnaTKGmRR8eXYTYVotOPY26lzbKwRWWEzEce79KD_Re41SZZ">