// 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 }