1 // RUN: %clang_cc1 -std=c++20 -fcxx-exceptions -verify %s
5 template<A a
> struct B
{
6 static constexpr A
&v
= a
; // expected-error {{binding reference of type 'A' to value of type 'const A' drops 'const' qualifier}}
9 template<A a
> struct C
{
10 static constexpr const A
&v
= a
;
13 // All such template parameters in the program of the same type with the same
14 // value denote the same template parameter object.
15 template<A a
, typename T
> void check() {
16 static_assert(&a
== &T::v
); // expected-error {{failed}}
20 template void check
<A
{1}, T
>();
21 template void check
<A
{2}, T
>(); // expected-note {{instantiation of}}
23 // Different types with the same value are unequal.
25 template<A2 a2
> struct C2
{
26 static constexpr const A2
&v
= a2
;
28 static_assert((void*)&C
<A
{}>::v
!= (void*)&C2
<A2
{}>::v
);
30 // A template parameter object shall have constant destruction.
31 namespace ConstDestruction
{
38 throw "oh no"; // expected-note {{subexpression not valid}}
43 void f() {} // expected-note 2{{invalid explicitly-specified argument}}
47 f
<D
{0, false}>(); // expected-error {{no matching function}}
50 // We can SFINAE on constant destruction.
51 template<typename T
> auto h(T t
) -> decltype(f
<T
{1, false}>());
52 template<typename T
> auto h(T t
) -> decltype(f
<T
{1, true}>());
56 // Ensure we don't cache an invalid template argument after we've already
57 // seen it in a SFINAE context.
58 f
<D
{1, false}>(); // expected-error {{no matching function}}
62 template<D d
> struct Z
{};
64 Z
<D
{2, false}> z2
; // expected-error {{non-type template argument is not a constant expression}} expected-note-re {{in call to '{{.*}}.~D()'}}