66 lines · cpp
1// RUN: %clang_cc1 -std=c++20 -fcxx-exceptions -verify %s2 3struct A { int n; };4 5template<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}}7};8 9template<A a> struct C {10 static constexpr const A &v = a;11};12 13// All such template parameters in the program of the same type with the same14// value denote the same template parameter object.15template<A a, typename T> void check() {16 static_assert(&a == &T::v); // expected-error {{failed}}17}18 19using T = C<A{1}>;20template void check<A{1}, T>();21template void check<A{2}, T>(); // expected-note {{instantiation of}}22 23// Different types with the same value are unequal.24struct A2 { int n; };25template<A2 a2> struct C2 {26 static constexpr const A2 &v = a2;27};28static_assert((void*)&C<A{}>::v != (void*)&C2<A2{}>::v);29 30// A template parameter object shall have constant destruction.31namespace ConstDestruction {32 struct D {33 int n;34 bool can_destroy;35 36 constexpr ~D() {37 if (!can_destroy)38 throw "oh no"; // expected-note {{subexpression not valid}}39 }40 };41 42 template<D d>43 void f() {} // expected-note 2{{invalid explicitly-specified argument}}44 45 void g() {46 f<D{0, true}>();47 f<D{0, false}>(); // expected-error {{no matching function}}48 }49 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}>());53 54 void i() {55 h(D());56 // Ensure we don't cache an invalid template argument after we've already57 // seen it in a SFINAE context.58 f<D{1, false}>(); // expected-error {{no matching function}}59 f<D{1, true}>();60 }61 62 template<D d> struct Z {};63 Z<D{2, true}> z1;64 Z<D{2, false}> z2; // expected-error {{non-type template argument is not a constant expression}} expected-note-re {{in call to '{{.*}}.~D()'}}65}66