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

    <tr>
        <th>Summary</th>
        <td>
            NTTP of structural class types pass values literally when used directly (should: invoke copy constructors) in Clang 15 (C++)
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            new issue
      </td>
    </tr>

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

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

<pre>
    The Clang C++ compiler produces the wrong output for the following valid C++20 source code:
    
```
/*
 * @author{Jelle Hellings}.
 */
#include <iostream>
#include <functional>


/*
 * A function object that returns the input.
 */
constexpr static inline std::identity id = {};


/*
 * A structural class type that keeps track of copies: if a value of this type
 * with copy count @{copy_count} is copied, then the resulting copy will have a
 * copy count of @{copy_count + 1}.
 */
struct copy_counter
{
    /* The copy count. */
    unsigned copy_count;


    /*
     * Create a copy counter: start at zero by default.
     */
    constexpr copy_counter(unsigned init = 0u) noexcept : copy_count{init} {}

    /*
     * The copy constructor: increases the count by one.
     */
    constexpr copy_counter(const copy_counter& other) noexcept :
            copy_count(other.copy_count + 1u) {}
};


/*
 * A template that takes a copy counter @{C} as a non-type template parameter
 * and prints it to standard output. In addition, print the expected value
 * provided by @{expected}.
 */
template<copy_counter C>
void print_nttp(const auto& expected)
{
    std::cout << C.copy_count
              << " (expected: " << expected.copy_count << ")" << std::endl;
}


/*
 * A template that takes a copy counter @{C} as a non-type template parameter
 * and passes it to the above print function in a few different ways.
 */
template<copy_counter C>
void test_cases()
{
    constexpr const copy_counter D = {C.copy_count};
 static_assert(C.copy_count == D.copy_count);

 print_nttp<C>(static_cast<copy_counter>(C));
 print_nttp<D>(static_cast<copy_counter>(D));
 print_nttp<(C)>(static_cast<copy_counter>((C)));
    print_nttp<(C, C)>(static_cast<copy_counter>((C, C)));
 print_nttp<id(C)>(static_cast<copy_counter>(id(C)));
 print_nttp<copy_counter{C}>(static_cast<copy_counter>(copy_counter{C}));
}


/*
 * Entry-point of the program.
 */
int main()
{
 test_cases<copy_counter{}>();
}
```

We have used both the Clang C++ compiler 15.0.1 of Visual Studio 17.4.3 and the x86-64 Clang 15.0.0 compiler  (with -std=c++20  and -std=c++2b) on Compiler Explorer.

According to the C++20 standard, the above code should output:
```
1 (expected: 1)
1 (expected: 1)
1 (expected: 1)
1 (expected: 1)
1 (expected: 1)
1 (expected: 1)
```

When compiled with both versions of Clang we tried, the above code _incorrectly_ outputs:
```
0 (expected: 1)
1 (expected: 1)
0 (expected: 1)
1 (expected: 1)
1 (expected: 1)
1 (expected: 1)
```

Note specifically that Clang currently generates different instantiations of `print_nttp` even in cases where _identical_ template arguments are provided (the first two cases).

We refer to the article https://jhellings.nl/article?articleid=1 for a full analysis of what this program should do. In short:

Clause 8 in Section [temp.param] of the C++ standard says:

    An id-expression naming a non-type template-parameter of class type T denotes a static storage duration object of type const T known as a template parameter object, whose value is that of the corresponding template argument after it has been converted to the type of the template-parameter. ...
    
In this case, a conversion of an expression e used as a template argument to type copy_counter will _always_ invoke the copy-constructor, the result of which can be verified via static_cast<copy_counter>(e) according to Clause 1 of Section [expr.static.ast] (The result of the expression static_cast<T>(v) is the result of converting the expression v to type T. ... )
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzMWFtv47oR_jX0yyCCTMW3Bz_4skFPHw4KnKB9DGhpbHGXJgWSsuP--mJISpYdZ5GzLdCzCLKOxPk4M99cLZyTB424ZJM1m2xHovW1scvvtUU32pnqsnytETZK6ANsGF8zvobSHBup0EJjTdWW6MDXCGdr9AFM65vWw97Y8HBvlDJnqQ9wEkpWHQTPwZnWlgilqZAVK5ZvWb4CAIif2DRPP_FP_sJ4d4jxFbDnPGrKZuu_o1IIf0OlpD44Nttm14MkmBAKqUvVVgis2EjjvEVxZMW3R6_3rS69NFqo64Hh73ttVtBJgNl9x9KDr4UHi761OnpH6qb1jxQrjXYe3xsLzgsvS5BaSY3gfEV-KVayQu2lv4CsgBVbYLM1m21Zsf6SYs7btvStFQpKJZwDf2kwqvcDsXHgrSh_gNlDaRqJjhUrkHsQxFeL9NzXMkoNcM_S1yRwgdK02hMdbLamB2_hAZttQboIWTG-IRfo4AeLrlWeAiKIn6VSUIsTghjAD5DN_gM4UAyOP-E52gvX02iTb2brQZAFRwGF9vWu7AaIjrU6JEc1gHvo9yvk9e9gyMai8AhicAtacrHzwnoQHv6N1sDuAhXuRav6CEkAN9pcI-XGOj7v1ZRa-hAjecv4ArTB9xIberQamjBb00HiKMXSV0wZ-EpHJ5tgidSlReFSEYgE7S5gNP6SLeHF3cMpGF_Th1uTBvDp38BGPg8y2X3YBMfcmP31XPJ4bBTxGdLHix_o7qhNsboh3wp6qY1-ihnXyTbCiiP2YRmgha6gsVJ7B9KDNxQeuhK2SuU0g980iKqSVGIoncLh4HB8b7D0WMV8HWA21pxkhRWREbXqjn6SOZ2GrNgM3Q-bvgaejEx6vmnvm54t0XpDLPUX8MWDnOsLWmla4m_Dig1sBgR95BO6Y4xzYHzeX1Cs4qP4tnt8Q3YvSNpcz_ZaoK7UlfjbJPg_RYBwlEYxAohbsTMnTFz3DUZqELDHM1Ryv0eL2sNZXNx_wahH599KSmHG54-5G6brfX7CtmtLN2QO0ip1tjeyz1Jqbm6Z2pL8dijMF3c5OQy7YhMM4PMEWwrn70yM7zeB-ivULcj2ayDbn4J0t3wJaqDSEBDgEeYG_ixwkviZurL6Uwpfj_8M9EYuhv7X4B8J3l70tbz8pr29PDVGxnmBUqex5mDF8VFW0KmjkPpxsA-S4YNlvWGPVbwbWcPvf2GcblpHldj4Omj3yTg9nmR5NiYT_ildKxT84dtKGhjPsuesCDWCpN_n06fpcwIJMvkVg8pkmM6eQqXblv3AHeTvnu6oGxoNm07823ujjEWbDY1YlaWxFc1sqTANpvjUqNKMl0oWDfXgatOqroP17frOS-P7sj7uOfmLvHpMK42zyedVnIYDuSe0ThrtiMPIzxnB2-sQPHTQm9SlsRZLry5vyU_uM0flv6T8r0n9Dx31u_EIrsFS7mUplLrEzhl9U7aW-pe6wAE1WuHRDbqa1BRcXgrfeZRN80HhmeaAJwwNMeQrnGu05NWwL5VCvV1brrCH9og0XwmL19GI8XlYUqV1HvzZQOqCi-wuhy3u0fZt2XpZKoTa-ybwRfXo5XudFtBMK8Zf0iFWdJ8k5d04LMYC9q1SILRQFyeDaecwT9CmlSpXlz6VCcOfq40dJFH4vVGidQhz8sAfGKcDNlmT0VmYMdhk29XDrtb0g6UTF3eHR41opUFWT9Tp0VEkgxZHSvwHc8xTP8eE7fG6XL5Chdr4MBqlndZ5Y8UBoWqtGK7JpB2JxKniFX5oc9Zxbvo4LiUhyqRzbRymFZW2U_JesjSklGuMjgXrPgJA7AlKeqiFgx2GPNYntDRDJ4KDSgnuo7UZZFl2_33FbzqyRwFECoqEGnxo9iA0DJya-sGtnb2GpEV0ymDICovym1A0672B1CfzA5O9zeVpuJOlQhMX7RhbsqyhFBp2SBVK7iXtC7Jj5_MGjdQexLD6p5gLTWoQc2RbFtEyAptsKbdeb9RI20rng9u7X-OFJ7pQujsDEkFBhVuQU--s10ALML4YVcuiWhQLMcLleDrjOefPfDaql3y-KDjnopqX8-me55OqeJ7OhKjK3a6YLaqRXNLhMefTnD_nfJbNOc_nfDx53k35Yp9P2HOORyFVptTpmBl7GEnnWlxOFtPFYqTEDpULX6RxrvEM4SVtIJPtyC5J5mnXHhx7zpV03l1RvPQKl7-_vv6DzH34lY0L60EMeQdKerShnJ6pE4VoqmRsJeT5WDzieh4i5X5zd8HRuh8iIA566_CzGLVWLW_L20H6ut1lpTky_kKKp_-eGmtiVr4Ecx3jL8Ed_wkAAP__2vZI6w">