// 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 dr2007 { // dr2007: 3.4 template struct A { typename T::error e; }; template struct B { }; B > b1; B > b2 = b1; int a = b2[0]; // cxx98-error@-1 {{type 'B >' does not provide a subscript operator}} // since-cxx11-error@-2 {{type 'B>' does not provide a subscript operator}} int b = __builtin_addressof(b2)->foo; // cxx98-error@-1 {{no member named 'foo' in 'dr2007::B >'}} // since-cxx11-error@-2 {{no member named 'foo' in 'dr2007::B>'}} } // dr2009: na namespace dr2026 { // dr2026: 11 template struct X {}; const int a = a + 1; // #dr2026-a // expected-warning@-1 {{variable 'a' is uninitialized when used within its own initialization}} X xa; // #dr2026-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@#dr2026-a {{declared here}} // since-cxx11-error@#dr2026-xa {{non-type template argument is not a constant expression}} // since-cxx11-note@#dr2026-xa {{initializer of 'a' is not a constant expression}} // since-cxx11-note@#dr2026-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; // #dr2026-e // expected-warning@-1 {{static variable 'e' is suspiciously used within its own initialization}} X xe; // #dr2026-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@#dr2026-e {{declared here}} // since-cxx11-error@#dr2026-xe {{non-type template argument is not a constant expression}} // since-cxx11-note@#dr2026-xe {{initializer of 'e' is not a constant expression}} // since-cxx11-note@#dr2026-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 dr2049 { // dr2049: 18 drafting #if __cplusplus >= 202302L template struct X {}; X<> a; X b; static_assert(__is_same(decltype(a), decltype(b))); #endif } namespace dr2061 { // dr2061: 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 void f(); template struct S; } } } namespace A { namespace C { template<> void f() { } template<> struct S { }; } } void use() { A::C::f(); A::C::S s; } #endif // C++11 } namespace dr2076 { // dr2076: 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 &); // #dr2076-foo void bar(string_view); // #dr2076-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@#dr2076-foo {{cannot convert initializer list}} bar(arg); bar({arg}); bar({{arg}}); // since-cxx11-error@-1 {{no matching function}} // since-cxx11-note@#dr2076-bar {{cannot convert initializer list}} bar({{{arg}}}); // since-cxx11-error@-1 {{no matching function}} // since-cxx11-note@#dr2076-bar {{cannot convert initializer list}} } #endif } namespace dr2082 { // dr2082: 11 void test1(int x, int = sizeof(x)); // ok #if __cplusplus >= 201103L void test2(int x, int = decltype(x){}); // ok #endif } namespace dr2083 { // dr2083: 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 DR2083. void ref_to_non_const() { int c; const int &ra = a; // #dr2083-ra int &rb = b; // #dr2083-rb int &rc = c; // #dr2083-rc struct A { int f() { int a = ra; // cxx98-error@-1 {{reference to local variable 'ra' declared in enclosing function 'dr2083::ref_to_non_const'}} // cxx98-note@#dr2083-ra {{'ra' declared here}} int b = rb; // cxx98-error@-1 {{reference to local variable 'rb' declared in enclosing function 'dr2083::ref_to_non_const'}} // cxx98-note@#dr2083-rb {{'rb' declared here}} int c = rc; // expected-error@-1 {{reference to local variable 'rc' declared in enclosing function 'dr2083::ref_to_non_const'}} // expected-note@#dr2083-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}; // #dr2083-m1 constexpr Mut2 m2 = {1, 2}; // #dr2083-m2 constexpr Mut3 m3 = {1, 2}; // #dr2083-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 'dr2083::mutable_subobjects'}} // since-cxx11-note@#dr2083-m1 {{'m1' declared here}} static_assert(m2.m.a == 1, ""); // since-cxx11-error@-1 {{reference to local variable 'm2' declared in enclosing function 'dr2083::mutable_subobjects'}} // since-cxx11-note@#dr2083-m2 {{'m2' declared here}} static_assert(m3.a == 1, ""); // since-cxx11-error@-1 {{reference to local variable 'm3' declared in enclosing function 'dr2083::mutable_subobjects'}} // since-cxx11-note@#dr2083-m3 {{'m3' declared here}} } }; } #endif void ellipsis() { void ellipsis(...); struct A {}; const int n = 0; #if __cplusplus >= 201103L constexpr #endif A a = {}; // #dr2083-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 'dr2083::ellipsis'}} // expected-note@#dr2083-a {{'a' declared here}} } }; } #if __cplusplus >= 201103L void volatile_lval() { struct A { int n; }; constexpr A a = {0}; // #dr2083-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 'dr2083::volatile_lval'}} // since-cxx11-note@#dr2083-a2 {{'a' declared here}} } }; } #endif void discarded_lval() { struct A { int x; mutable int y; volatile int z; }; A a; // #dr2083-a-3 int &r = a.x; // #dr2083-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 'dr2083::discarded_lval'}} FIXME // expected-note@#dr2083-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 'dr2083::discarded_lval'}} FIXME // expected-note@#dr2083-a-3 {{'a' declared here}} true ? a.x : a.y; // #dr2083-ternary // expected-warning@-1 {{expression result unused}} // expected-error@#dr2083-ternary {{reference to local variable 'a' declared in enclosing function 'dr2083::discarded_lval'}} FIXME // expected-note@#dr2083-a-3 {{'a' declared here}} // expected-error@#dr2083-ternary {{reference to local variable 'a' declared in enclosing function 'dr2083::discarded_lval'}} FIXME // expected-note@#dr2083-a-3 {{'a' declared here}} (void)a.x; // expected-error@-1 {{reference to local variable 'a' declared in enclosing function 'dr2083::discarded_lval'}} FIXME // expected-note@#dr2083-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 'dr2083::discarded_lval'}} FIXME // expected-note@#dr2083-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 'dr2083::discarded_lval'}} // expected-note@#dr2083-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 'dr2083::discarded_lval'}} // expected-note@#dr2083-r {{'r' declared here}} } }; } namespace dr_example_1 { extern int globx; int main() { const int &x = globx; // #dr2083-x struct A { const int *foo() { return &x; } // cxx98-error@-1 {{reference to local variable 'x' declared in enclosing function 'dr2083::dr_example_1::main'}} // cxx98-note@#dr2083-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 dr2094 { // dr2094: 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&), ""); } // dr2096: dup 2598