annotate gcc/d/dmd/escape.c @ 158:494b0b89df80 default tip

...
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 18:13:55 +0900
parents 1830386684a0
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
145
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2 /* Compiler implementation of the D programming language
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3 * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4 * written by Walter Bright
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
5 * http://www.digitalmars.com
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
6 * Distributed under the Boost Software License, Version 1.0.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
7 * http://www.boost.org/LICENSE_1_0.txt
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
8 * https://github.com/D-Programming-Language/dmd/blob/master/src/escape.c
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
9 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
10
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
11 #include "mars.h"
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
12 #include "init.h"
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
13 #include "expression.h"
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
14 #include "scope.h"
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
15 #include "aggregate.h"
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
16 #include "declaration.h"
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
17 #include "module.h"
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
18
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
19 /************************************
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
20 * Aggregate the data collected by the escapeBy??() functions.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
21 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
22 struct EscapeByResults
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
23 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
24 VarDeclarations byref; // array into which variables being returned by ref are inserted
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
25 VarDeclarations byvalue; // array into which variables with values containing pointers are inserted
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
26 FuncDeclarations byfunc; // nested functions that are turned into delegates
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
27 Expressions byexp; // array into which temporaries being returned by ref are inserted
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
28 };
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
29
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
30 static bool checkReturnEscapeImpl(Scope *sc, Expression *e, bool refs, bool gag);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
31 static void inferReturn(FuncDeclaration *fd, VarDeclaration *v);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
32 static void escapeByValue(Expression *e, EscapeByResults *er);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
33 static void escapeByRef(Expression *e, EscapeByResults *er);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
34 static void findAllOuterAccessedVariables(FuncDeclaration *fd, VarDeclarations *vars);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
35
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
36 /* 'v' is assigned unsafely to 'par'
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
37 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
38 static void unsafeAssign(Scope *sc, FuncDeclaration *fdc, Identifier *par, Expression *arg, bool gag,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
39 bool &result, VarDeclaration *v, const char *desc)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
40 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
41 if (global.params.vsafe && sc->func->setUnsafe())
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
42 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
43 if (!gag)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
44 error(arg->loc, "%s %s assigned to non-scope parameter %s calling %s",
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
45 desc, v->toChars(),
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
46 par ? par->toChars() : "unnamed",
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
47 fdc ? fdc->toPrettyChars() : "indirectly");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
48 result = true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
49 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
50 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
51
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
52 /****************************************
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
53 * Function parameter par is being initialized to arg,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
54 * and par may escape.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
55 * Detect if scoped values can escape this way.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
56 * Print error messages when these are detected.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
57 * Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
58 * sc = used to determine current function and module
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
59 * par = identifier of function parameter
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
60 * arg = initializer for param
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
61 * gag = do not print error messages
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
62 * Returns:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
63 * true if pointers to the stack can escape via assignment
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
64 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
65 bool checkParamArgumentEscape(Scope *sc, FuncDeclaration *fdc, Identifier *par, Expression *arg, bool gag)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
66 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
67 //printf("checkParamArgumentEscape(arg: %s par: %s)\n", arg->toChars(), par->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
68 //printf("type = %s, %d\n", arg->type->toChars(), arg->type->hasPointers());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
69
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
70 if (!arg->type->hasPointers())
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
71 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
72
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
73 EscapeByResults er;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
74
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
75 escapeByValue(arg, &er);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
76
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
77 if (!er.byref.dim && !er.byvalue.dim && !er.byfunc.dim && !er.byexp.dim)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
78 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
79
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
80 bool result = false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
81
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
82 for (size_t i = 0; i < er.byvalue.dim; i++)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
83 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
84 //printf("byvalue %s\n", v->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
85 VarDeclaration *v = er.byvalue[i];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
86 if (v->isDataseg())
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
87 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
88
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
89 Dsymbol *p = v->toParent2();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
90
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
91 v->storage_class &= ~STCmaybescope;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
92
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
93 if (v->isScope())
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
94 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
95 unsafeAssign(sc, fdc, par, arg, gag, result, v, "scope variable");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
96 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
97 else if (v->storage_class & STCvariadic && p == sc->func)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
98 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
99 Type *tb = v->type->toBasetype();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
100 if (tb->ty == Tarray || tb->ty == Tsarray)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
101 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
102 unsafeAssign(sc, fdc, par, arg, gag, result, v, "variadic variable");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
103 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
104 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
105 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
106 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
107 /* v is not 'scope', and is assigned to a parameter that may escape.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
108 * Therefore, v can never be 'scope'.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
109 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
110 v->doNotInferScope = true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
111 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
112 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
113
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
114 for (size_t i = 0; i < er.byref.dim; i++)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
115 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
116 VarDeclaration *v = er.byref[i];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
117 if (v->isDataseg())
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
118 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
119
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
120 Dsymbol *p = v->toParent2();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
121
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
122 v->storage_class &= ~STCmaybescope;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
123
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
124 if ((v->storage_class & (STCref | STCout)) == 0 && p == sc->func)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
125 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
126 unsafeAssign(sc, fdc, par, arg, gag, result, v, "reference to local variable");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
127 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
128 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
129 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
130
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
131 for (size_t i = 0; i < er.byfunc.dim; i++)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
132 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
133 FuncDeclaration *fd = er.byfunc[i];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
134 //printf("fd = %s, %d\n", fd->toChars(), fd->tookAddressOf);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
135 VarDeclarations vars;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
136 findAllOuterAccessedVariables(fd, &vars);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
137
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
138 for (size_t j = 0; j < vars.dim; j++)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
139 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
140 VarDeclaration *v = vars[j];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
141 //printf("v = %s\n", v->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
142 assert(!v->isDataseg()); // these are not put in the closureVars[]
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
143
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
144 Dsymbol *p = v->toParent2();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
145
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
146 v->storage_class &= ~STCmaybescope;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
147
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
148 if ((v->storage_class & (STCref | STCout | STCscope)) && p == sc->func)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
149 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
150 unsafeAssign(sc, fdc, par, arg, gag, result, v, "reference to local");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
151 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
152 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
153 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
154 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
155
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
156 for (size_t i = 0; i < er.byexp.dim; i++)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
157 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
158 Expression *ee = er.byexp[i];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
159 if (sc->func->setUnsafe())
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
160 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
161 if (!gag)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
162 error(ee->loc, "reference to stack allocated value returned by %s assigned to non-scope parameter %s",
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
163 ee->toChars(),
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
164 par ? par->toChars() : "unnamed");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
165 result = true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
166 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
167 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
168
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
169 return result;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
170 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
171
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
172 /****************************************
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
173 * Given an AssignExp, determine if the lvalue will cause
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
174 * the contents of the rvalue to escape.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
175 * Print error messages when these are detected.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
176 * Infer 'scope' for the lvalue where possible, in order
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
177 * to eliminate the error.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
178 * Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
179 * sc = used to determine current function and module
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
180 * ae = AssignExp to check for any pointers to the stack
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
181 * gag = do not print error messages
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
182 * Returns:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
183 * true if pointers to the stack can escape via assignment
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
184 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
185 bool checkAssignEscape(Scope *sc, Expression *e, bool gag)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
186 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
187 //printf("checkAssignEscape(e: %s)\n", e->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
188 if (e->op != TOKassign && e->op != TOKblit && e->op != TOKconstruct)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
189 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
190 AssignExp *ae = (AssignExp *)e;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
191 Expression *e1 = ae->e1;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
192 Expression *e2 = ae->e2;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
193 //printf("type = %s, %d\n", e1->type->toChars(), e1->type->hasPointers());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
194
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
195 if (!e1->type->hasPointers())
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
196 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
197
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
198 if (e1->op == TOKslice)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
199 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
200
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
201 EscapeByResults er;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
202
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
203 escapeByValue(e2, &er);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
204
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
205 if (!er.byref.dim && !er.byvalue.dim && !er.byfunc.dim && !er.byexp.dim)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
206 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
207
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
208 VarDeclaration *va = NULL;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
209 while (e1->op == TOKdotvar)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
210 e1 = ((DotVarExp *)e1)->e1;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
211
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
212 if (e1->op == TOKvar)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
213 va = ((VarExp *)e1)->var->isVarDeclaration();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
214 else if (e1->op == TOKthis)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
215 va = ((ThisExp *)e1)->var->isVarDeclaration();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
216 else if (e1->op == TOKindex)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
217 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
218 IndexExp *ie = (IndexExp *)e1;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
219 if (ie->e1->op == TOKvar && ie->e1->type->toBasetype()->ty == Tsarray)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
220 va = ((VarExp *)ie->e1)->var->isVarDeclaration();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
221 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
222
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
223 // Try to infer 'scope' for va if in a function not marked @system
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
224 bool inferScope = false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
225 if (va && sc->func && sc->func->type && sc->func->type->ty == Tfunction)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
226 inferScope = ((TypeFunction *)sc->func->type)->trust != TRUSTsystem;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
227
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
228 bool result = false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
229 for (size_t i = 0; i < er.byvalue.dim; i++)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
230 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
231 VarDeclaration *v = er.byvalue[i];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
232 //printf("byvalue: %s\n", v->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
233 if (v->isDataseg())
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
234 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
235
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
236 Dsymbol *p = v->toParent2();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
237
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
238 if (!(va && va->isScope()))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
239 v->storage_class &= ~STCmaybescope;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
240
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
241 if (v->isScope())
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
242 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
243 if (va && va->isScope() && va->storage_class & STCreturn && !(v->storage_class & STCreturn) &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
244 sc->func->setUnsafe())
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
245 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
246 if (!gag)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
247 error(ae->loc, "scope variable %s assigned to return scope %s", v->toChars(), va->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
248 result = true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
249 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
250 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
251
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
252 // If va's lifetime encloses v's, then error
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
253 if (va &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
254 ((va->enclosesLifetimeOf(v) && !(v->storage_class & STCparameter)) ||
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
255 // va is class reference
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
256 (ae->e1->op == TOKdotvar && va->type->toBasetype()->ty == Tclass && (va->enclosesLifetimeOf(v) || !va->isScope())) ||
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
257 va->storage_class & STCref) &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
258 sc->func->setUnsafe())
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
259 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
260 if (!gag)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
261 error(ae->loc, "scope variable %s assigned to %s with longer lifetime", v->toChars(), va->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
262 result = true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
263 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
264 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
265
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
266 if (va && !va->isDataseg() && !va->doNotInferScope)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
267 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
268 if (!va->isScope() && inferScope)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
269 { //printf("inferring scope for %s\n", va->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
270 va->storage_class |= STCscope | STCscopeinferred;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
271 va->storage_class |= v->storage_class & STCreturn;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
272 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
273 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
274 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
275 if (sc->func->setUnsafe())
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
276 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
277 if (!gag)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
278 error(ae->loc, "scope variable %s assigned to non-scope %s", v->toChars(), e1->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
279 result = true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
280 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
281 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
282 else if (v->storage_class & STCvariadic && p == sc->func)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
283 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
284 Type *tb = v->type->toBasetype();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
285 if (tb->ty == Tarray || tb->ty == Tsarray)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
286 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
287 if (va && !va->isDataseg() && !va->doNotInferScope)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
288 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
289 if (!va->isScope() && inferScope)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
290 { //printf("inferring scope for %s\n", va->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
291 va->storage_class |= STCscope | STCscopeinferred;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
292 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
293 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
294 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
295 if (sc->func->setUnsafe())
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
296 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
297 if (!gag)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
298 error(ae->loc, "variadic variable %s assigned to non-scope %s", v->toChars(), e1->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
299 result = true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
300 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
301 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
302 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
303 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
304 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
305 /* v is not 'scope', and we didn't check the scope of where we assigned it to.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
306 * It may escape via that assignment, therefore, v can never be 'scope'.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
307 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
308 v->doNotInferScope = true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
309 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
310 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
311
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
312 for (size_t i = 0; i < er.byref.dim; i++)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
313 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
314 VarDeclaration *v = er.byref[i];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
315 //printf("byref: %s\n", v->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
316 if (v->isDataseg())
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
317 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
318
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
319 Dsymbol *p = v->toParent2();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
320
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
321 // If va's lifetime encloses v's, then error
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
322 if (va &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
323 ((va->enclosesLifetimeOf(v) && !(v->storage_class & STCparameter)) || va->storage_class & STCref) &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
324 sc->func->setUnsafe())
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
325 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
326 if (!gag)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
327 error(ae->loc, "address of variable %s assigned to %s with longer lifetime", v->toChars(), va->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
328 result = true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
329 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
330 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
331
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
332 if (!(va && va->isScope()))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
333 v->storage_class &= ~STCmaybescope;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
334
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
335 if ((v->storage_class & (STCref | STCout)) == 0 && p == sc->func)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
336 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
337 if (va && !va->isDataseg() && !va->doNotInferScope)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
338 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
339 if (!va->isScope() && inferScope)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
340 { //printf("inferring scope for %s\n", va->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
341 va->storage_class |= STCscope | STCscopeinferred;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
342 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
343 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
344 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
345 if (sc->func->setUnsafe())
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
346 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
347 if (!gag)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
348 error(ae->loc, "reference to local variable %s assigned to non-scope %s", v->toChars(), e1->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
349 result = true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
350 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
351 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
352 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
353 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
354
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
355 for (size_t i = 0; i < er.byfunc.dim; i++)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
356 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
357 FuncDeclaration *fd = er.byfunc[i];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
358 //printf("fd = %s, %d\n", fd->toChars(), fd->tookAddressOf);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
359 VarDeclarations vars;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
360 findAllOuterAccessedVariables(fd, &vars);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
361
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
362 for (size_t j = 0; j < vars.dim; j++)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
363 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
364 VarDeclaration *v = vars[j];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
365 //printf("v = %s\n", v->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
366 assert(!v->isDataseg()); // these are not put in the closureVars[]
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
367
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
368 Dsymbol *p = v->toParent2();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
369
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
370 if (!(va && va->isScope()))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
371 v->storage_class &= ~STCmaybescope;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
372
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
373 if ((v->storage_class & (STCref | STCout | STCscope)) && p == sc->func)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
374 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
375 if (va && !va->isDataseg() && !va->doNotInferScope)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
376 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
377 /* Don't infer STCscope for va, because then a closure
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
378 * won't be generated for sc->func.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
379 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
380 //if (!va->isScope() && inferScope)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
381 //va->storage_class |= STCscope | STCscopeinferred;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
382 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
383 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
384 if (sc->func->setUnsafe())
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
385 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
386 if (!gag)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
387 error(ae->loc, "reference to local %s assigned to non-scope %s in @safe code", v->toChars(), e1->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
388 result = true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
389 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
390 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
391 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
392 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
393 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
394
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
395 for (size_t i = 0; i < er.byexp.dim; i++)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
396 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
397 Expression *ee = er.byexp[i];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
398 if (va && !va->isDataseg() && !va->doNotInferScope)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
399 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
400 if (!va->isScope() && inferScope)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
401 { //printf("inferring scope for %s\n", va->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
402 va->storage_class |= STCscope | STCscopeinferred;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
403 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
404 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
405 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
406 if (sc->func->setUnsafe())
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
407 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
408 if (!gag)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
409 error(ee->loc, "reference to stack allocated value returned by %s assigned to non-scope %s",
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
410 ee->toChars(), e1->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
411 result = true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
412 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
413 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
414
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
415 return result;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
416 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
417
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
418 /************************************
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
419 * Detect cases where pointers to the stack can 'escape' the
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
420 * lifetime of the stack frame when throwing `e`.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
421 * Print error messages when these are detected.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
422 * Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
423 * sc = used to determine current function and module
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
424 * e = expression to check for any pointers to the stack
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
425 * gag = do not print error messages
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
426 * Returns:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
427 * true if pointers to the stack can escape
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
428 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
429 bool checkThrowEscape(Scope *sc, Expression *e, bool gag)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
430 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
431 //printf("[%s] checkThrowEscape, e = %s\n", e->loc->toChars(), e->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
432 EscapeByResults er;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
433
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
434 escapeByValue(e, &er);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
435
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
436 if (!er.byref.dim && !er.byvalue.dim && !er.byexp.dim)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
437 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
438
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
439 bool result = false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
440 for (size_t i = 0; i < er.byvalue.dim; i++)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
441 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
442 VarDeclaration *v = er.byvalue[i];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
443 //printf("byvalue %s\n", v->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
444 if (v->isDataseg())
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
445 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
446
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
447 if (v->isScope())
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
448 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
449 if (sc->_module && sc->_module->isRoot())
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
450 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
451 // Only look for errors if in module listed on command line
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
452 if (global.params.vsafe) // https://issues.dlang.org/show_bug.cgi?id=17029
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
453 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
454 if (!gag)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
455 error(e->loc, "scope variable %s may not be thrown", v->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
456 result = true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
457 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
458 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
459 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
460 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
461 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
462 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
463 //printf("no infer for %s\n", v->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
464 v->doNotInferScope = true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
465 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
466 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
467 return result;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
468 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
469
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
470 /************************************
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
471 * Detect cases where pointers to the stack can 'escape' the
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
472 * lifetime of the stack frame by returning 'e' by value.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
473 * Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
474 * sc = used to determine current function and module
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
475 * e = expression to check for any pointers to the stack
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
476 * gag = do not print error messages
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
477 * Returns:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
478 * true if pointers to the stack can escape
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
479 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
480
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
481 bool checkReturnEscape(Scope *sc, Expression *e, bool gag)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
482 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
483 //printf("[%s] checkReturnEscape, e = %s\n", e->loc->toChars(), e->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
484 return checkReturnEscapeImpl(sc, e, false, gag);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
485 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
486
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
487 /************************************
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
488 * Detect cases where returning 'e' by ref can result in a reference to the stack
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
489 * being returned.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
490 * Print error messages when these are detected.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
491 * Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
492 * sc = used to determine current function and module
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
493 * e = expression to check
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
494 * gag = do not print error messages
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
495 * Returns:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
496 * true if references to the stack can escape
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
497 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
498 bool checkReturnEscapeRef(Scope *sc, Expression *e, bool gag)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
499 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
500 //printf("[%s] checkReturnEscapeRef, e = %s\n", e->loc.toChars(), e->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
501 //printf("current function %s\n", sc->func->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
502 //printf("parent2 function %s\n", sc->func->toParent2()->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
503
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
504 return checkReturnEscapeImpl(sc, e, true, gag);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
505 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
506
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
507 static void escapingRef(VarDeclaration *v, Expression *e, bool &result, bool gag)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
508 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
509 if (!gag)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
510 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
511 const char *msg;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
512 if (v->storage_class & STCparameter)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
513 msg = "returning `%s` escapes a reference to parameter `%s`, perhaps annotate with `return`";
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
514 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
515 msg = "returning `%s` escapes a reference to local variable `%s`";
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
516 error(e->loc, msg, e->toChars(), v->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
517 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
518 result = true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
519 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
520
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
521 static bool checkReturnEscapeImpl(Scope *sc, Expression *e, bool refs, bool gag)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
522 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
523 //printf("[%s] checkReturnEscapeImpl, e = %s\n", e->loc->toChars(), e->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
524 EscapeByResults er;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
525
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
526 if (refs)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
527 escapeByRef(e, &er);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
528 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
529 escapeByValue(e, &er);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
530
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
531 if (!er.byref.dim && !er.byvalue.dim && !er.byexp.dim)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
532 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
533
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
534 bool result = false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
535 for (size_t i = 0; i < er.byvalue.dim; i++)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
536 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
537 VarDeclaration *v = er.byvalue[i];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
538 //printf("byvalue %s\n", v->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
539 if (v->isDataseg())
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
540 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
541
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
542 Dsymbol *p = v->toParent2();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
543
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
544 if ((v->isScope() || (v->storage_class & STCmaybescope)) &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
545 !(v->storage_class & STCreturn) &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
546 v->isParameter() &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
547 sc->func->flags & FUNCFLAGreturnInprocess &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
548 p == sc->func)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
549 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
550 inferReturn(sc->func, v); // infer addition of 'return'
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
551 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
552 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
553
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
554 if (v->isScope())
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
555 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
556 if (v->storage_class & STCreturn)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
557 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
558
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
559 if (sc->_module && sc->_module->isRoot() &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
560 /* This case comes up when the ReturnStatement of a __foreachbody is
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
561 * checked for escapes by the caller of __foreachbody. Skip it.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
562 *
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
563 * struct S { static int opApply(int delegate(S*) dg); }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
564 * S* foo() {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
565 * foreach (S* s; S) // create __foreachbody for body of foreach
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
566 * return s; // s is inferred as 'scope' but incorrectly tested in foo()
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
567 * return null; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
568 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
569 !(!refs && p->parent == sc->func))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
570 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
571 // Only look for errors if in module listed on command line
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
572 if (global.params.vsafe) // https://issues.dlang.org/show_bug.cgi?id=17029
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
573 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
574 if (!gag)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
575 error(e->loc, "scope variable %s may not be returned", v->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
576 result = true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
577 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
578 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
579 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
580 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
581 else if (v->storage_class & STCvariadic && p == sc->func)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
582 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
583 Type *tb = v->type->toBasetype();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
584 if (tb->ty == Tarray || tb->ty == Tsarray)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
585 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
586 if (!gag)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
587 error(e->loc, "returning `%s` escapes a reference to variadic parameter `%s`", e->toChars(), v->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
588 result = false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
589 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
590 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
591 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
592 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
593 //printf("no infer for %s\n", v->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
594 v->doNotInferScope = true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
595 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
596 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
597
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
598 for (size_t i = 0; i < er.byref.dim; i++)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
599 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
600 VarDeclaration *v = er.byref[i];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
601 //printf("byref %s\n", v->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
602 if (v->isDataseg())
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
603 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
604
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
605 Dsymbol *p = v->toParent2();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
606
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
607 if ((v->storage_class & (STCref | STCout)) == 0)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
608 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
609 if (p == sc->func)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
610 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
611 escapingRef(v, e, result, gag);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
612 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
613 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
614 FuncDeclaration *fd = p->isFuncDeclaration();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
615 if (fd && sc->func->flags & FUNCFLAGreturnInprocess)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
616 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
617 /* Code like:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
618 * int x;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
619 * auto dg = () { return &x; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
620 * Making it:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
621 * auto dg = () return { return &x; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
622 * Because dg.ptr points to x, this is returning dt.ptr+offset
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
623 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
624 if (global.params.vsafe)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
625 sc->func->storage_class |= STCreturn;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
626 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
627 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
628
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
629 /* Check for returning a ref variable by 'ref', but should be 'return ref'
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
630 * Infer the addition of 'return', or set result to be the offending expression.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
631 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
632 if ( (v->storage_class & (STCref | STCout)) &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
633 !(v->storage_class & (STCreturn | STCforeach)))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
634 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
635 if ((sc->func->flags & FUNCFLAGreturnInprocess) && p == sc->func)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
636 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
637 inferReturn(sc->func, v); // infer addition of 'return'
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
638 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
639 else if (global.params.useDIP25 &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
640 sc->_module && sc->_module->isRoot())
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
641 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
642 // Only look for errors if in module listed on command line
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
643
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
644 if (p == sc->func)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
645 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
646 //printf("escaping reference to local ref variable %s\n", v->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
647 //printf("storage class = x%llx\n", v->storage_class);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
648 escapingRef(v, e, result, gag);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
649 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
650 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
651 // Don't need to be concerned if v's parent does not return a ref
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
652 FuncDeclaration *fd = p->isFuncDeclaration();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
653 if (fd && fd->type && fd->type->ty == Tfunction)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
654 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
655 TypeFunction *tf = (TypeFunction *)fd->type;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
656 if (tf->isref)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
657 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
658 if (!gag)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
659 error(e->loc, "escaping reference to outer local variable %s", v->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
660 result = true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
661 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
662 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
663 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
664 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
665 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
666 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
667
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
668 for (size_t i = 0; i < er.byexp.dim; i++)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
669 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
670 Expression *ee = er.byexp[i];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
671 //printf("byexp %s\n", ee->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
672 if (!gag)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
673 error(ee->loc, "escaping reference to stack allocated value returned by %s", ee->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
674 result = true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
675 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
676
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
677 return result;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
678 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
679
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
680
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
681 /*************************************
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
682 * Variable v needs to have 'return' inferred for it.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
683 * Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
684 * fd = function that v is a parameter to
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
685 * v = parameter that needs to be STCreturn
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
686 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
687
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
688 static void inferReturn(FuncDeclaration *fd, VarDeclaration *v)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
689 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
690 // v is a local in the current function
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
691
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
692 //printf("for function '%s' inferring 'return' for variable '%s'\n", fd->toChars(), v->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
693 v->storage_class |= STCreturn;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
694
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
695 TypeFunction *tf = (TypeFunction *)fd->type;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
696 if (v == fd->vthis)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
697 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
698 /* v is the 'this' reference, so mark the function
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
699 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
700 fd->storage_class |= STCreturn;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
701 if (tf->ty == Tfunction)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
702 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
703 //printf("'this' too %p %s\n", tf, sc->func->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
704 tf->isreturn = true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
705 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
706 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
707 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
708 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
709 // Perform 'return' inference on parameter
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
710 if (tf->ty == Tfunction && tf->parameters)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
711 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
712 const size_t dim = Parameter::dim(tf->parameters);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
713 for (size_t i = 0; i < dim; i++)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
714 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
715 Parameter *p = Parameter::getNth(tf->parameters, i);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
716 if (p->ident == v->ident)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
717 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
718 p->storageClass |= STCreturn;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
719 break; // there can be only one
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
720 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
721 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
722 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
723 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
724 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
725
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
726
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
727 /****************************************
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
728 * e is an expression to be returned by value, and that value contains pointers.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
729 * Walk e to determine which variables are possibly being
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
730 * returned by value, such as:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
731 * int* function(int* p) { return p; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
732 * If e is a form of &p, determine which variables have content
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
733 * which is being returned as ref, such as:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
734 * int* function(int i) { return &i; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
735 * Multiple variables can be inserted, because of expressions like this:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
736 * int function(bool b, int i, int* p) { return b ? &i : p; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
737 *
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
738 * No side effects.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
739 *
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
740 * Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
741 * e = expression to be returned by value
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
742 * er = where to place collected data
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
743 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
744 static void escapeByValue(Expression *e, EscapeByResults *er)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
745 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
746 //printf("[%s] escapeByValue, e: %s\n", e->loc.toChars(), e->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
747
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
748 class EscapeVisitor : public Visitor
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
749 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
750 public:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
751 EscapeByResults *er;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
752
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
753 EscapeVisitor(EscapeByResults *er)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
754 : er(er)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
755 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
756 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
757
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
758 void visit(Expression *)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
759 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
760 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
761
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
762 void visit(AddrExp *e)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
763 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
764 escapeByRef(e->e1, er);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
765 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
766
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
767 void visit(SymOffExp *e)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
768 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
769 VarDeclaration *v = e->var->isVarDeclaration();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
770 if (v)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
771 er->byref.push(v);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
772 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
773
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
774 void visit(VarExp *e)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
775 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
776 VarDeclaration *v = e->var->isVarDeclaration();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
777 if (v)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
778 er->byvalue.push(v);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
779 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
780
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
781 void visit(ThisExp *e)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
782 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
783 if (e->var)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
784 er->byvalue.push(e->var);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
785 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
786
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
787 void visit(DotVarExp *e)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
788 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
789 Type *t = e->e1->type->toBasetype();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
790 if (t->ty == Tstruct)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
791 e->e1->accept(this);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
792 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
793
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
794 void visit(DelegateExp *e)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
795 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
796 Type *t = e->e1->type->toBasetype();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
797 if (t->ty == Tclass || t->ty == Tpointer)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
798 escapeByValue(e->e1, er);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
799 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
800 escapeByRef(e->e1, er);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
801 er->byfunc.push(e->func);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
802 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
803
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
804 void visit(FuncExp *e)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
805 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
806 if (e->fd->tok == TOKdelegate)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
807 er->byfunc.push(e->fd);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
808 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
809
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
810 void visit(TupleExp *)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
811 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
812 assert(0); // should have been lowered by now
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
813 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
814
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
815 void visit(ArrayLiteralExp *e)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
816 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
817 Type *tb = e->type->toBasetype();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
818 if (tb->ty == Tsarray || tb->ty == Tarray)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
819 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
820 if (e->basis)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
821 e->basis->accept(this);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
822 for (size_t i = 0; i < e->elements->dim; i++)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
823 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
824 Expression *el = (*e->elements)[i];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
825 if (el)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
826 el->accept(this);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
827 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
828 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
829 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
830
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
831 void visit(StructLiteralExp *e)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
832 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
833 if (e->elements)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
834 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
835 for (size_t i = 0; i < e->elements->dim; i++)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
836 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
837 Expression *ex = (*e->elements)[i];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
838 if (ex)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
839 ex->accept(this);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
840 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
841 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
842 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
843
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
844 void visit(NewExp *e)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
845 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
846 Type *tb = e->newtype->toBasetype();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
847 if (tb->ty == Tstruct && !e->member && e->arguments)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
848 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
849 for (size_t i = 0; i < e->arguments->dim; i++)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
850 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
851 Expression *ex = (*e->arguments)[i];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
852 if (ex)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
853 ex->accept(this);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
854 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
855 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
856 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
857
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
858 void visit(CastExp *e)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
859 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
860 Type *tb = e->type->toBasetype();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
861 if (tb->ty == Tarray &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
862 e->e1->type->toBasetype()->ty == Tsarray)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
863 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
864 escapeByRef(e->e1, er);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
865 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
866 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
867 e->e1->accept(this);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
868 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
869
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
870 void visit(SliceExp *e)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
871 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
872 if (e->e1->op == TOKvar)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
873 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
874 VarDeclaration *v = ((VarExp *)e->e1)->var->isVarDeclaration();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
875 Type *tb = e->type->toBasetype();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
876 if (v)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
877 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
878 if (tb->ty == Tsarray)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
879 return;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
880 if (v->storage_class & STCvariadic)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
881 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
882 er->byvalue.push(v);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
883 return;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
884 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
885 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
886 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
887 Type *t1b = e->e1->type->toBasetype();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
888 if (t1b->ty == Tsarray)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
889 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
890 Type *tb = e->type->toBasetype();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
891 if (tb->ty != Tsarray)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
892 escapeByRef(e->e1, er);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
893 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
894 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
895 e->e1->accept(this);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
896 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
897
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
898 void visit(BinExp *e)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
899 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
900 Type *tb = e->type->toBasetype();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
901 if (tb->ty == Tpointer)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
902 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
903 e->e1->accept(this);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
904 e->e2->accept(this);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
905 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
906 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
907
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
908 void visit(BinAssignExp *e)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
909 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
910 e->e1->accept(this);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
911 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
912
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
913 void visit(AssignExp *e)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
914 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
915 e->e1->accept(this);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
916 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
917
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
918 void visit(CommaExp *e)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
919 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
920 e->e2->accept(this);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
921 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
922
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
923 void visit(CondExp *e)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
924 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
925 e->e1->accept(this);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
926 e->e2->accept(this);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
927 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
928
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
929 void visit(CallExp *e)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
930 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
931 //printf("CallExp(): %s\n", e->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
932 /* Check each argument that is
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
933 * passed as 'return scope'.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
934 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
935 Type *t1 = e->e1->type->toBasetype();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
936 TypeFunction *tf = NULL;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
937 TypeDelegate *dg = NULL;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
938 if (t1->ty == Tdelegate)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
939 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
940 dg = (TypeDelegate *)t1;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
941 tf = (TypeFunction *)dg->next;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
942 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
943 else if (t1->ty == Tfunction)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
944 tf = (TypeFunction *)t1;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
945 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
946 return;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
947
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
948 if (e->arguments && e->arguments->dim)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
949 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
950 /* j=1 if _arguments[] is first argument,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
951 * skip it because it is not passed by ref
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
952 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
953 size_t j = (tf->linkage == LINKd && tf->varargs == 1);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
954 for (size_t i = j; i < e->arguments->dim; ++i)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
955 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
956 Expression *arg = (*e->arguments)[i];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
957 size_t nparams = Parameter::dim(tf->parameters);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
958 if (i - j < nparams && i >= j)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
959 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
960 Parameter *p = Parameter::getNth(tf->parameters, i - j);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
961 const StorageClass stc = tf->parameterStorageClass(p);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
962 if ((stc & (STCscope)) && (stc & STCreturn))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
963 arg->accept(this);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
964 else if ((stc & (STCref)) && (stc & STCreturn))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
965 escapeByRef(arg, er);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
966 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
967 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
968 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
969 // If 'this' is returned, check it too
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
970 if (e->e1->op == TOKdotvar && t1->ty == Tfunction)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
971 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
972 DotVarExp *dve = (DotVarExp *)e->e1;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
973 FuncDeclaration *fd = dve->var->isFuncDeclaration();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
974 AggregateDeclaration *ad = NULL;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
975 if (global.params.vsafe && tf->isreturn && fd && (ad = fd->isThis()) != NULL)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
976 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
977 if (ad->isClassDeclaration() || tf->isscope) // this is 'return scope'
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
978 dve->e1->accept(this);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
979 else if (ad->isStructDeclaration()) // this is 'return ref'
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
980 escapeByRef(dve->e1, er);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
981 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
982 else if (dve->var->storage_class & STCreturn || tf->isreturn)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
983 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
984 if (dve->var->storage_class & STCscope)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
985 dve->e1->accept(this);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
986 else if (dve->var->storage_class & STCref)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
987 escapeByRef(dve->e1, er);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
988 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
989 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
990
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
991 /* If returning the result of a delegate call, the .ptr
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
992 * field of the delegate must be checked.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
993 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
994 if (dg)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
995 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
996 if (tf->isreturn)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
997 e->e1->accept(this);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
998 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
999 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1000 };
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1001
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1002 EscapeVisitor v(er);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1003 e->accept(&v);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1004 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1005
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1006 /****************************************
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1007 * e is an expression to be returned by 'ref'.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1008 * Walk e to determine which variables are possibly being
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1009 * returned by ref, such as:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1010 * ref int function(int i) { return i; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1011 * If e is a form of *p, determine which variables have content
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1012 * which is being returned as ref, such as:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1013 * ref int function(int* p) { return *p; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1014 * Multiple variables can be inserted, because of expressions like this:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1015 * ref int function(bool b, int i, int* p) { return b ? i : *p; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1016 *
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1017 * No side effects.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1018 *
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1019 * Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1020 * e = expression to be returned by 'ref'
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1021 * er = where to place collected data
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1022 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1023 static void escapeByRef(Expression *e, EscapeByResults *er)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1024 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1025 //printf("[%s] escapeByRef, e: %s\n", e->loc->toChars(), e->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1026 class EscapeRefVisitor : public Visitor
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1027 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1028 public:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1029 EscapeByResults *er;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1030
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1031 EscapeRefVisitor(EscapeByResults *er)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1032 : er(er)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1033 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1034 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1035
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1036 void visit(Expression *)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1037 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1038 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1039
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1040 void visit(VarExp *e)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1041 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1042 VarDeclaration *v = e->var->isVarDeclaration();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1043 if (v)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1044 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1045 if (v->storage_class & STCref && v->storage_class & (STCforeach | STCtemp) && v->_init)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1046 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1047 /* If compiler generated ref temporary
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1048 * (ref v = ex; ex)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1049 * look at the initializer instead
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1050 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1051 if (ExpInitializer *ez = v->_init->isExpInitializer())
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1052 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1053 assert(ez->exp && ez->exp->op == TOKconstruct);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1054 Expression *ex = ((ConstructExp *)ez->exp)->e2;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1055 ex->accept(this);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1056 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1057 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1058 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1059 er->byref.push(v);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1060 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1061 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1062
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1063 void visit(ThisExp *e)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1064 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1065 if (e->var)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1066 er->byref.push(e->var);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1067 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1068
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1069 void visit(PtrExp *e)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1070 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1071 escapeByValue(e->e1, er);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1072 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1073
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1074 void visit(IndexExp *e)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1075 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1076 Type *tb = e->e1->type->toBasetype();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1077 if (e->e1->op == TOKvar)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1078 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1079 VarDeclaration *v = ((VarExp *)e->e1)->var->isVarDeclaration();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1080 if (tb->ty == Tarray || tb->ty == Tsarray)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1081 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1082 if (v->storage_class & STCvariadic)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1083 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1084 er->byref.push(v);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1085 return;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1086 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1087 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1088 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1089 if (tb->ty == Tsarray)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1090 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1091 e->e1->accept(this);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1092 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1093 else if (tb->ty == Tarray)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1094 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1095 escapeByValue(e->e1, er);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1096 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1097 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1098
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1099 void visit(DotVarExp *e)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1100 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1101 Type *t1b = e->e1->type->toBasetype();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1102 if (t1b->ty == Tclass)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1103 escapeByValue(e->e1, er);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1104 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1105 e->e1->accept(this);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1106 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1107
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1108 void visit(BinAssignExp *e)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1109 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1110 e->e1->accept(this);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1111 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1112
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1113 void visit(AssignExp *e)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1114 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1115 e->e1->accept(this);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1116 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1117
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1118 void visit(CommaExp *e)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1119 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1120 e->e2->accept(this);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1121 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1122
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1123 void visit(CondExp *e)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1124 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1125 e->e1->accept(this);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1126 e->e2->accept(this);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1127 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1128
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1129 void visit(CallExp *e)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1130 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1131 /* If the function returns by ref, check each argument that is
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1132 * passed as 'return ref'.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1133 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1134 Type *t1 = e->e1->type->toBasetype();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1135 TypeFunction *tf;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1136 if (t1->ty == Tdelegate)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1137 tf = (TypeFunction *)((TypeDelegate *)t1)->next;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1138 else if (t1->ty == Tfunction)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1139 tf = (TypeFunction *)t1;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1140 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1141 return;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1142 if (tf->isref)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1143 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1144 if (e->arguments && e->arguments->dim)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1145 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1146 /* j=1 if _arguments[] is first argument,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1147 * skip it because it is not passed by ref
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1148 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1149 size_t j = (tf->linkage == LINKd && tf->varargs == 1);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1150
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1151 for (size_t i = j; i < e->arguments->dim; ++i)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1152 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1153 Expression *arg = (*e->arguments)[i];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1154 size_t nparams = Parameter::dim(tf->parameters);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1155 if (i - j < nparams && i >= j)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1156 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1157 Parameter *p = Parameter::getNth(tf->parameters, i - j);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1158 const StorageClass stc = tf->parameterStorageClass(p);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1159 if ((stc & (STCout | STCref)) && (stc & STCreturn))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1160 arg->accept(this);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1161 else if ((stc & STCscope) && (stc & STCreturn))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1162 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1163 if (arg->op == TOKdelegate)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1164 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1165 DelegateExp *de = (DelegateExp *)arg;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1166 if (de->func->isNested())
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1167 er->byexp.push(de);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1168 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1169 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1170 escapeByValue(arg, er);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1171 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1172 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1173 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1174 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1175
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1176 // If 'this' is returned by ref, check it too
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1177 if (e->e1->op == TOKdotvar && t1->ty == Tfunction)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1178 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1179 DotVarExp *dve = (DotVarExp *)e->e1;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1180 if (dve->var->storage_class & STCreturn || tf->isreturn)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1181 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1182 if ((dve->var->storage_class & STCscope) || tf->isscope)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1183 escapeByValue(dve->e1, er);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1184 else if ((dve->var->storage_class & STCref) || tf->isref)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1185 dve->e1->accept(this);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1186 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1187
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1188 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1189 // If it's a delegate, check it too
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1190 if (e->e1->op == TOKvar && t1->ty == Tdelegate)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1191 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1192 escapeByValue(e->e1, er);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1193 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1194 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1195 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1196 er->byexp.push(e);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1197 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1198 };
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1199
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1200 EscapeRefVisitor v(er);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1201 e->accept(&v);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1202 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1203
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1204 /*************************
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1205 * Find all variables accessed by this delegate that are
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1206 * in functions enclosing it.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1207 * Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1208 * fd = function
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1209 * vars = array to append found variables to
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1210 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1211 void findAllOuterAccessedVariables(FuncDeclaration *fd, VarDeclarations *vars)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1212 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1213 //printf("findAllOuterAccessedVariables(fd: %s)\n", fd.toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1214 for (Dsymbol *p = fd->parent; p; p = p->parent)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1215 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1216 FuncDeclaration *fdp = p->isFuncDeclaration();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1217 if (fdp)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1218 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1219 for (size_t i = 0; i < fdp->closureVars.dim; i++)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1220 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1221 VarDeclaration *v = fdp->closureVars[i];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1222 for (size_t j = 0; j < v->nestedrefs.dim; j++)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1223 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1224 FuncDeclaration *fdv = v->nestedrefs[j];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1225 if (fdv == fd)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1226 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1227 //printf("accessed: %s, type %s\n", v->toChars(), v->type->toChars());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1228 vars->push(v);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1229 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1230 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1231 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1232 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1233 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1234 }