| // RUN: %clang_cc1 -std=c++17 %s -triple x86_64-linux-gnu -emit-llvm -o - | FileCheck %s --implicit-check-not='call{{.*}}dtor' |
| // RUN: %clang_cc1 -std=c++23 %s -triple x86_64-linux-gnu -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK-CXX23,CHECK-CXX23-NEXT,CHECK-CXX23-LABEL |
| |
| namespace std { |
| typedef decltype(sizeof(int)) size_t; |
| |
| template <class E> |
| struct initializer_list { |
| const E *begin; |
| size_t size; |
| initializer_list() : begin(nullptr), size(0) {} |
| }; |
| |
| template <typename E> |
| struct list { |
| list() {} |
| ~list() {} |
| E *begin(); |
| E *end(); |
| const E *begin() const; |
| const E *end() const; |
| }; |
| |
| template <typename E> |
| struct vector { |
| vector() {} |
| vector(std::initializer_list<E>) {} |
| ~vector() {} |
| E *begin(); |
| E *end(); |
| const E *begin() const; |
| const E *end() const; |
| }; |
| |
| template <typename T> |
| struct lock_guard { |
| lock_guard(T) {} |
| ~lock_guard() {} |
| }; |
| |
| struct mutex {}; |
| } // namespace std |
| |
| void then(); |
| |
| struct dtor { |
| ~dtor(); |
| }; |
| |
| dtor ctor(); |
| |
| auto &&lambda = [a = {ctor()}] {}; |
| // CHECK-LABEL: define |
| // CHECK: call {{.*}}ctor |
| // CHECK: call {{.*}}atexit{{.*}}global_array_dtor |
| |
| // CHECK-LABEL: define{{.*}}global_array_dtor |
| // CHECK: call {{.*}}dtor |
| |
| // [lifetime extension occurs if the object was obtained by] |
| // -- a temporary materialization conversion |
| // CHECK-LABEL: ref_binding |
| void ref_binding() { |
| // CHECK: call {{.*}}ctor |
| auto &&x = ctor(); |
| // CHECK: call {{.*}}then |
| then(); |
| // CHECK: call {{.*}}dtor |
| // CHECK: } |
| } |
| |
| // -- ( expression ) |
| // CHECK-LABEL: parens |
| void parens() { |
| // CHECK: call {{.*}}ctor |
| auto &&x = ctor(); |
| // CHECK: call {{.*}}then |
| then(); |
| // CHECK: call {{.*}}dtor |
| // CHECK: } |
| } |
| |
| // -- subscripting of an array |
| // CHECK-LABEL: array_subscript_1 |
| void array_subscript_1() { |
| using T = dtor[1]; |
| // CHECK: call {{.*}}ctor |
| auto &&x = T{ctor()}[0]; |
| // CHECK: call {{.*}}then |
| then(); |
| // CHECK: call {{.*}}dtor |
| // CHECK: } |
| } |
| // CHECK-LABEL: array_subscript_2 |
| void array_subscript_2() { |
| using T = dtor[1]; |
| // CHECK: call {{.*}}ctor |
| auto &&x = ((dtor*)T{ctor()})[0]; |
| // CHECK: call {{.*}}dtor |
| // CHECK: call {{.*}}then |
| then(); |
| // CHECK: } |
| } |
| |
| struct with_member { dtor d; ~with_member(); }; |
| struct with_ref_member { dtor &&d; ~with_ref_member(); }; |
| |
| // -- a class member access using the . operator [...] |
| // CHECK-LABEL: member_access_1 |
| void member_access_1() { |
| // CHECK: call {{.*}}ctor |
| auto &&x = with_member{ctor()}.d; |
| // CHECK: call {{.*}}then |
| then(); |
| // CHECK: call {{.*}}with_member |
| // CHECK: } |
| } |
| // CHECK-LABEL: member_access_2 |
| void member_access_2() { |
| // CHECK: call {{.*}}ctor |
| auto &&x = with_ref_member{ctor()}.d; |
| // CHECK: call {{.*}}with_ref_member |
| // CHECK: call {{.*}}dtor |
| // CHECK: call {{.*}}then |
| then(); |
| // CHECK: } |
| } |
| // CHECK-LABEL: member_access_3 |
| void member_access_3() { |
| // CHECK: call {{.*}}ctor |
| auto &&x = (&(const with_member&)with_member{ctor()})->d; |
| // CHECK: call {{.*}}with_member |
| // CHECK: call {{.*}}then |
| then(); |
| // CHECK: } |
| } |
| |
| // -- a pointer-to-member operation using the .* operator [...] |
| // CHECK-LABEL: member_ptr_access_1 |
| void member_ptr_access_1() { |
| // CHECK: call {{.*}}ctor |
| auto &&x = with_member{ctor()}.*&with_member::d; |
| // CHECK: call {{.*}}then |
| then(); |
| // CHECK: call {{.*}}with_member |
| // CHECK: } |
| } |
| // CHECK-LABEL: member_ptr_access_2 |
| void member_ptr_access_2() { |
| // CHECK: call {{.*}}ctor |
| auto &&x = (&(const with_member&)with_member{ctor()})->*&with_member::d; |
| // CHECK: call {{.*}}with_member |
| // CHECK: call {{.*}}then |
| then(); |
| // CHECK: } |
| } |
| |
| // -- a [named] cast [...] |
| // CHECK-LABEL: static_cast |
| void test_static_cast() { |
| // CHECK: call {{.*}}ctor |
| auto &&x = static_cast<dtor&&>(ctor()); |
| // CHECK: call {{.*}}then |
| then(); |
| // CHECK: call {{.*}}dtor |
| // CHECK: } |
| } |
| // CHECK-LABEL: const_cast |
| void test_const_cast() { |
| // CHECK: call {{.*}}ctor |
| auto &&x = const_cast<dtor&&>(ctor()); |
| // CHECK: call {{.*}}then |
| then(); |
| // CHECK: call {{.*}}dtor |
| // CHECK: } |
| } |
| // CHECK-LABEL: reinterpret_cast |
| void test_reinterpret_cast() { |
| // CHECK: call {{.*}}ctor |
| auto &&x = reinterpret_cast<dtor&&>(static_cast<dtor&&>(ctor())); |
| // CHECK: call {{.*}}then |
| then(); |
| // CHECK: call {{.*}}dtor |
| // CHECK: } |
| } |
| // CHECK-LABEL: dynamic_cast |
| void test_dynamic_cast() { |
| // CHECK: call {{.*}}ctor |
| auto &&x = dynamic_cast<dtor&&>(ctor()); |
| // CHECK: call {{.*}}then |
| then(); |
| // CHECK: call {{.*}}dtor |
| // CHECK: } |
| } |
| |
| // -- [explicit cast notation is defined in terms of the above] |
| // CHECK-LABEL: c_style_cast |
| void c_style_cast() { |
| // CHECK: call {{.*}}ctor |
| auto &&x = (dtor&&)ctor(); |
| // CHECK: call {{.*}}then |
| then(); |
| // CHECK: call {{.*}}dtor |
| // CHECK: } |
| } |
| // CHECK-LABEL: function_style_cast |
| void function_style_cast() { |
| // CHECK: call {{.*}}ctor |
| using R = dtor&&; |
| auto &&x = R(ctor()); |
| // CHECK: call {{.*}}then |
| then(); |
| // CHECK: call {{.*}}dtor |
| // CHECK: } |
| } |
| |
| // -- a conditional operator |
| // CHECK-LABEL: conditional |
| void conditional(bool b) { |
| // CHECK: call {{.*}}ctor |
| // CHECK: call {{.*}}ctor |
| auto &&x = b ? (dtor&&)ctor() : (dtor&&)ctor(); |
| // CHECK: call {{.*}}then |
| then(); |
| // CHECK: call {{.*}}dtor |
| // CHECK: call {{.*}}dtor |
| // CHECK: } |
| } |
| |
| // -- a comma expression |
| // CHECK-LABEL: comma |
| void comma() { |
| // CHECK: call {{.*}}ctor |
| auto &&x = (true, (dtor&&)ctor()); |
| // CHECK: call {{.*}}then |
| then(); |
| // CHECK: call {{.*}}dtor |
| // CHECK: } |
| } |
| |
| |
| // This applies recursively: if an object is lifetime-extended and contains a |
| // reference, the referent is also extended. |
| // CHECK-LABEL: init_capture_ref |
| void init_capture_ref() { |
| // CHECK: call {{.*}}ctor |
| auto x = [&a = (const dtor&)ctor()] {}; |
| // CHECK: call {{.*}}then |
| then(); |
| // CHECK: call {{.*}}dtor |
| // CHECK: } |
| } |
| // CHECK-LABEL: init_capture_ref_indirect |
| void init_capture_ref_indirect() { |
| // CHECK: call {{.*}}ctor |
| auto x = [&a = (const dtor&)ctor()] {}; |
| // CHECK: call {{.*}}then |
| then(); |
| // CHECK: call {{.*}}dtor |
| // CHECK: } |
| } |
| // CHECK-LABEL: init_capture_init_list |
| void init_capture_init_list() { |
| // CHECK: call {{.*}}ctor |
| auto x = [a = {ctor()}] {}; |
| // CHECK: call {{.*}}then |
| then(); |
| // CHECK: call {{.*}}dtor |
| // CHECK: } |
| } |
| |
| void check_dr1815() { // dr1815: yes |
| #if __cplusplus >= 201402L |
| |
| struct A { |
| int &&r = 0; |
| ~A() {} |
| }; |
| |
| struct B { |
| A &&a = A{}; |
| ~B() {} |
| }; |
| B a = {}; |
| |
| // CHECK: call {{.*}}block_scope_begin_function |
| extern void block_scope_begin_function(); |
| extern void block_scope_end_function(); |
| block_scope_begin_function(); |
| { |
| // CHECK: call void @_ZZ12check_dr1815vEN1BD1Ev |
| // CHECK: call void @_ZZ12check_dr1815vEN1AD1Ev |
| B b = {}; |
| } |
| // CHECK: call {{.*}}block_scope_end_function |
| block_scope_end_function(); |
| |
| // CHECK: call {{.*}}some_other_function |
| extern void some_other_function(); |
| some_other_function(); |
| // CHECK: call void @_ZZ12check_dr1815vEN1BD1Ev |
| // CHECK: call void @_ZZ12check_dr1815vEN1AD1Ev |
| #endif |
| } |
| |
| namespace P2718R0 { |
| namespace basic { |
| template <typename E> using T2 = std::list<E>; |
| template <typename E> const T2<E> &f1_temp(const T2<E> &t) { return t; } |
| template <typename E> const T2<E> &f2_temp(T2<E> t) { return t; } |
| template <typename E> T2<E> g_temp() { return T2<E>{}; } |
| |
| template <typename E> |
| void foo_dependent_context1() { |
| // CHECK-CXX23: void @_ZN7P2718R05basic22foo_dependent_context1IiEEvv() |
| // CHECK-CXX23: for.cond.cleanup: |
| // CHECK-CXX23-NEXT: call void @_ZNSt4listIiED1Ev( |
| for (auto e : f1_temp(g_temp<E>())) {} // OK, lifetime of return value of g() extended |
| } |
| |
| template <typename E> |
| void foo_dependent_context2() { |
| // CHECK-CXX23: void @_ZN7P2718R05basic22foo_dependent_context2IiEEvv() |
| // CHECK-CXX23-NEXT: entry: |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R05basic6g_tempIiEESt4listIT_Ev( |
| // CHECK-CXX23-NEXT: call {{.*}} @_ZN7P2718R05basic7f2_tempIiEERKSt4listIT_ES4_( |
| // CHECK-CXX23-NEXT: call void @_ZNSt4listIiED1Ev( |
| // CHECK-CXX23: call {{.*}} @_ZNKSt4listIiE5beginEv( |
| // CHECK-CXX23: call {{.*}} @_ZNKSt4listIiE3endEv( |
| for (auto e : f2_temp(g_temp<E>())) {} // undefined behavior |
| } |
| |
| template void foo_dependent_context1<int>(); |
| template void foo_dependent_context2<int>(); |
| } // namespace basic |
| |
| namespace discard_value_expression { |
| template <typename T> |
| void f_dependent_context1() { |
| std::vector<T> v = { 42, 17, 13 }; |
| std::mutex m; |
| // CHECK-CXX23: void @_ZN7P2718R024discard_value_expression20f_dependent_context1IiEEvv() |
| // CHECK-CXX23-LABEL: for.cond.cleanup: |
| // CHECK-CXX23-NEXT: call void @_ZNSt10lock_guardISt5mutexED1Ev( |
| for (T x : std::lock_guard<std::mutex>(m), v) // lock released in C++ 2023 |
| std::lock_guard<std::mutex> guard(m); // OK in C++ 2023, now deadlocks |
| } |
| |
| template <typename T> |
| void f_dependent_context2() { |
| std::vector<T> v = { 42, 17, 13 }; |
| std::mutex m; |
| // CHECK-CXX23: void @_ZN7P2718R024discard_value_expression20f_dependent_context2IiEEvv() |
| // CHECK-CXX23-LABEL: for.cond.cleanup: |
| // CHECK-CXX23-NEXT: call void @_ZNSt10lock_guardISt5mutexED1Ev( |
| for (T x : (void)std::lock_guard<std::mutex>(m), v) // lock released in C++ 2023 |
| std::lock_guard<std::mutex> guard(m); // OK in C++ 2023, now deadlocks |
| } |
| |
| template <typename T> |
| void f_dependent_context3() { |
| std::vector<T> v = { 42, 17, 13 }; |
| std::mutex m; |
| // CHECK-CXX23: void @_ZN7P2718R024discard_value_expression20f_dependent_context3IiEEvv() |
| // CHECK-CXX23-LABEL: for.cond.cleanup: |
| // CHECK-CXX23-NEXT: call void @_ZNSt10lock_guardISt5mutexED1Ev( |
| for (T x : static_cast<void>(std::lock_guard<std::mutex>(m)), v) // lock released in C++ 2023 |
| std::lock_guard<std::mutex> guard(m); // OK in C++ 2023, now deadlocks |
| } |
| |
| template void f_dependent_context1<int>(); |
| template void f_dependent_context2<int>(); |
| template void f_dependent_context3<int>(); |
| } // namespace discard_value_expression |
| |
| namespace member_call { |
| template <typename T> |
| struct ListWrapper { |
| std::list<T> list; |
| ListWrapper() {} |
| ~ListWrapper() {} |
| const T *begin() const { return list.begin(); } |
| const T *end() const { return list.end(); } |
| ListWrapper& r() { return *this; } |
| ListWrapper g() { return ListWrapper(); } |
| }; |
| |
| template <typename E> |
| ListWrapper<E> g_temp() { return ListWrapper<E>{}; } |
| |
| template <typename T> |
| void member_call_dependent_context() { |
| // CHECK-CXX23: void @_ZN7P2718R011member_call29member_call_dependent_contextIiEEvv() |
| // CHECK-CXX23-LABEL: for.cond.cleanup: |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R011member_call11ListWrapperIiED1Ev( |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R011member_call11ListWrapperIiED1Ev( |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R011member_call11ListWrapperIiED1Ev( |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R011member_call11ListWrapperIiED1Ev( |
| for (auto e : g_temp<T>().r().g().r().g().r().g()) {} |
| } |
| |
| template void member_call_dependent_context<int>(); |
| } // namespace member_call |
| |
| namespace default_arg { |
| template <typename T> |
| struct DefaultArg { |
| DefaultArg() {} |
| DefaultArg(int) {} |
| ~DefaultArg() {} |
| }; |
| |
| template <typename T> |
| struct C2 : public std::list<T> { |
| C2() {} |
| C2(int, const C2 &, const DefaultArg<T> &Default = DefaultArg<T>{}) {} |
| }; |
| |
| template <typename T> |
| std::list<T> temp_foo(const std::list<T>&, const DefaultArg<T> &Default = DefaultArg<T>{}) { |
| return std::list<T>{}; |
| } |
| |
| template <typename T> |
| void default_arg_dependent_context1() { |
| // CHECK-CXX23: void @_ZN7P2718R011default_arg30default_arg_dependent_context1IiEEvv() |
| // CHECK-CXX23-LABEL: for.cond.cleanup: |
| // CHECK-CXX23-NEXT: call void @_ZNSt4listIiED1Ev( |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R011default_arg10DefaultArgIiED1Ev( |
| // CHECK-CXX23-NEXT: call void @_ZNSt4listIiED1Ev( |
| for (auto e : temp_foo(std::list<T>{})) {} |
| } |
| |
| template <typename T> |
| void default_arg_dependent_context2() { |
| // CHECK-CXX23: void @_ZN7P2718R011default_arg30default_arg_dependent_context2IiEEvv() |
| // CHECK-CXX23-LABEL: for.cond.cleanup: |
| // CHECK-CXX23-NEXT: call void @_ZNSt4listIiED1Ev( |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R011default_arg10DefaultArgIiED1Ev( |
| // CHECK-CXX23-NEXT: call void @_ZNSt4listIiED1Ev( |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R011default_arg10DefaultArgIiED1Ev( |
| // CHECK-CXX23-NEXT: call void @_ZNSt4listIiED1Ev( |
| for (auto e : temp_foo(temp_foo(std::list<T>{}))) {} |
| } |
| |
| template <typename T> |
| void default_arg_dependent_context3() { |
| // CHECK-CXX23: void @_ZN7P2718R011default_arg30default_arg_dependent_context3IiEEvv() |
| // CHECK-CXX23-LABEL: for.cond.cleanup: |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R011default_arg2C2IiED1Ev( |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R011default_arg10DefaultArgIiED1Ev( |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R011default_arg2C2IiED1Ev( |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R011default_arg10DefaultArgIiED1Ev( |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R011default_arg2C2IiED1Ev( |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R011default_arg10DefaultArgIiED1Ev( |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R011default_arg2C2IiED1Ev( |
| |
| for (auto e : C2<T>(0, C2<T>(0, C2<T>(0, C2<T>())))) {} |
| } |
| |
| template void default_arg_dependent_context1<int>(); |
| template void default_arg_dependent_context2<int>(); |
| template void default_arg_dependent_context3<int>(); |
| } // namespace default_arg |
| |
| namespace default_init { |
| template <class T> |
| struct DepA { |
| T arr[1]; |
| ~DepA() {} |
| }; |
| |
| template <class T> |
| struct DepB { |
| int x; |
| const DepA<T> &a = DepA<T>{{0}}; |
| ~DepB() {} |
| const int *begin() { return a.arr; } |
| const int *end() { return &a.arr[1]; } |
| }; |
| |
| template <typename T> |
| void default_init1_dependent() { |
| // CHECK-CXX23: void @_ZN7P2718R012default_init23default_init1_dependentINS0_4DepBIiEEEEvv() |
| // CHECK-CXX23-LABEL: for.cond.cleanup: |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R012default_init4DepBIiED1Ev( |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R012default_init4DepAIiED1Ev( |
| for (auto &&x : T{0}) {} |
| } |
| |
| template <typename T> |
| void default_init2_dependent() { |
| // CHECK-CXX23: void @_ZN7P2718R012default_init23default_init2_dependentINS0_4DepBIiEEEEvv() |
| // CHECK-CXX23-LABEL: for.cond.cleanup: |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R012default_init4DepBIiED1Ev( |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R012default_init4DepAIiED1Ev( |
| for (auto &&x : T{0}.a.arr) {} |
| } |
| |
| template void default_init1_dependent<DepB<int>>(); |
| template void default_init2_dependent<DepB<int>>(); |
| } // namespace default_init |
| |
| // -- Examples from https://wg21.link/p2718r0 |
| extern void block_scope_begin_function(); |
| extern void block_scope_end_function(); |
| namespace std_examples { |
| using T = std::list<int>; |
| const T& f1(const T& t) { return t; } |
| const T& f2(T t) { return t; } |
| T g(); |
| void foo() { |
| // CHECK-CXX23: define {{.*}} void @_ZN7P2718R012std_examples3fooEv() |
| // CHECK-CXX23: call void @_ZN7P2718R026block_scope_begin_functionEv |
| block_scope_begin_function(); |
| { |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R012std_examples1gEv |
| // CHECK-CXX23-NEXT: call {{.*}} @_ZN7P2718R012std_examples2f1ERKSt4listIiE |
| // CHECK-CXX23: for.cond.cleanup: |
| // CHECK-CXX23-NEXT: call void @_ZNSt4listIiED1Ev |
| for (auto e : f1(g())) {} // OK, lifetime of return value of g() extended |
| } |
| // CHECK-CXX23: call void @_ZN7P2718R024block_scope_end_functionEv |
| block_scope_end_function(); |
| |
| // The lifetime of temporary returned by g() in this case will not be extended. |
| // CHECK-CXX23: call void @_ZN7P2718R026block_scope_begin_functionEv |
| block_scope_begin_function(); |
| { |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R012std_examples1gEv |
| // CHECK-CXX23-NEXT: call {{.*}} @_ZN7P2718R012std_examples2f2ESt4listIiE |
| // CHECK-CXX23-NEXT: call void @_ZNSt4listIiED1Ev |
| for (auto e : f2(g())) {} // undefined behavior |
| } |
| // CHECK-CXX23: call void @_ZN7P2718R024block_scope_end_functionEv |
| block_scope_end_function(); |
| } |
| } // namespace std_examples |
| |
| namespace basic { |
| using T = std::list<int>; |
| const T& f1(const T& t) { return t; } |
| const T& f2(T t) { return t; } |
| T g() { return T{}; } |
| |
| void foo1() { |
| // CHECK-CXX23: void @_ZN7P2718R05basic4foo1Ev() |
| // CHECK-CXX23: for.cond.cleanup: |
| // CHECK-CXX23-NEXT: call void @_ZNSt4listIiED1Ev( |
| for (auto e : f1(g())) {} // OK, lifetime of return value of g() extended |
| } |
| |
| void foo2() { |
| // CHECK-CXX23: void @_ZN7P2718R05basic4foo2Ev() |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R05basic1gEv( |
| // CHECK-CXX23-NEXT: call {{.*}} @_ZN7P2718R05basic2f2ESt4listIiE( |
| // CHECK-CXX23-NEXT: call void @_ZNSt4listIiED1Ev( |
| for (auto e : f2(g())) {} // undefined behavior |
| } |
| } // namespace basic |
| |
| namespace discard_value_expression { |
| void f1() { |
| std::vector<int> v = { 42, 17, 13 }; |
| std::mutex m; |
| // CHECK-CXX23: void @_ZN7P2718R024discard_value_expression2f1Ev() |
| // CHECK-CXX23-LABEL: for.cond.cleanup: |
| // CHECK-CXX23-NEXT: call void @_ZNSt10lock_guardISt5mutexED1Ev( |
| for (int x : std::lock_guard<std::mutex>(m), v) // lock released in C++ 2023 |
| std::lock_guard<std::mutex> guard(m); // OK in C++ 2023, now deadlocks |
| } |
| |
| void f2() { |
| std::vector<int> v = { 42, 17, 13 }; |
| std::mutex m; |
| // CHECK-CXX23: void @_ZN7P2718R024discard_value_expression2f2Ev() |
| // CHECK-CXX23-LABEL: for.cond.cleanup: |
| // CHECK-CXX23-NEXT: call void @_ZNSt10lock_guardISt5mutexED1Ev( |
| for (int x : (void)std::lock_guard<std::mutex>(m), v) // lock released in C++ 2023 |
| std::lock_guard<std::mutex> guard(m); // OK in C++ 2023, now deadlocks |
| } |
| |
| void f3() { |
| std::vector<int> v = { 42, 17, 13 }; |
| std::mutex m; |
| // CHECK-CXX23: void @_ZN7P2718R024discard_value_expression2f3Ev() |
| // CHECK-CXX23-LABEL: for.cond.cleanup: |
| // CHECK-CXX23-NEXT: call void @_ZNSt10lock_guardISt5mutexED1Ev( |
| for (int x : static_cast<void>(std::lock_guard<std::mutex>(m)), v) // lock released in C++ 2023 |
| std::lock_guard<std::mutex> guard(m); // OK in C++ 2023, now deadlocks |
| } |
| } // namespace discard_value_expression |
| |
| namespace member_call { |
| using A = ListWrapper<int>; |
| |
| A g() { return A(); } |
| const A &f1(const A &t) { return t; } |
| |
| void member_call() { |
| // CHECK-CXX23: void @_ZN7P2718R011member_call11member_callEv() |
| // CHECK-CXX23-LABEL: for.cond.cleanup: |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R011member_call11ListWrapperIiED1Ev( |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R011member_call11ListWrapperIiED1Ev( |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R011member_call11ListWrapperIiED1Ev( |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R011member_call11ListWrapperIiED1Ev( |
| for (auto e : g().r().g().r().g().r().g()) {} |
| } |
| } // namespace member_call |
| |
| namespace default_arg { |
| using A = std::list<int>; |
| using DefaultA = DefaultArg<int>; |
| struct C : public A { |
| C() {} |
| C(int, const C &, const DefaultA & = DefaultA()) {} |
| }; |
| |
| A foo(const A&, const DefaultA &Default = DefaultA()) { |
| return A(); |
| } |
| |
| int (&some_func(const A & = A{}))[3]; |
| |
| void default_arg1() { |
| // CHECK-CXX23: void @_ZN7P2718R011default_arg12default_arg1Ev() |
| // CHECK-CXX23-LABEL: for.cond.cleanup: |
| // CHECK-CXX23-NEXT: call void @_ZNSt4listIiED1Ev( |
| for (auto e : some_func()) {} |
| } |
| |
| void default_arg2() { |
| // CHECK-CXX23: void @_ZN7P2718R011default_arg12default_arg2Ev() |
| // CHECK-CXX23-LABEL: for.cond.cleanup: |
| // CHECK-CXX23-NEXT: call void @_ZNSt4listIiED1Ev( |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R011default_arg10DefaultArgIiED1Ev( |
| // CHECK-CXX23-NEXT: call void @_ZNSt4listIiED1Ev( |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R011default_arg10DefaultArgIiED1Ev( |
| // CHECK-CXX23-NEXT: call void @_ZNSt4listIiED1Ev( |
| for (auto e : some_func(foo(foo(A())))) {} |
| } |
| |
| void default_arg3() { |
| // CHECK-CXX23: void @_ZN7P2718R011default_arg12default_arg3Ev() |
| // CHECK-CXX23-LABEL: for.cond.cleanup: |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R011default_arg1CD1Ev( |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R011default_arg10DefaultArgIiED1Ev( |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R011default_arg1CD1Ev( |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R011default_arg10DefaultArgIiED1Ev( |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R011default_arg1CD1Ev( |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R011default_arg10DefaultArgIiED1Ev( |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R011default_arg1CD1Ev( |
| for (auto e : C(0, C(0, C(0, C())))) {} |
| } |
| } // namespace default_arg |
| |
| namespace default_init { |
| struct X { |
| int x; |
| ~X() {} |
| }; |
| |
| struct Y { |
| int y; |
| const X &x = X{1}; |
| ~Y() {} |
| }; |
| |
| struct A { |
| int arr[1]; |
| const Y &y = Y{1}; |
| ~A() {} |
| }; |
| |
| struct B { |
| int x; |
| const A &a = A{{0}}; |
| ~B() {} |
| const int *begin() { return a.arr; } |
| const int *end() { return &a.arr[1]; } |
| }; |
| |
| void default_init1() { |
| // CHECK-CXX23: void @_ZN7P2718R012default_init13default_init1Ev() |
| // CHECK-CXX23-LABEL: for.cond.cleanup: |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R012default_init1BD1Ev( |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R012default_init1AD1Ev( |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R012default_init1YD1Ev( |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R012default_init1XD1Ev( |
| for (auto &&x : B{0}) {} |
| } |
| |
| void default_init2() { |
| // CHECK-CXX23: void @_ZN7P2718R012default_init13default_init2Ev() |
| // CHECK-CXX23-LABEL: for.cond.cleanup: |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R012default_init1BD1Ev( |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R012default_init1AD1Ev( |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R012default_init1YD1Ev( |
| // CHECK-CXX23-NEXT: call void @_ZN7P2718R012default_init1XD1Ev( |
| for (auto &&x : B{0}.a.arr) {} |
| } |
| } // namespace default_init |
| } // namespace P2718R0 |