You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This feature largely models the same behavior as in C++11. It is
technically a breaking change between C99 and C11, so the paper is not
being backported to older language modes.
One difference between C++ and C is that things which are rvalues in C
are often lvalues in C++ (such as the result of a ternary operator or a
comma operator).
Fixes#96486
// RUN: %clang_cc1 -fsyntax-only -verify=expected,cpp -std=c++11 -x c++ %s
4
4
5
-
/* WG14 N1285: No
5
+
/* WG14 N1285: Clang 21
6
6
* Extending the lifetime of temporary objects (factored approach)
7
7
*
8
-
* NB: we do not properly materialize temporary expressions in situations where
9
-
* it would be expected; that is why the "no-diagnostics" marking is named
10
-
* "wrong". We do issue the expected diagnostic in C++ mode.
8
+
* This paper introduced the notion of an object with a temporary lifetime. Any
9
+
* operation resulting in an rvalue of structure or union type which contains
10
+
* an array results in an object with temporary lifetime.
11
+
*
12
+
* Even though this is a change for C11, we treat it as a DR and apply it
13
+
* retroactively to earlier C language modes.
11
14
*/
12
15
13
-
// wrong-no-diagnostics
16
+
// C11 6.2.4p8: A non-lvalue expression with structure or union type, where the
17
+
// structure or union contains a member with array type (including,
18
+
// recursively, members of all contained structures and unions) refers to an
19
+
// object with automatic storage duration and temporary lifetime. Its lifetime
20
+
// begins when the expression is evaluated and its initial value is the value
21
+
// of the expression. Its lifetime ends when the evaluation of the containing
22
+
// full expression or full declarator ends. Any attempt to modify an object
23
+
// with temporary lifetime results in undefined behavior.
14
24
15
25
structX { inta[5]; };
16
26
structXf(void);
17
27
18
-
intfoo(void) {
19
-
// FIXME: This diagnostic should be issued in C11 as well (though not in C99,
20
-
// as this paper was a breaking change between C99 and C11).
21
-
int*p=f().a; // cpp-warning {{temporary whose address is used as value of local variable 'p' will be destroyed at the end of the full-expression}}
22
-
return*p;
28
+
unionU { inta[10]; doubled; };
29
+
unionUg(void);
30
+
31
+
voidsink(int*);
32
+
33
+
intfunc_return(void) {
34
+
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}}
35
+
p=f().a; // expected-warning {{object backing the pointer p will be destroyed at the end of the full-expression}}
36
+
p=g().a; // expected-warning {{object backing the pointer p will be destroyed at the end of the full-expression}}
37
+
sink(f().a); // Ok
38
+
return*f().a; // Ok
39
+
}
40
+
41
+
intternary(void) {
42
+
int*p= (1 ? (structX){ 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}}
43
+
int*r= (1 ? (unionU){ 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}}
44
+
p= (1 ? (structX){ 0 } : f()).a; // expected-warning {{object backing the pointer p will be destroyed at the end of the full-expression}}
45
+
sink((1 ? (structX){ 0 } : f()).a); // Ok
46
+
47
+
// This intentionally gets one diagnostic in C and two in C++. In C, the
48
+
// compound literal results in an lvalue, not an rvalue as it does in C++. So
49
+
// only one branch results in a temporary in C but both branches do in C++.
50
+
int*q=1 ? (structX){ 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}} \
51
+
cpp-warning {{temporary whose address is used as value of local variable 'q' will be destroyed at the end of the full-expression}}
52
+
q=1 ? (structX){ 0 }.a : f().a; // expected-warning {{object backing the pointer q will be destroyed at the end of the full-expression}} \
53
+
cpp-warning {{object backing the pointer q will be destroyed at the end of the full-expression}}
54
+
q=1 ? (structX){ 0 }.a : g().a; // expected-warning {{object backing the pointer q will be destroyed at the end of the full-expression}} \
55
+
cpp-warning {{object backing the pointer q will be destroyed at the end of the full-expression}}
56
+
sink(1 ? (structX){ 0 }.a : f().a); // Ok
57
+
return*(1 ? (structX){ 0 }.a : f().a); // Ok
23
58
}
24
59
60
+
intcomma(void) {
61
+
structXx;
62
+
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}}
63
+
p= ((void)0, x).a; // c-warning {{object backing the pointer p will be destroyed at the end of the full-expression}}
64
+
sink(((void)0, x).a); // Ok
65
+
return*(((void)0, x).a);// Ok
66
+
}
67
+
68
+
intcast(void) {
69
+
structXx;
70
+
int*p= ((structX)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}}
71
+
p= ((structX)x).a; // expected-warning {{object backing the pointer p will be destroyed at the end of the full-expression}}
72
+
sink(((structX)x).a); // Ok
73
+
return*(((structX)x).a); // Ok
74
+
}
75
+
76
+
intassign(void) {
77
+
structXx, s;
78
+
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}}
79
+
p= (x=s).a; // c-warning {{object backing the pointer p will be destroyed at the end of the full-expression}}
0 commit comments