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