xref: /netbsd/external/gpl3/gcc.old/dist/gcc/d/dmd/nogc.c (revision 760c2415)
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