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
83 lines
4.7 KiB
C
83 lines
4.7 KiB
C
// RUN: %clang_cc1 -fsyntax-only -verify=expected,c -std=c99 %s
|
|
// RUN: %clang_cc1 -fsyntax-only -verify=expected,c -std=c11 %s
|
|
// RUN: %clang_cc1 -fsyntax-only -verify=expected,cpp -std=c++11 -x c++ %s
|
|
|
|
/* WG14 N1285: Clang 21
|
|
* Extending the lifetime of temporary objects (factored approach)
|
|
*
|
|
* This paper introduced the notion of an object with a temporary lifetime. Any
|
|
* operation resulting in an rvalue of structure or union type which contains
|
|
* an array results in an object with temporary lifetime.
|
|
*
|
|
* Even though this is a change for C11, we treat it as a DR and apply it
|
|
* retroactively to earlier C language modes.
|
|
*/
|
|
|
|
// C11 6.2.4p8: A non-lvalue expression with structure or union type, where the
|
|
// structure or union contains a member with array type (including,
|
|
// recursively, members of all contained structures and unions) refers to an
|
|
// object with automatic storage duration and temporary lifetime. Its lifetime
|
|
// begins when the expression is evaluated and its initial value is the value
|
|
// of the expression. Its lifetime ends when the evaluation of the containing
|
|
// full expression or full declarator ends. Any attempt to modify an object
|
|
// with temporary lifetime results in undefined behavior.
|
|
|
|
struct X { int a[5]; };
|
|
struct X f(void);
|
|
|
|
union U { int a[10]; double d; };
|
|
union U g(void);
|
|
|
|
void sink(int *);
|
|
|
|
int func_return(void) {
|
|
int *p = f().a; // expected-warning {{temporary whose address is used as value of local variable 'p' will be destroyed at the end of the full-expression}}
|
|
p = f().a; // expected-warning {{object backing the pointer 'p' will be destroyed at the end of the full-expression}}
|
|
p = g().a; // expected-warning {{object backing the pointer 'p' will be destroyed at the end of the full-expression}}
|
|
sink(f().a); // Ok
|
|
return *f().a; // Ok
|
|
}
|
|
|
|
int ternary(void) {
|
|
int *p = (1 ? (struct X){ 0 } : f()).a; // expected-warning {{temporary whose address is used as value of local variable 'p' will be destroyed at the end of the full-expression}}
|
|
int *r = (1 ? (union U){ 0 } : g()).a; // expected-warning {{temporary whose address is used as value of local variable 'r' will be destroyed at the end of the full-expression}}
|
|
p = (1 ? (struct X){ 0 } : f()).a; // expected-warning {{object backing the pointer 'p' will be destroyed at the end of the full-expression}}
|
|
sink((1 ? (struct X){ 0 } : f()).a); // Ok
|
|
|
|
// This intentionally gets one diagnostic in C and two in C++. In C, the
|
|
// compound literal results in an lvalue, not an rvalue as it does in C++. So
|
|
// only one branch results in a temporary in C but both branches do in C++.
|
|
int *q = 1 ? (struct X){ 0 }.a : f().a; // expected-warning {{temporary whose address is used as value of local variable 'q' will be destroyed at the end of the full-expression}} \
|
|
cpp-warning {{temporary whose address is used as value of local variable 'q' will be destroyed at the end of the full-expression}}
|
|
q = 1 ? (struct X){ 0 }.a : f().a; // expected-warning {{object backing the pointer 'q' will be destroyed at the end of the full-expression}} \
|
|
cpp-warning {{object backing the pointer 'q' will be destroyed at the end of the full-expression}}
|
|
q = 1 ? (struct X){ 0 }.a : g().a; // expected-warning {{object backing the pointer 'q' will be destroyed at the end of the full-expression}} \
|
|
cpp-warning {{object backing the pointer 'q' will be destroyed at the end of the full-expression}}
|
|
sink(1 ? (struct X){ 0 }.a : f().a); // Ok
|
|
return *(1 ? (struct X){ 0 }.a : f().a); // Ok
|
|
}
|
|
|
|
int comma(void) {
|
|
struct X x;
|
|
int *p = ((void)0, x).a; // c-warning {{temporary whose address is used as value of local variable 'p' will be destroyed at the end of the full-expression}}
|
|
p = ((void)0, x).a; // c-warning {{object backing the pointer 'p' will be destroyed at the end of the full-expression}}
|
|
sink(((void)0, x).a); // Ok
|
|
return *(((void)0, x).a);// Ok
|
|
}
|
|
|
|
int cast(void) {
|
|
struct X x;
|
|
int *p = ((struct X)x).a; // expected-warning {{temporary whose address is used as value of local variable 'p' will be destroyed at the end of the full-expression}}
|
|
p = ((struct X)x).a; // expected-warning {{object backing the pointer 'p' will be destroyed at the end of the full-expression}}
|
|
sink(((struct X)x).a); // Ok
|
|
return *(((struct X)x).a); // Ok
|
|
}
|
|
|
|
int assign(void) {
|
|
struct X x, s;
|
|
int *p = (x = s).a; // c-warning {{temporary whose address is used as value of local variable 'p' will be destroyed at the end of the full-expression}}
|
|
p = (x = s).a; // c-warning {{object backing the pointer 'p' will be destroyed at the end of the full-expression}}
|
|
sink((x = s).a); // Ok
|
|
return *((x = s).a); // Ok
|
|
}
|