| // RUN: %clang_cc1 -std=c++98 -triple x86_64-unknown-unknown %s -verify=expected,cxx98 -fexceptions -fcxx-exceptions -pedantic-errors |
| // RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,cxx11 -fexceptions -fcxx-exceptions -pedantic-errors |
| // RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx14 -fexceptions -fcxx-exceptions -pedantic-errors |
| // RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx14 -fexceptions -fcxx-exceptions -pedantic-errors |
| // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx14,since-cxx20 -fexceptions -fcxx-exceptions -pedantic-errors |
| // RUN: %clang_cc1 -std=c++23 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx14,since-cxx20 -fexceptions -fcxx-exceptions -pedantic-errors |
| // RUN: %clang_cc1 -std=c++2c -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx14,since-cxx20 -fexceptions -fcxx-exceptions -pedantic-errors |
| |
| #if __cplusplus == 199711L |
| #define static_assert(...) __extension__ _Static_assert(__VA_ARGS__) |
| // cxx98-error@-1 {{variadic macros are a C99 feature}} |
| #endif |
| |
| namespace cwg2007 { // cwg2007: 3.4 |
| template<typename T> struct A { typename T::error e; }; |
| template<typename T> struct B { }; |
| B<A<void> > b1; |
| B<A<void> > b2 = b1; |
| int a = b2[0]; |
| // cxx98-error@-1 {{type 'B<A<void> >' does not provide a subscript operator}} |
| // since-cxx11-error@-2 {{type 'B<A<void>>' does not provide a subscript operator}} |
| int b = __builtin_addressof(b2)->foo; |
| // cxx98-error@-1 {{no member named 'foo' in 'cwg2007::B<cwg2007::A<void> >'}} |
| // since-cxx11-error@-2 {{no member named 'foo' in 'cwg2007::B<cwg2007::A<void>>'}} |
| } |
| |
| // cwg2009: na |
| |
| namespace cwg2026 { // cwg2026: 11 |
| template<int> struct X {}; |
| |
| const int a = a + 1; // #cwg2026-a |
| // expected-warning@-1 {{variable 'a' is uninitialized when used within its own initialization}} |
| X<a> xa; // #cwg2026-xa |
| // cxx98-error@-1 {{non-type template argument of type 'int' is not an integral constant expression}} |
| // cxx98-note@-2 {{initializer of 'a' is not a constant expression}} |
| // cxx98-note@#cwg2026-a {{declared here}} |
| // since-cxx11-error@#cwg2026-xa {{non-type template argument is not a constant expression}} |
| // since-cxx11-note@#cwg2026-xa {{initializer of 'a' is not a constant expression}} |
| // since-cxx11-note@#cwg2026-a {{declared here}} |
| |
| #if __cplusplus >= 201103L |
| constexpr int b = b; |
| // since-cxx11-error@-1 {{constexpr variable 'b' must be initialized by a constant expression}} |
| // since-cxx11-note@-2 {{read of object outside its lifetime is not allowed in a constant expression}} |
| [[clang::require_constant_initialization]] int c = c; |
| // since-cxx11-error@-1 {{variable does not have a constant initializer}} |
| // since-cxx11-note@-2 {{required by 'require_constant_initialization' attribute here}} |
| // cxx11-note@-3 {{read of non-const variable 'c' is not allowed in a constant expression}} |
| // cxx11-note@-4 {{declared here}} |
| // since-cxx14-note@-5 {{read of object outside its lifetime is not allowed in a constant expression}} |
| #endif |
| |
| #if __cplusplus >= 202002L |
| constinit int d = d; |
| // since-cxx20-error@-1 {{variable does not have a constant initializer}} |
| // since-cxx20-note@-2 {{required by 'constinit' specifier here}} |
| // since-cxx20-note@-3 {{read of object outside its lifetime is not allowed in a constant expression}} |
| #endif |
| |
| void f() { |
| static const int e = e + 1; // #cwg2026-e |
| // expected-warning@-1 {{static variable 'e' is suspiciously used within its own initialization}} |
| X<e> xe; // #cwg2026-xe |
| // cxx98-error@-1 {{non-type template argument of type 'int' is not an integral constant expression}} |
| // cxx98-note@-2 {{initializer of 'e' is not a constant expression}} |
| // cxx98-note@#cwg2026-e {{declared here}} |
| // since-cxx11-error@#cwg2026-xe {{non-type template argument is not a constant expression}} |
| // since-cxx11-note@#cwg2026-xe {{initializer of 'e' is not a constant expression}} |
| // since-cxx11-note@#cwg2026-e {{declared here}} |
| |
| #if __cplusplus >= 201103L |
| static constexpr int f = f; |
| // since-cxx11-error@-1 {{constexpr variable 'f' must be initialized by a constant expression}} |
| // since-cxx11-note@-2 {{read of object outside its lifetime is not allowed in a constant expression}} |
| [[clang::require_constant_initialization]] static int g = g; |
| // since-cxx11-error@-1 {{variable does not have a constant initializer}} |
| // since-cxx11-note@-2 {{required by 'require_constant_initialization' attribute here}} |
| // cxx11-note@-3 {{read of non-const variable 'g' is not allowed in a constant expression}} |
| // cxx11-note@-4 {{declared here}} |
| // since-cxx14-note@-5 {{read of object outside its lifetime is not allowed in a constant expression}} |
| #endif |
| |
| #if __cplusplus >= 202002L |
| static constinit int h = h; |
| // since-cxx20-error@-1 {{variable does not have a constant initializer}} |
| // since-cxx20-note@-2 {{required by 'constinit' specifier here}} |
| // since-cxx20-note@-3 {{read of object outside its lifetime is not allowed in a constant expression}} |
| #endif |
| } |
| } |
| |
| namespace cwg2049 { // cwg2049: 18 |
| #if __cplusplus >= 202302L |
| template <int* x = {}> struct X {}; |
| X<> a; |
| X<nullptr> b; |
| static_assert(__is_same(decltype(a), decltype(b))); |
| #endif |
| } |
| |
| namespace cwg2061 { // cwg2061: yes |
| #if __cplusplus >= 201103L |
| namespace A { |
| inline namespace b { |
| namespace C { |
| // 'f' is the example from the DR. 'S' is an example where if we didn't |
| // properly handle the two being the same, we would get an incomplete |
| // type error during attempted instantiation. |
| template<typename T> void f(); |
| template<typename T> struct S; |
| } |
| } |
| } |
| |
| namespace A { |
| namespace C { |
| template<> void f<int>() { } |
| template<> struct S<int> { }; |
| } |
| } |
| |
| void use() { |
| A::C::f<int>(); |
| A::C::S<int> s; |
| } |
| #endif // C++11 |
| } |
| |
| namespace cwg2076 { // cwg2076: 13 |
| #if __cplusplus >= 201103L |
| namespace std_example { |
| struct A { A(int); }; |
| struct B { B(A); }; |
| B b{{0}}; |
| |
| struct Params { int a; int b; }; |
| struct Foo { |
| Foo(Params); |
| }; |
| Foo foo{{1, 2}}; |
| } |
| |
| struct string_view { |
| string_view(int); // not an aggregate |
| }; |
| struct string { |
| string(int); // not an aggregate |
| operator string_view() const; |
| }; |
| |
| void foo(const string &); // #cwg2076-foo |
| void bar(string_view); // #cwg2076-bar |
| |
| void func(const string &arg) { |
| // An argument in one set of braces is subject to user-defined conversions; |
| // an argument in two sets of braces is not, but an identity conversion is |
| // still OK. |
| foo(arg); |
| foo({arg}); |
| foo({{arg}}); |
| foo({{{arg}}}); |
| // since-cxx11-error@-1 {{no matching function}} |
| // since-cxx11-note@#cwg2076-foo {{cannot convert initializer list}} |
| bar(arg); |
| bar({arg}); |
| bar({{arg}}); |
| // since-cxx11-error@-1 {{no matching function}} |
| // since-cxx11-note@#cwg2076-bar {{cannot convert initializer list}} |
| bar({{{arg}}}); |
| // since-cxx11-error@-1 {{no matching function}} |
| // since-cxx11-note@#cwg2076-bar {{cannot convert initializer list}} |
| } |
| #endif |
| } |
| |
| namespace cwg2082 { // cwg2082: 11 |
| void test1(int x, int = sizeof(x)); // ok |
| #if __cplusplus >= 201103L |
| void test2(int x, int = decltype(x){}); // ok |
| #endif |
| } |
| |
| namespace cwg2083 { // cwg2083: partial |
| #if __cplusplus >= 201103L |
| void non_const_mem_ptr() { |
| struct A { |
| int x; |
| int y; |
| }; |
| constexpr A a = {1, 2}; |
| struct B { |
| int A::*p; |
| constexpr int g() const { |
| // OK, not an odr-use of 'a'. |
| return a.*p; |
| }; |
| }; |
| static_assert(B{&A::x}.g() == 1, ""); |
| static_assert(B{&A::y}.g() == 2, ""); |
| } |
| #endif |
| |
| const int a = 1; |
| int b; |
| // Note, references only get special odr-use / constant initializxer |
| // treatment in C++11 onwards. We continue to apply that even after CWG2083. |
| void ref_to_non_const() { |
| int c; |
| const int &ra = a; // #cwg2083-ra |
| int &rb = b; // #cwg2083-rb |
| int &rc = c; // #cwg2083-rc |
| struct A { |
| int f() { |
| int a = ra; |
| // cxx98-error@-1 {{reference to local variable 'ra' declared in enclosing function 'cwg2083::ref_to_non_const'}} |
| // cxx98-note@#cwg2083-ra {{'ra' declared here}} |
| int b = rb; |
| // cxx98-error@-1 {{reference to local variable 'rb' declared in enclosing function 'cwg2083::ref_to_non_const'}} |
| // cxx98-note@#cwg2083-rb {{'rb' declared here}} |
| int c = rc; |
| // expected-error@-1 {{reference to local variable 'rc' declared in enclosing function 'cwg2083::ref_to_non_const'}} |
| // expected-note@#cwg2083-rc {{'rc' declared here}} |
| return a + b + c; |
| } |
| }; |
| } |
| |
| #if __cplusplus >= 201103L |
| struct NoMut1 { int a, b; }; |
| struct NoMut2 { NoMut1 m; }; |
| struct NoMut3 : NoMut1 { |
| constexpr NoMut3(int a, int b) : NoMut1{a, b} {} |
| }; |
| struct Mut1 { |
| int a; |
| mutable int b; |
| }; |
| struct Mut2 { Mut1 m; }; |
| struct Mut3 : Mut1 { |
| constexpr Mut3(int a, int b) : Mut1{a, b} {} |
| }; |
| void mutable_subobjects() { |
| constexpr NoMut1 nm1 = {1, 2}; |
| constexpr NoMut2 nm2 = {1, 2}; |
| constexpr NoMut3 nm3 = {1, 2}; |
| constexpr Mut1 m1 = {1, 2}; // #cwg2083-m1 |
| constexpr Mut2 m2 = {1, 2}; // #cwg2083-m2 |
| constexpr Mut3 m3 = {1, 2}; // #cwg2083-m3 |
| struct A { |
| void f() { |
| static_assert(nm1.a == 1, ""); |
| static_assert(nm2.m.a == 1, ""); |
| static_assert(nm3.a == 1, ""); |
| // Can't even access a non-mutable member of a variable containing mutable fields. |
| static_assert(m1.a == 1, ""); |
| // since-cxx11-error@-1 {{reference to local variable 'm1' declared in enclosing function 'cwg2083::mutable_subobjects'}} |
| // since-cxx11-note@#cwg2083-m1 {{'m1' declared here}} |
| static_assert(m2.m.a == 1, ""); |
| // since-cxx11-error@-1 {{reference to local variable 'm2' declared in enclosing function 'cwg2083::mutable_subobjects'}} |
| // since-cxx11-note@#cwg2083-m2 {{'m2' declared here}} |
| static_assert(m3.a == 1, ""); |
| // since-cxx11-error@-1 {{reference to local variable 'm3' declared in enclosing function 'cwg2083::mutable_subobjects'}} |
| // since-cxx11-note@#cwg2083-m3 {{'m3' declared here}} |
| } |
| }; |
| } |
| #endif |
| |
| void ellipsis() { |
| void ellipsis(...); |
| struct A {}; |
| const int n = 0; |
| #if __cplusplus >= 201103L |
| constexpr |
| #endif |
| A a = {}; // #cwg2083-a |
| struct B { |
| void f() { |
| ellipsis(n); |
| // Even though this is technically modelled as an lvalue-to-rvalue |
| // conversion, it calls a constructor and binds 'a' to a reference, so |
| // it results in an odr-use. |
| ellipsis(a); |
| // expected-error@-1 {{reference to local variable 'a' declared in enclosing function 'cwg2083::ellipsis'}} |
| // expected-note@#cwg2083-a {{'a' declared here}} |
| } |
| }; |
| } |
| |
| #if __cplusplus >= 201103L |
| void volatile_lval() { |
| struct A { int n; }; |
| constexpr A a = {0}; // #cwg2083-a2 |
| struct B { |
| void f() { |
| // An lvalue-to-rvalue conversion of a volatile lvalue always results |
| // in odr-use. |
| int A::*p = &A::n; |
| int x = a.*p; |
| volatile int A::*q = p; |
| int y = a.*q; |
| // since-cxx11-error@-1 {{reference to local variable 'a' declared in enclosing function 'cwg2083::volatile_lval'}} |
| // since-cxx11-note@#cwg2083-a2 {{'a' declared here}} |
| } |
| }; |
| } |
| #endif |
| |
| void discarded_lval() { |
| struct A { int x; mutable int y; volatile int z; }; |
| A a; // #cwg2083-a-3 |
| int &r = a.x; // #cwg2083-r |
| struct B { |
| void f() { |
| // FIXME: We emit more errors than we should be. They are explictly marked below. |
| a.x; |
| // expected-warning@-1 {{expression result unused}} |
| // expected-error@-2 {{reference to local variable 'a' declared in enclosing function 'cwg2083::discarded_lval'}} FIXME |
| // expected-note@#cwg2083-a-3 {{'a' declared here}} |
| a.*&A::x; |
| // expected-warning@-1 {{expression result unused}} |
| // expected-error@-2 {{reference to local variable 'a' declared in enclosing function 'cwg2083::discarded_lval'}} FIXME |
| // expected-note@#cwg2083-a-3 {{'a' declared here}} |
| true ? a.x : a.y; // #cwg2083-ternary |
| // expected-warning@-1 {{expression result unused}} |
| // expected-error@#cwg2083-ternary {{reference to local variable 'a' declared in enclosing function 'cwg2083::discarded_lval'}} FIXME |
| // expected-note@#cwg2083-a-3 {{'a' declared here}} |
| // expected-error@#cwg2083-ternary {{reference to local variable 'a' declared in enclosing function 'cwg2083::discarded_lval'}} FIXME |
| // expected-note@#cwg2083-a-3 {{'a' declared here}} |
| (void)a.x; |
| // expected-error@-1 {{reference to local variable 'a' declared in enclosing function 'cwg2083::discarded_lval'}} FIXME |
| // expected-note@#cwg2083-a-3 {{'a' declared here}} |
| a.x, discarded_lval(); |
| // expected-warning@-1 {{left operand of comma operator has no effect}} |
| // expected-error@-2 {{reference to local variable 'a' declared in enclosing function 'cwg2083::discarded_lval'}} FIXME |
| // expected-note@#cwg2083-a-3 {{'a' declared here}} |
| |
| // 'volatile' qualifier triggers an lvalue-to-rvalue conversion. |
| a.z; |
| // cxx98-warning@-1 {{expression result unused; assign into a variable to force a volatile load}} |
| // expected-error@-2 {{reference to local variable 'a' declared in enclosing function 'cwg2083::discarded_lval'}} |
| // expected-note@#cwg2083-a-3 {{'a' declared here}} |
| |
| // References always get "loaded" to determine what they reference, |
| // even if the result is discarded. |
| r; |
| // expected-warning@-1 {{expression result unused}} |
| // expected-error@-2 {{reference to local variable 'r' declared in enclosing function 'cwg2083::discarded_lval'}} |
| // expected-note@#cwg2083-r {{'r' declared here}} |
| } |
| }; |
| } |
| |
| namespace dr_example_1 { |
| extern int globx; |
| int main() { |
| const int &x = globx; // #cwg2083-x |
| struct A { |
| const int *foo() { return &x; } |
| // cxx98-error@-1 {{reference to local variable 'x' declared in enclosing function 'cwg2083::dr_example_1::main'}} |
| // cxx98-note@#cwg2083-x {{'x' declared here}} |
| } a; |
| return *a.foo(); |
| } |
| } |
| |
| #if __cplusplus >= 201103L |
| namespace dr_example_2 { |
| struct A { |
| int q; |
| constexpr A(int q) : q(q) {} |
| constexpr A(const A &a) : q(a.q * 2) {} // (note, not called) |
| }; |
| |
| int main(void) { |
| constexpr A a(42); |
| constexpr int aq = a.q; |
| struct Q { |
| int foo() { return a.q; } |
| } q; |
| return q.foo(); |
| } |
| |
| // Checking odr-use does not invent an lvalue-to-rvalue conversion (and |
| // hence copy construction) on the potential result variable. |
| struct B { |
| int b = 42; |
| constexpr B() {} |
| constexpr B(const B&) = delete; |
| }; |
| void f() { |
| constexpr B b; |
| struct Q { |
| constexpr int foo() const { return b.b; } |
| }; |
| static_assert(Q().foo() == 42, ""); |
| } |
| } |
| #endif |
| } |
| |
| namespace cwg2094 { // cwg2094: 5 |
| struct A { int n; }; |
| struct B { volatile int n; }; |
| static_assert(__is_trivially_copyable(volatile int), ""); |
| static_assert(__is_trivially_copyable(const volatile int), ""); |
| static_assert(__is_trivially_copyable(const volatile int[]), ""); |
| static_assert(__is_trivially_copyable(A), ""); |
| static_assert(__is_trivially_copyable(volatile A), ""); |
| static_assert(__is_trivially_copyable(const volatile A), ""); |
| static_assert(__is_trivially_copyable(const volatile A[]), ""); |
| static_assert(__is_trivially_copyable(B), ""); |
| |
| static_assert(__is_trivially_constructible(A, A const&), ""); |
| static_assert(__is_trivially_constructible(B, B const&), ""); |
| |
| static_assert(__is_trivially_assignable(A, const A&), ""); |
| static_assert(__is_trivially_assignable(B, const B&), ""); |
| } |
| |
| // cwg2096: dup 2598 |