CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
738 lines
22 KiB
C++
738 lines
22 KiB
C++
// 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 GH165182 {
|
|
extern "C" int printf(const char *, ...);
|
|
|
|
const char* s = "1";
|
|
|
|
struct Foo {
|
|
int& x;
|
|
Foo(int& x) noexcept : x{x} {}
|
|
~Foo() noexcept { x = 42; }
|
|
const char* begin() const noexcept { return s; }
|
|
const char* end() const noexcept { return s + 1; }
|
|
};
|
|
|
|
const Foo& f1(const Foo& t) noexcept { return t; }
|
|
Foo g(int& x) noexcept { return Foo(x); }
|
|
|
|
// Lifetime extension is missing!
|
|
template <typename T>
|
|
int test1() {
|
|
int x = 5;
|
|
int sum = 0;
|
|
// CHECK-CXX23: for.cond.cleanup:
|
|
// CHECK-CXX23-NEXT: call void @_ZN7P2718R08GH1651823FooD1Ev(
|
|
for (int _ : f1(g(x))) sum += x;
|
|
sum += x;
|
|
return sum;
|
|
}
|
|
|
|
int foo() {
|
|
printf("%i\n", test1<int>());
|
|
}
|
|
|
|
} // namespace GH165182
|
|
} // namespace P2718R0
|