]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/d/dmd/nogc.c
ipa-param-manip: Be careful about a reallocating hash_map
[thirdparty/gcc.git] / gcc / d / dmd / nogc.c
CommitLineData
b4c522fa
IB
1
2/* Compiler implementation of the D programming language
a3b38b77 3 * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
b4c522fa
IB
4 * written by Walter Bright
5 * http://www.digitalmars.com
6 * Distributed under the Boost Software License, Version 1.0.
7 * http://www.boost.org/LICENSE_1_0.txt
8 * https://github.com/D-Programming-Language/dmd/blob/master/src/nogc.c
9 */
10
11#include "mars.h"
12#include "init.h"
13#include "visitor.h"
14#include "expression.h"
15#include "statement.h"
16#include "declaration.h"
17#include "id.h"
18#include "module.h"
19#include "scope.h"
20#include "tokens.h"
21#include "aggregate.h"
22
23bool walkPostorder(Expression *e, StoppableVisitor *v);
24
25void FuncDeclaration::printGCUsage(Loc loc, const char* warn)
26{
27 if (!global.params.vgc)
28 return;
29
30 Module *m = getModule();
31 if (m && m->isRoot() && !inUnittest())
32 {
33 message(loc, "vgc: %s", warn);
34 }
35}
36
37/**************************************
38 * Look for GC-allocations
39 */
40class NOGCVisitor : public StoppableVisitor
41{
42public:
43 FuncDeclaration *f;
44 bool err;
45
46 NOGCVisitor(FuncDeclaration *f)
47 {
48 this->f = f;
49 this->err = false;
50 }
51
52 void doCond(Expression *exp)
53 {
54 if (exp)
55 walkPostorder(exp, this);
56 }
57
58 void visit(Expression *)
59 {
60 }
61
62 void visit(DeclarationExp *e)
63 {
64 // Note that, walkPostorder does not support DeclarationExp today.
65 VarDeclaration *v = e->declaration->isVarDeclaration();
66 if (v && !(v->storage_class & STCmanifest) && !v->isDataseg() && v->_init)
67 {
68 if (ExpInitializer *ei = v->_init->isExpInitializer())
69 {
70 doCond(ei->exp);
71 }
72 }
73 }
74
75 void visit(CallExp *)
76 {
77 }
78
79 void visit(ArrayLiteralExp *e)
80 {
2cbc99d1 81 if (e->type->ty != Tarray || !e->elements || !e->elements->length)
b4c522fa
IB
82 return;
83
84 if (f->setGC())
85 {
a3b38b77 86 e->error("array literal in @nogc %s `%s` may cause GC allocation",
b4c522fa
IB
87 f->kind(), f->toPrettyChars());
88 err = true;
89 return;
90 }
91 f->printGCUsage(e->loc, "array literal may cause GC allocation");
92 }
93
94 void visit(AssocArrayLiteralExp *e)
95 {
2cbc99d1 96 if (!e->keys->length)
b4c522fa
IB
97 return;
98
99 if (f->setGC())
100 {
a3b38b77 101 e->error("associative array literal in @nogc %s `%s` may cause GC allocation",
b4c522fa
IB
102 f->kind(), f->toPrettyChars());
103 err = true;
104 return;
105 }
106 f->printGCUsage(e->loc, "associative array literal may cause GC allocation");
107 }
108
109 void visit(NewExp *e)
110 {
111 if (e->member && !e->member->isNogc() && f->setGC())
112 {
113 // @nogc-ness is already checked in NewExp::semantic
114 return;
115 }
116 if (e->onstack)
117 return;
118 if (e->allocator)
119 return;
120
121 if (f->setGC())
122 {
a3b38b77 123 e->error("cannot use `new` in @nogc %s `%s`",
b4c522fa
IB
124 f->kind(), f->toPrettyChars());
125 err = true;
126 return;
127 }
a3b38b77 128 f->printGCUsage(e->loc, "`new` causes GC allocation");
b4c522fa
IB
129 }
130
131 void visit(DeleteExp *e)
132 {
133 if (e->e1->op == TOKvar)
134 {
135 VarDeclaration *v = ((VarExp *)e->e1)->var->isVarDeclaration();
136 if (v && v->onstack)
137 return; // delete for scope allocated class object
138 }
139
140 Type *tb = e->e1->type->toBasetype();
141 AggregateDeclaration *ad = NULL;
142 switch (tb->ty)
143 {
144 case Tclass:
145 ad = ((TypeClass *)tb)->sym;
146 break;
147
148 case Tpointer:
149 tb = ((TypePointer *)tb)->next->toBasetype();
150 if (tb->ty == Tstruct)
151 ad = ((TypeStruct *)tb)->sym;
152 break;
153
154 default:
155 break;
156 }
157 if (ad && ad->aggDelete)
158 return;
159
160 if (f->setGC())
161 {
a3b38b77 162 e->error("cannot use `delete` in @nogc %s `%s`",
b4c522fa
IB
163 f->kind(), f->toPrettyChars());
164 err = true;
165 return;
166 }
a3b38b77 167 f->printGCUsage(e->loc, "`delete` requires GC");
b4c522fa
IB
168 }
169
170 void visit(IndexExp* e)
171 {
172 Type *t1b = e->e1->type->toBasetype();
173 if (t1b->ty == Taarray)
174 {
175 if (f->setGC())
176 {
a3b38b77 177 e->error("indexing an associative array in @nogc %s `%s` may cause GC allocation",
b4c522fa
IB
178 f->kind(), f->toPrettyChars());
179 err = true;
180 return;
181 }
182 f->printGCUsage(e->loc, "indexing an associative array may cause GC allocation");
183 }
184 }
185
186 void visit(AssignExp *e)
187 {
188 if (e->e1->op == TOKarraylength)
189 {
190 if (f->setGC())
191 {
a3b38b77 192 e->error("setting `length` in @nogc %s `%s` may cause GC allocation",
b4c522fa
IB
193 f->kind(), f->toPrettyChars());
194 err = true;
195 return;
196 }
a3b38b77 197 f->printGCUsage(e->loc, "setting `length` may cause GC allocation");
b4c522fa
IB
198 }
199 }
200
201 void visit(CatAssignExp *e)
202 {
203 if (f->setGC())
204 {
a3b38b77 205 e->error("cannot use operator ~= in @nogc %s `%s`",
b4c522fa
IB
206 f->kind(), f->toPrettyChars());
207 err = true;
208 return;
209 }
210 f->printGCUsage(e->loc, "operator ~= may cause GC allocation");
211 }
212
213 void visit(CatExp *e)
214 {
215 if (f->setGC())
216 {
a3b38b77 217 e->error("cannot use operator ~ in @nogc %s `%s`",
b4c522fa
IB
218 f->kind(), f->toPrettyChars());
219 err = true;
220 return;
221 }
222 f->printGCUsage(e->loc, "operator ~ may cause GC allocation");
223 }
224};
225
226Expression *checkGC(Scope *sc, Expression *e)
227{
228 FuncDeclaration *f = sc->func;
229 if (e && e->op != TOKerror &&
230 f && sc->intypeof != 1 && !(sc->flags & SCOPEctfe) &&
231 ((f->type->ty == Tfunction && ((TypeFunction *)f->type)->isnogc) ||
232 (f->flags & FUNCFLAGnogcInprocess) ||
233 global.params.vgc))
234 {
235 NOGCVisitor gcv(f);
236 walkPostorder(e, &gcv);
237 if (gcv.err)
238 return new ErrorExp();
239 }
240 return e;
241}