0
|
1 module dmd.FuncDeclaration;
|
|
2
|
|
3 import dmd.Declaration;
|
|
4 import dmd.DotIdExp;
|
|
5 import dmd.TryFinallyStatement;
|
|
6 import dmd.StaticDtorDeclaration;
|
|
7 import dmd.PeelStatement;
|
|
8 import dmd.SynchronizedStatement;
|
|
9 import dmd.TOK;
|
|
10 import dmd.SymOffExp;
|
|
11 import dmd.AssignExp;
|
|
12 import dmd.ExpInitializer;
|
|
13 import dmd.BE;
|
|
14 import dmd.Id;
|
|
15 import dmd.StringExp;
|
|
16 import dmd.DsymbolExp;
|
|
17 import dmd.HaltExp;
|
|
18 import dmd.CommaExp;
|
|
19 import dmd.ReturnStatement;
|
|
20 import dmd.IntegerExp;
|
|
21 import dmd.ExpStatement;
|
|
22 import dmd.CSX;
|
|
23 import dmd.CompoundStatement;
|
|
24 import dmd.LabelStatement;
|
|
25 import dmd.ThisExp;
|
|
26 import dmd.SuperExp;
|
|
27 import dmd.IdentifierExp;
|
|
28 import dmd.AssertExp;
|
|
29 import dmd.CallExp;
|
|
30 import dmd.RET;
|
|
31 import dmd.VarExp;
|
|
32 import dmd.TupleDeclaration;
|
|
33 import dmd.ThisDeclaration;
|
|
34 import dmd.TypeTuple;
|
|
35 import dmd.TemplateInstance;
|
|
36 import dmd.ScopeDsymbol;
|
|
37 import dmd.AliasDeclaration;
|
|
38 import dmd.MOD;
|
|
39 import dmd.PROT;
|
|
40 import dmd.Lexer;
|
|
41 import dmd.LINK;
|
|
42 import dmd.CtorDeclaration;
|
|
43 import dmd.Global;
|
|
44 import dmd.DtorDeclaration;
|
|
45 import dmd.InvariantDeclaration;
|
|
46 import dmd.TY;
|
|
47 import dmd.PtrExp;
|
|
48 import dmd.DeclarationExp;
|
|
49 import dmd.InlineDoState;
|
|
50 import dmd.Argument;
|
|
51 import dmd.StructDeclaration;
|
|
52 import dmd.ClassDeclaration;
|
|
53 import dmd.InterfaceDeclaration;
|
|
54 import dmd.Array;
|
|
55 import dmd.Statement;
|
|
56 import dmd.Identifier;
|
|
57 import dmd.VarDeclaration;
|
|
58 import dmd.LabelDsymbol;
|
|
59 import dmd.DsymbolTable;
|
|
60 import dmd.ArrayTypes;
|
|
61 import dmd.Loc;
|
|
62 import dmd.ILS;
|
|
63 import dmd.ForeachStatement;
|
|
64 import dmd.Type;
|
|
65 import dmd.BUILTIN;
|
|
66 import dmd.TypeFunction;
|
|
67 import dmd.Expression;
|
|
68 import dmd.STC;
|
|
69 import dmd.Dsymbol;
|
|
70 import dmd.Scope;
|
|
71 import dmd.OutBuffer;
|
|
72 import dmd.HdrGenState;
|
|
73 import dmd.MATCH;
|
|
74 import dmd.AggregateDeclaration;
|
|
75 import dmd.InterState;
|
|
76 import dmd.InlineScanState;
|
|
77 import dmd.IRState;
|
|
78 import dmd.Util;
|
|
79 import dmd.BaseClass;
|
|
80 import dmd.Module;
|
|
81 import dmd.ILS;
|
|
82 import dmd.InlineCostState;
|
|
83
|
|
84 import dmd.expression.Util;
|
|
85
|
|
86 import dmd.declaration.Match;
|
|
87
|
|
88 import dmd.backend.Symbol;
|
|
89 import dmd.backend.func_t;
|
|
90 import dmd.backend.Util;
|
|
91 import dmd.backend.glue;
|
|
92 import dmd.backend.SC;
|
|
93 import dmd.backend.F;
|
|
94 import dmd.backend.Cstate;
|
|
95 import dmd.backend.TYM;
|
|
96 import dmd.backend.OPER;
|
|
97 import dmd.backend.TYFL;
|
|
98 import dmd.backend.TYPE;
|
|
99 import dmd.backend.SFL;
|
|
100 import dmd.backend.mTY;
|
|
101 import dmd.backend.FL;
|
|
102 import dmd.backend.REG;
|
|
103 import dmd.backend.block;
|
|
104 import dmd.backend.Blockx;
|
|
105 import dmd.backend.Config;
|
|
106 import dmd.backend.BC;
|
|
107 import dmd.backend.elem;
|
|
108 import dmd.backend.targ_types;
|
|
109 import dmd.backend.mTYman;
|
|
110 import dmd.backend.RTLSYM;
|
|
111 import dmd.backend.LIST;
|
|
112
|
|
113 import core.stdc.stdio;
|
|
114 import core.stdc.string;
|
|
115
|
|
116 import std.string;
|
|
117
|
|
118 class FuncDeclaration : Declaration
|
|
119 {
|
|
120 Array fthrows; // Array of Type's of exceptions (not used)
|
|
121 Statement frequire;
|
|
122 Statement fensure;
|
|
123 Statement fbody;
|
|
124
|
|
125 Identifier outId; // identifier for out statement
|
|
126 VarDeclaration vresult; // variable corresponding to outId
|
|
127 LabelDsymbol returnLabel; // where the return goes
|
|
128
|
|
129 DsymbolTable localsymtab; // used to prevent symbols in different
|
|
130 // scopes from having the same name
|
|
131 VarDeclaration vthis; // 'this' parameter (member and nested)
|
|
132 VarDeclaration v_arguments; // '_arguments' parameter
|
|
133 version (IN_GCC) {
|
|
134 VarDeclaration v_argptr; // '_argptr' variable
|
|
135 }
|
|
136 Dsymbols parameters; // Array of VarDeclaration's for parameters
|
|
137 DsymbolTable labtab; // statement label symbol table
|
|
138 Declaration overnext; // next in overload list
|
|
139 Loc endloc; // location of closing curly bracket
|
|
140 int vtblIndex = -1; // for member functions, index into vtbl[]
|
|
141 int naked; // !=0 if naked
|
|
142 int inlineAsm; // !=0 if has inline assembler
|
|
143 ILS inlineStatus = ILS.ILSuninitialized;
|
|
144 int inlineNest; // !=0 if nested inline
|
|
145 int cantInterpret; // !=0 if cannot interpret function
|
|
146 int semanticRun; // 1 semantic() run
|
|
147 // 2 semantic2() run
|
|
148 // 3 semantic3() started
|
|
149 // 4 semantic3() done
|
|
150 // 5 toObjFile() run
|
|
151 // this function's frame ptr
|
|
152 ForeachStatement fes; // if foreach body, this is the foreach
|
|
153 int introducing; // !=0 if 'introducing' function
|
|
154 Type tintro; // if !=null, then this is the type
|
|
155 // of the 'introducing' function
|
|
156 // this one is overriding
|
|
157 int inferRetType; // !=0 if return type is to be inferred
|
|
158
|
|
159 // Things that should really go into Scope
|
|
160 int hasReturnExp; // 1 if there's a return exp; statement
|
|
161 // 2 if there's a throw statement
|
|
162 // 4 if there's an assert(0)
|
|
163 // 8 if there's inline asm
|
|
164
|
|
165 // Support for NRVO (named return value optimization)
|
|
166 bool nrvo_can = true; // !=0 means we can do it
|
|
167 VarDeclaration nrvo_var; // variable to replace with shidden
|
|
168 Symbol* shidden; // hidden pointer passed to function
|
|
169
|
|
170 version (DMDV2) {
|
|
171 BUILTIN builtin; // set if this is a known, builtin
|
|
172 // function we can evaluate at compile
|
|
173 // time
|
|
174
|
|
175 int tookAddressOf; // set if someone took the address of
|
|
176 // this function
|
|
177 Dsymbols closureVars; // local variables in this function
|
|
178 // which are referenced by nested
|
|
179 // functions
|
|
180 } else {
|
|
181 int nestedFrameRef; // !=0 if nested variables referenced
|
|
182 }
|
|
183
|
|
184 this(Loc loc, Loc endloc, Identifier id, STC storage_class, Type type)
|
|
185 {
|
|
186 super(id);
|
|
187
|
|
188 //printf("FuncDeclaration(id = '%s', type = %p)\n", id.toChars(), type);
|
|
189 //printf("storage_class = x%x\n", storage_class);
|
|
190 this.storage_class = storage_class;
|
|
191 this.type = type;
|
|
192 this.loc = loc;
|
|
193 this.endloc = endloc;
|
|
194
|
|
195 /* The type given for "infer the return type" is a TypeFunction with
|
|
196 * null for the return type.
|
|
197 */
|
|
198 inferRetType = (type && type.nextOf() is null);
|
|
199
|
|
200 closureVars = new Dsymbols();
|
|
201
|
|
202 version (DMDV2) {
|
|
203 builtin = BUILTIN.BUILTINunknown;
|
|
204 }
|
|
205 }
|
|
206
|
|
207 Dsymbol syntaxCopy(Dsymbol s)
|
|
208 {
|
|
209 FuncDeclaration f;
|
|
210
|
|
211 //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars());
|
|
212 if (s)
|
|
213 f = cast(FuncDeclaration)s;
|
|
214 else
|
|
215 f = new FuncDeclaration(loc, endloc, ident, storage_class, type.syntaxCopy());
|
|
216
|
|
217 f.outId = outId;
|
|
218 f.frequire = frequire ? frequire.syntaxCopy() : null;
|
|
219 f.fensure = fensure ? fensure.syntaxCopy() : null;
|
|
220 f.fbody = fbody ? fbody.syntaxCopy() : null;
|
|
221 assert(!fthrows); // deprecated
|
|
222
|
|
223 return f;
|
|
224 }
|
|
225
|
|
226 // Do the semantic analysis on the external interface to the function.
|
|
227 void semantic(Scope sc)
|
|
228 {
|
|
229 TypeFunction f;
|
|
230 StructDeclaration sd;
|
|
231 ClassDeclaration cd;
|
|
232 InterfaceDeclaration id;
|
|
233 Dsymbol pd;
|
|
234
|
|
235 static if (false) {
|
|
236 printf("FuncDeclaration.semantic(sc = %p, this = %p, '%s', linkage = %d)\n", sc, this, toPrettyChars(), sc.linkage);
|
|
237 if (isFuncLiteralDeclaration())
|
|
238 printf("\tFuncLiteralDeclaration()\n");
|
|
239 printf("sc.parent = %s, parent = %s\n", sc.parent.toChars(), parent ? parent.toChars() : "");
|
|
240 printf("type: %p, %s\n", type, type.toChars());
|
|
241 }
|
|
242
|
|
243 if (semanticRun && isFuncLiteralDeclaration())
|
|
244 {
|
|
245 /* Member functions that have return types that are
|
|
246 * forward references can have semantic() run more than
|
|
247 * once on them.
|
|
248 * See test\interface2.d, test20
|
|
249 */
|
|
250 return;
|
|
251 }
|
|
252 assert(semanticRun <= 1);
|
|
253 semanticRun = 1;
|
|
254
|
|
255 storage_class |= sc.stc & ~STC.STCref;
|
|
256 //printf("function storage_class = x%x\n", storage_class);
|
|
257
|
|
258 if (!originalType)
|
|
259 originalType = type;
|
|
260 if (!type.deco)
|
|
261 {
|
|
262 /* Apply const and invariant storage class
|
|
263 * to the function type
|
|
264 */
|
|
265 type = type.semantic(loc, sc);
|
|
266 STC stc = storage_class;
|
|
267 if (type.isInvariant())
|
|
268 stc |= STC.STCimmutable;
|
|
269 if (type.isConst())
|
|
270 stc |= STC.STCconst;
|
|
271 if (type.isShared() || storage_class & STC.STCsynchronized)
|
|
272 stc |= STC.STCshared;
|
|
273 switch (stc & STC.STC_TYPECTOR)
|
|
274 {
|
|
275 case STC.STCimmutable:
|
|
276 case STC.STCimmutable | STC.STCconst:
|
|
277 case STC.STCimmutable | STC.STCconst | STC.STCshared:
|
|
278 case STC.STCimmutable | STC.STCshared:
|
|
279 // Don't use toInvariant(), as that will do a merge()
|
|
280 type = type.makeInvariant();
|
|
281 type.deco = type.merge().deco;
|
|
282 break;
|
|
283
|
|
284 case STC.STCconst:
|
|
285 type = type.makeConst();
|
|
286 type.deco = type.merge().deco;
|
|
287 break;
|
|
288
|
|
289 case STC.STCshared | STC.STCconst:
|
|
290 type = type.makeSharedConst();
|
|
291 type.deco = type.merge().deco;
|
|
292 break;
|
|
293
|
|
294 case STC.STCshared:
|
|
295 type = type.makeShared();
|
|
296 type.deco = type.merge().deco;
|
|
297 break;
|
|
298
|
|
299 case STC.STCundefined:
|
|
300 break;
|
|
301
|
|
302 default:
|
|
303 assert(0);
|
|
304 }
|
|
305 }
|
|
306 //type.print();
|
|
307 if (type.ty != TY.Tfunction)
|
|
308 {
|
|
309 error("%s must be a function", toChars());
|
|
310 return;
|
|
311 }
|
|
312 f = cast(TypeFunction)type;
|
|
313 size_t nparams = Argument.dim(f.parameters);
|
|
314
|
|
315 linkage = sc.linkage;
|
|
316 // if (!parent)
|
|
317 {
|
|
318 //parent = sc.scopesym;
|
|
319 parent = sc.parent;
|
|
320 }
|
|
321 protection = sc.protection;
|
|
322 Dsymbol parent = toParent();
|
|
323
|
|
324 if (storage_class & STC.STCscope)
|
|
325 error("functions cannot be scope");
|
|
326
|
|
327 if (isAbstract() && !isVirtual())
|
|
328 error("non-virtual functions cannot be abstract");
|
|
329
|
|
330 if ((f.isConst() || f.isInvariant()) && !isThis())
|
|
331 error("without 'this' cannot be const/immutable");
|
|
332
|
|
333 if (isAbstract() && isFinal())
|
|
334 error("cannot be both final and abstract");
|
|
335 static if (false) {
|
|
336 if (isAbstract() && fbody)
|
|
337 error("abstract functions cannot have bodies");
|
|
338 }
|
|
339
|
|
340 static if (false) {
|
|
341 if (isStaticConstructor() || isStaticDestructor())
|
|
342 {
|
|
343 if (!isStatic() || type.nextOf().ty != Tvoid)
|
|
344 error("static constructors / destructors must be static void");
|
|
345 if (f.arguments && f.arguments.dim)
|
|
346 error("static constructors / destructors must have empty parameter list");
|
|
347 // BUG: check for invalid storage classes
|
|
348 }
|
|
349 }
|
|
350
|
|
351 version (IN_GCC) {
|
|
352 AggregateDeclaration ad;
|
|
353
|
|
354 ad = parent.isAggregateDeclaration();
|
|
355 if (ad)
|
|
356 ad.methods.push(cast(void*)this);
|
|
357 }
|
|
358 sd = parent.isStructDeclaration();
|
|
359 if (sd)
|
|
360 {
|
|
361 if (isCtorDeclaration())
|
|
362 {
|
|
363 return;
|
|
364 }
|
|
365 static if (false) {
|
|
366 // Verify no constructors, destructors, etc.
|
|
367 if (isCtorDeclaration()
|
|
368 //||isDtorDeclaration()
|
|
369 //|| isInvariantDeclaration()
|
|
370 //|| isUnitTestDeclaration()
|
|
371 )
|
|
372 {
|
|
373 error("special member functions not allowed for %ss", sd.kind());
|
|
374 }
|
|
375
|
|
376 if (!sd.inv)
|
|
377 sd.inv = isInvariantDeclaration();
|
|
378
|
|
379 if (!sd.aggNew)
|
|
380 sd.aggNew = isNewDeclaration();
|
|
381
|
|
382 if (isDelete())
|
|
383 {
|
|
384 if (sd.aggDelete)
|
|
385 error("multiple delete's for struct %s", sd.toChars());
|
|
386 sd.aggDelete = cast(DeleteDeclaration)this;
|
|
387 }
|
|
388 }
|
|
389 }
|
|
390
|
|
391 id = parent.isInterfaceDeclaration();
|
|
392 if (id)
|
|
393 {
|
|
394 storage_class |= STC.STCabstract;
|
|
395
|
|
396 if (isCtorDeclaration() ||
|
|
397 ///static if (DMDV2) {
|
|
398 isPostBlitDeclaration() ||
|
|
399 ///}
|
|
400 isDtorDeclaration() ||
|
|
401 isInvariantDeclaration() ||
|
|
402 isUnitTestDeclaration() || isNewDeclaration() || isDelete())
|
|
403 error("special function not allowed in interface %s", id.toChars());
|
|
404 if (fbody)
|
|
405 error("function body is not abstract in interface %s", id.toChars());
|
|
406 }
|
|
407
|
|
408 /* Template member functions aren't virtual:
|
|
409 * interface TestInterface { void tpl(T)(); }
|
|
410 * and so won't work in interfaces
|
|
411 */
|
|
412 if ((pd = toParent()) !is null &&
|
|
413 pd.isTemplateInstance() &&
|
|
414 (pd = toParent2()) !is null &&
|
|
415 (id = pd.isInterfaceDeclaration()) !is null)
|
|
416 {
|
|
417 error("template member function not allowed in interface %s", id.toChars());
|
|
418 }
|
|
419
|
|
420 cd = parent.isClassDeclaration();
|
|
421 if (cd)
|
|
422 { int vi;
|
|
423 CtorDeclaration ctor;
|
|
424 DtorDeclaration dtor;
|
|
425 InvariantDeclaration inv;
|
|
426
|
|
427 if (isCtorDeclaration())
|
|
428 {
|
|
429 // ctor = cast(CtorDeclaration)this;
|
|
430 // if (!cd.ctor)
|
|
431 // cd.ctor = ctor;
|
|
432 return;
|
|
433 }
|
|
434
|
|
435 static if (false) {
|
|
436 dtor = isDtorDeclaration();
|
|
437 if (dtor)
|
|
438 {
|
|
439 if (cd.dtor)
|
|
440 error("multiple destructors for class %s", cd.toChars());
|
|
441 cd.dtor = dtor;
|
|
442 }
|
|
443
|
|
444 inv = isInvariantDeclaration();
|
|
445 if (inv)
|
|
446 {
|
|
447 cd.inv = inv;
|
|
448 }
|
|
449
|
|
450 if (isNewDeclaration())
|
|
451 {
|
|
452 if (!cd.aggNew)
|
|
453 cd.aggNew = cast(NewDeclaration)this;
|
|
454 }
|
|
455
|
|
456 if (isDelete())
|
|
457 {
|
|
458 if (cd.aggDelete)
|
|
459 error("multiple delete's for class %s", cd.toChars());
|
|
460 cd.aggDelete = cast(DeleteDeclaration)this;
|
|
461 }
|
|
462 }
|
|
463
|
|
464 if (storage_class & STC.STCabstract)
|
|
465 cd.isabstract = true;
|
|
466
|
|
467 // if static function, do not put in vtbl[]
|
|
468 if (!isVirtual())
|
|
469 {
|
|
470 //printf("\tnot virtual\n");
|
|
471 goto Ldone;
|
|
472 }
|
|
473
|
|
474 // Find index of existing function in vtbl[] to override
|
|
475 vi = findVtblIndex(cd.vtbl, cd.baseClass ? cd.baseClass.vtbl.dim : 0);
|
|
476 switch (vi)
|
|
477 {
|
|
478 case -1:
|
|
479 /* Didn't find one, so
|
|
480 * This is an 'introducing' function which gets a new
|
|
481 * slot in the vtbl[].
|
|
482 */
|
|
483
|
|
484 // Verify this doesn't override previous final function
|
|
485 if (cd.baseClass)
|
|
486 {
|
|
487 Dsymbol s = cd.baseClass.search(loc, ident, 0);
|
|
488 if (s)
|
|
489 {
|
|
490 FuncDeclaration ff = s.isFuncDeclaration();
|
|
491 ff = ff.overloadExactMatch(type);
|
|
492 if (ff && ff.isFinal() && ff.prot() != PROT.PROTprivate)
|
|
493 error("cannot override final function %s", ff.toPrettyChars());
|
|
494 }
|
|
495 }
|
|
496
|
|
497 if (isFinal())
|
|
498 {
|
|
499 if (isOverride())
|
|
500 error("does not override any function");
|
|
501 cd.vtblFinal.push(cast(void*)this);
|
|
502 }
|
|
503 else
|
|
504 {
|
|
505 // Append to end of vtbl[]
|
|
506 //printf("\tintroducing function\n");
|
|
507 introducing = 1;
|
|
508 vi = cd.vtbl.dim;
|
|
509 cd.vtbl.push(cast(void*)this);
|
|
510 vtblIndex = vi;
|
|
511 }
|
|
512 break;
|
|
513
|
|
514 case -2: // can't determine because of fwd refs
|
|
515 cd.sizeok = 2; // can't finish due to forward reference
|
|
516 return;
|
|
517
|
|
518 default:
|
|
519 {
|
|
520 FuncDeclaration fdv = cast(FuncDeclaration)cd.vtbl.data[vi];
|
|
521 // This function is covariant with fdv
|
|
522 if (fdv.isFinal())
|
|
523 error("cannot override final function %s", fdv.toPrettyChars());
|
|
524
|
|
525 version (DMDV2) {
|
|
526 if (!isOverride())
|
|
527 warning(loc, "overrides base class function %s, but is not marked with 'override'", fdv.toPrettyChars());
|
|
528 }
|
|
529
|
|
530 if (fdv.toParent() == parent)
|
|
531 {
|
|
532 // If both are mixins, then error.
|
|
533 // If either is not, the one that is not overrides
|
|
534 // the other.
|
|
535 if (fdv.parent.isClassDeclaration())
|
|
536 break;
|
|
537 if (!this.parent.isClassDeclaration()
|
|
538 ///static if (!BREAKABI) {
|
|
539 && !isDtorDeclaration()
|
|
540 ///}
|
|
541 ///version (DMDV2) {
|
|
542 && !isPostBlitDeclaration()
|
|
543 ///}
|
|
544 )
|
|
545 error("multiple overrides of same function");
|
|
546 }
|
|
547 cd.vtbl.data[vi] = cast(void*)this;
|
|
548 vtblIndex = vi;
|
|
549
|
|
550 /* This works by whenever this function is called,
|
|
551 * it actually returns tintro, which gets dynamically
|
|
552 * cast to type. But we know that tintro is a base
|
|
553 * of type, so we could optimize it by not doing a
|
|
554 * dynamic cast, but just subtracting the isBaseOf()
|
|
555 * offset if the value is != null.
|
|
556 */
|
|
557
|
|
558 if (fdv.tintro)
|
|
559 tintro = fdv.tintro;
|
|
560 else if (!type.equals(fdv.type))
|
|
561 {
|
|
562 /* Only need to have a tintro if the vptr
|
|
563 * offsets differ
|
|
564 */
|
|
565 int offset;
|
|
566 if (fdv.type.nextOf().isBaseOf(type.nextOf(), &offset))
|
|
567 {
|
|
568 tintro = fdv.type;
|
|
569 }
|
|
570 }
|
|
571 break;
|
|
572 }
|
|
573 }
|
|
574
|
|
575 /* Go through all the interface bases.
|
|
576 * If this function is covariant with any members of those interface
|
|
577 * functions, set the tintro.
|
|
578 */
|
|
579 for (int i = 0; i < cd.interfaces_dim; i++)
|
|
580 {
|
|
581 BaseClass b = cd.interfaces[i];
|
|
582 vi = findVtblIndex(b.base.vtbl, b.base.vtbl.dim);
|
|
583 switch (vi)
|
|
584 {
|
|
585 case -1:
|
|
586 break;
|
|
587
|
|
588 case -2:
|
|
589 cd.sizeok = 2; // can't finish due to forward reference
|
|
590 return;
|
|
591
|
|
592 default:
|
|
593 { FuncDeclaration fdv = cast(FuncDeclaration)b.base.vtbl.data[vi];
|
|
594 Type ti = null;
|
|
595
|
|
596 if (fdv.tintro)
|
|
597 ti = fdv.tintro;
|
|
598 else if (!type.equals(fdv.type))
|
|
599 {
|
|
600 /* Only need to have a tintro if the vptr
|
|
601 * offsets differ
|
|
602 */
|
|
603 int offset;
|
|
604 if (fdv.type.nextOf().isBaseOf(type.nextOf(), &offset))
|
|
605 {
|
|
606 ti = fdv.type;
|
|
607 static if (false) {
|
|
608 if (offset)
|
|
609 ti = fdv.type;
|
|
610 else if (type.nextOf().ty == Tclass)
|
|
611 {
|
|
612 ClassDeclaration cdn = (cast(TypeClass)type.nextOf()).sym;
|
|
613 if (cdn && cdn.sizeok != 1)
|
|
614 ti = fdv.type;
|
|
615 }
|
|
616 }
|
|
617 }
|
|
618 }
|
|
619 if (ti)
|
|
620 {
|
|
621 if (tintro && !tintro.equals(ti))
|
|
622 {
|
|
623 error("incompatible covariant types %s and %s", tintro.toChars(), ti.toChars());
|
|
624 }
|
|
625 tintro = ti;
|
|
626 }
|
|
627 goto L2;
|
|
628 }
|
|
629 }
|
|
630 }
|
|
631
|
|
632 if (introducing && isOverride())
|
|
633 {
|
|
634 error("does not override any function");
|
|
635 }
|
|
636
|
|
637 L2: ;
|
|
638 }
|
|
639 else if (isOverride() && !parent.isTemplateInstance())
|
|
640 error("override only applies to class member functions");
|
|
641
|
|
642 /* Do not allow template instances to add virtual functions
|
|
643 * to a class.
|
|
644 */
|
|
645 if (isVirtual())
|
|
646 {
|
|
647 TemplateInstance ti = parent.isTemplateInstance();
|
|
648 if (ti)
|
|
649 {
|
|
650 // Take care of nested templates
|
|
651 while (1)
|
|
652 {
|
|
653 TemplateInstance ti2 = ti.tempdecl.parent.isTemplateInstance();
|
|
654 if (!ti2)
|
|
655 break;
|
|
656 ti = ti2;
|
|
657 }
|
|
658
|
|
659 // If it's a member template
|
|
660 ClassDeclaration cdd = ti.tempdecl.isClassMember();
|
|
661 if (cdd)
|
|
662 {
|
|
663 error("cannot use template to add virtual function to class '%s'", cdd.toChars());
|
|
664 }
|
|
665 }
|
|
666 }
|
|
667
|
|
668 if (isMain())
|
|
669 {
|
|
670 // Check parameters to see if they are either () or (char[][] args)
|
|
671 switch (nparams)
|
|
672 {
|
|
673 case 0:
|
|
674 break;
|
|
675
|
|
676 case 1:
|
|
677 {
|
|
678 Argument arg0 = Argument.getNth(f.parameters, 0);
|
|
679 if (arg0.type.ty != TY.Tarray ||
|
|
680 arg0.type.nextOf().ty != TY.Tarray ||
|
|
681 arg0.type.nextOf().nextOf().ty != TY.Tchar ||
|
|
682 arg0.storageClass & (STC.STCout | STC.STCref | STC.STClazy))
|
|
683 goto Lmainerr;
|
|
684 break;
|
|
685 }
|
|
686
|
|
687 default:
|
|
688 goto Lmainerr;
|
|
689 }
|
|
690
|
|
691 if (f.nextOf().ty != TY.Tint32 && f.nextOf().ty != TY.Tvoid)
|
|
692 error("must return int or void, not %s", f.nextOf().toChars());
|
|
693 if (f.varargs)
|
|
694 {
|
|
695 Lmainerr:
|
|
696 error("parameters must be main() or main(char[][] args)");
|
|
697 }
|
|
698 }
|
|
699
|
|
700 if (ident == Id.assign && (sd || cd))
|
|
701 { // Disallow identity assignment operator.
|
|
702
|
|
703 // opAssign(...)
|
|
704 if (nparams == 0)
|
|
705 { if (f.varargs == 1)
|
|
706 goto Lassignerr;
|
|
707 }
|
|
708 else
|
|
709 {
|
|
710 Argument arg0 = Argument.getNth(f.parameters, 0);
|
|
711 Type t0 = arg0.type.toBasetype();
|
|
712 Type tb = sd ? sd.type : cd.type;
|
|
713 if (arg0.type.implicitConvTo(tb) ||
|
|
714 (sd && t0.ty == TY.Tpointer && t0.nextOf().implicitConvTo(tb))
|
|
715 )
|
|
716 {
|
|
717 if (nparams == 1)
|
|
718 goto Lassignerr;
|
|
719 Argument arg1 = Argument.getNth(f.parameters, 1);
|
|
720 if (arg1.defaultArg)
|
|
721 goto Lassignerr;
|
|
722 }
|
|
723 }
|
|
724 }
|
|
725
|
|
726 Ldone:
|
|
727 /* Save scope for possible later use (if we need the
|
|
728 * function internals)
|
|
729 */
|
|
730 scope_ = new Scope(sc);
|
|
731 scope_.setNoFree();
|
|
732 return;
|
|
733
|
|
734 Lassignerr:
|
|
735 if (sd)
|
|
736 {
|
|
737 sd.hasIdentityAssign = 1; // don't need to generate it
|
|
738 goto Ldone;
|
|
739 }
|
|
740 error("identity assignment operator overload is illegal");
|
|
741 }
|
|
742
|
|
743 void semantic2(Scope sc)
|
|
744 {
|
|
745 }
|
|
746
|
|
747 // Do the semantic analysis on the internals of the function.
|
|
748 void semantic3(Scope sc)
|
|
749 {
|
|
750 TypeFunction f;
|
|
751 VarDeclaration argptr = null;
|
|
752 VarDeclaration _arguments = null;
|
|
753
|
|
754 if (!parent)
|
|
755 {
|
|
756 if (global.errors)
|
|
757 return;
|
|
758 //printf("FuncDeclaration.semantic3(%s '%s', sc = %p)\n", kind(), toChars(), sc);
|
|
759 assert(0);
|
|
760 }
|
|
761 //printf("FuncDeclaration.semantic3('%s.%s', sc = %p, loc = %s)\n", parent.toChars(), toChars(), sc, loc.toChars());
|
|
762 //fflush(stdout);
|
|
763 //printf("storage class = x%x %x\n", sc.stc, storage_class);
|
|
764 //{ static int x; if (++x == 2) *(char*)0=0; }
|
|
765 //printf("\tlinkage = %d\n", sc.linkage);
|
|
766
|
|
767 //printf(" sc.incontract = %d\n", sc.incontract);
|
|
768 if (semanticRun >= 3)
|
|
769 return;
|
|
770 semanticRun = 3;
|
|
771
|
|
772 if (!type || type.ty != TY.Tfunction)
|
|
773 return;
|
|
774 f = cast(TypeFunction)(type);
|
|
775
|
|
776 // Check the 'throws' clause
|
|
777 if (fthrows)
|
|
778 {
|
|
779 for (int i = 0; i < fthrows.dim; i++)
|
|
780 {
|
|
781 Type t = cast(Type)fthrows.data[i];
|
|
782
|
|
783 t = t.semantic(loc, sc);
|
|
784 if (!t.isClassHandle())
|
|
785 error("can only throw classes, not %s", t.toChars());
|
|
786 }
|
|
787 }
|
|
788
|
|
789 if (fbody || frequire)
|
|
790 {
|
|
791 /* Symbol table into which we place parameters and nested functions,
|
|
792 * solely to diagnose name collisions.
|
|
793 */
|
|
794 localsymtab = new DsymbolTable();
|
|
795
|
|
796 // Establish function scope
|
|
797 ScopeDsymbol ss = new ScopeDsymbol();
|
|
798 ss.parent = sc.scopesym;
|
|
799 Scope sc2 = sc.push(ss);
|
|
800 sc2.func = this;
|
|
801 sc2.parent = this;
|
|
802 sc2.callSuper = 0;
|
|
803 sc2.sbreak = null;
|
|
804 sc2.scontinue = null;
|
|
805 sc2.sw = null;
|
|
806 sc2.fes = fes;
|
|
807 sc2.linkage = LINK.LINKd;
|
|
808 sc2.stc &= ~(STC.STCauto | STC.STCscope | STC.STCstatic | STC.STCabstract | STC.STCdeprecated | STC.STC_TYPECTOR | STC.STCfinal | STC.STCtls | STC.STCgshared | STC.STCref);
|
|
809 sc2.protection = PROT.PROTpublic;
|
|
810 sc2.explicitProtection = 0;
|
|
811 sc2.structalign = 8;
|
|
812 sc2.incontract = 0;
|
|
813 sc2.tf = null;
|
|
814 sc2.noctor = 0;
|
|
815
|
|
816 // Declare 'this'
|
|
817 AggregateDeclaration ad = isThis();
|
|
818 if (ad)
|
|
819 { VarDeclaration v;
|
|
820
|
|
821 if (isFuncLiteralDeclaration() && isNested())
|
|
822 {
|
|
823 error("literals cannot be class members");
|
|
824 return;
|
|
825 }
|
|
826 else
|
|
827 {
|
|
828 assert(!isNested()); // can't be both member and nested
|
|
829 assert(ad.handle);
|
|
830 Type thandle = ad.handle;
|
|
831 version (STRUCTTHISREF) {
|
|
832 thandle = thandle.addMod(type.mod);
|
|
833 thandle = thandle.addStorageClass(storage_class);
|
|
834 if (isPure())
|
|
835 thandle = thandle.addMod(MOD.MODconst);
|
|
836 } else {
|
|
837 if (storage_class & STC.STCconst || type.isConst())
|
|
838 {
|
|
839 assert(0); // BUG: shared not handled
|
|
840 if (thandle.ty == TY.Tclass)
|
|
841 thandle = thandle.constOf();
|
|
842 else
|
|
843 { assert(thandle.ty == TY.Tpointer);
|
|
844 thandle = thandle.nextOf().constOf().pointerTo();
|
|
845 }
|
|
846 }
|
|
847 else if (storage_class & STC.STCimmutable || type.isInvariant())
|
|
848 {
|
|
849 if (thandle.ty == TY.Tclass)
|
|
850 thandle = thandle.invariantOf();
|
|
851 else
|
|
852 { assert(thandle.ty == TY.Tpointer);
|
|
853 thandle = thandle.nextOf().invariantOf().pointerTo();
|
|
854 }
|
|
855 }
|
|
856 else if (storage_class & STC.STCshared || type.isShared())
|
|
857 {
|
|
858 assert(0); // not implemented
|
|
859 }
|
|
860 }
|
|
861 v = new ThisDeclaration(loc, thandle);
|
|
862 v.storage_class |= STC.STCparameter;
|
|
863 version (STRUCTTHISREF) {
|
|
864 if (thandle.ty == TY.Tstruct)
|
|
865 v.storage_class |= STC.STCref;
|
|
866 }
|
|
867 v.semantic(sc2);
|
|
868 if (!sc2.insert(v))
|
|
869 assert(0);
|
|
870 v.parent = this;
|
|
871 vthis = v;
|
|
872 }
|
|
873 }
|
|
874 else if (isNested())
|
|
875 {
|
|
876 /* The 'this' for a nested function is the link to the
|
|
877 * enclosing function's stack frame.
|
|
878 * Note that nested functions and member functions are disjoint.
|
|
879 */
|
|
880 VarDeclaration v = new ThisDeclaration(loc, Type.tvoid.pointerTo());
|
|
881 v.storage_class |= STC.STCparameter;
|
|
882 v.semantic(sc2);
|
|
883 if (!sc2.insert(v))
|
|
884 assert(0);
|
|
885 v.parent = this;
|
|
886 vthis = v;
|
|
887 }
|
|
888
|
|
889 // Declare hidden variable _arguments[] and _argptr
|
|
890 if (f.varargs == 1)
|
|
891 {
|
|
892 version (TARGET_NET) {
|
|
893 varArgs(sc2, f, argptr, _arguments);
|
|
894 } else {
|
|
895 Type t;
|
|
896
|
|
897 if (f.linkage == LINK.LINKd)
|
|
898 {
|
|
899 // Declare _arguments[]
|
|
900 version (BREAKABI) {
|
|
901 v_arguments = new VarDeclaration(Loc(0), Type.typeinfotypelist.type, Id._arguments_typeinfo, null);
|
|
902 v_arguments.storage_class = STCparameter;
|
|
903 v_arguments.semantic(sc2);
|
|
904 sc2.insert(v_arguments);
|
|
905 v_arguments.parent = this;
|
|
906
|
|
907 //t = Type.typeinfo.type.constOf().arrayOf();
|
|
908 t = Type.typeinfo.type.arrayOf();
|
|
909 _arguments = new VarDeclaration(Loc(0), t, Id._arguments, null);
|
|
910 _arguments.semantic(sc2);
|
|
911 sc2.insert(_arguments);
|
|
912 _arguments.parent = this;
|
|
913 } else {
|
|
914 t = Type.typeinfo.type.arrayOf();
|
|
915 v_arguments = new VarDeclaration(Loc(0), t, Id._arguments, null);
|
|
916 v_arguments.storage_class = STC.STCparameter | STC.STCin;
|
|
917 v_arguments.semantic(sc2);
|
|
918 sc2.insert(v_arguments);
|
|
919 v_arguments.parent = this;
|
|
920 }
|
|
921 }
|
|
922 if (f.linkage == LINK.LINKd || (parameters && parameters.dim))
|
|
923 { // Declare _argptr
|
|
924 version (IN_GCC) {
|
|
925 t = d_gcc_builtin_va_list_d_type;
|
|
926 } else {
|
|
927 t = Type.tvoid.pointerTo();
|
|
928 }
|
|
929 argptr = new VarDeclaration(Loc(0), t, Id._argptr, null);
|
|
930 argptr.semantic(sc2);
|
|
931 sc2.insert(argptr);
|
|
932 argptr.parent = this;
|
|
933 }
|
|
934 }
|
|
935 }
|
|
936
|
|
937 // Propagate storage class from tuple parameters to their element-parameters.
|
|
938 if (f.parameters)
|
|
939 {
|
|
940 for (size_t i = 0; i < f.parameters.dim; i++)
|
|
941 { Argument arg = cast(Argument)f.parameters.data[i];
|
|
942
|
|
943 //printf("[%d] arg.type.ty = %d %s\n", i, arg.type.ty, arg.type.toChars());
|
|
944 if (arg.type.ty == TY.Ttuple)
|
|
945 { TypeTuple t = cast(TypeTuple)arg.type;
|
|
946 size_t dim = Argument.dim(t.arguments);
|
|
947 for (size_t j = 0; j < dim; j++)
|
|
948 { Argument narg = Argument.getNth(t.arguments, j);
|
|
949 narg.storageClass = arg.storageClass;
|
|
950 }
|
|
951 }
|
|
952 }
|
|
953 }
|
|
954
|
|
955 /* Declare all the function parameters as variables
|
|
956 * and install them in parameters[]
|
|
957 */
|
|
958 size_t nparams = Argument.dim(f.parameters);
|
|
959 if (nparams)
|
|
960 { /* parameters[] has all the tuples removed, as the back end
|
|
961 * doesn't know about tuples
|
|
962 */
|
|
963 parameters = new Dsymbols();
|
|
964 parameters.reserve(nparams);
|
|
965 for (size_t i = 0; i < nparams; i++)
|
|
966 {
|
|
967 Argument arg = Argument.getNth(f.parameters, i);
|
|
968 Identifier id = arg.ident;
|
|
969 if (!id)
|
|
970 {
|
|
971 /* Generate identifier for un-named parameter,
|
|
972 * because we need it later on.
|
|
973 */
|
|
974 arg.ident = id = Identifier.generateId("_param_", i);
|
|
975 }
|
|
976 Type vtype = arg.type;
|
|
977 if (isPure())
|
|
978 vtype = vtype.addMod(MOD.MODconst);
|
|
979 VarDeclaration v = new VarDeclaration(loc, vtype, id, null);
|
|
980 //printf("declaring parameter %s of type %s\n", v.toChars(), v.type.toChars());
|
|
981 v.storage_class |= STC.STCparameter;
|
|
982 if (f.varargs == 2 && i + 1 == nparams)
|
|
983 v.storage_class |= STC.STCvariadic;
|
|
984 v.storage_class |= arg.storageClass & (STC.STCin | STC.STCout | STC.STCref | STC.STClazy | STC.STCfinal | STC.STC_TYPECTOR | STC.STCnodtor);
|
|
985 v.semantic(sc2);
|
|
986 if (!sc2.insert(v))
|
|
987 error("parameter %s.%s is already defined", toChars(), v.toChars());
|
|
988 else
|
|
989 parameters.push(cast(void*)v);
|
|
990 localsymtab.insert(v);
|
|
991 v.parent = this;
|
|
992 }
|
|
993 }
|
|
994
|
|
995 // Declare the tuple symbols and put them in the symbol table,
|
|
996 // but not in parameters[].
|
|
997 if (f.parameters)
|
|
998 {
|
|
999 for (size_t i = 0; i < f.parameters.dim; i++)
|
|
1000 { Argument arg = cast(Argument)f.parameters.data[i];
|
|
1001
|
|
1002 if (!arg.ident)
|
|
1003 continue; // never used, so ignore
|
|
1004 if (arg.type.ty == TY.Ttuple)
|
|
1005 { TypeTuple t = cast(TypeTuple)arg.type;
|
|
1006 size_t dim = Argument.dim(t.arguments);
|
|
1007 Objects exps = new Objects();
|
|
1008 exps.setDim(dim);
|
|
1009 for (size_t j = 0; j < dim; j++)
|
|
1010 { Argument narg = Argument.getNth(t.arguments, j);
|
|
1011 assert(narg.ident);
|
|
1012 VarDeclaration v = sc2.search(Loc(0), narg.ident, null).isVarDeclaration();
|
|
1013 assert(v);
|
|
1014 Expression e = new VarExp(v.loc, v);
|
|
1015 exps.data[j] = cast(void*)e;
|
|
1016 }
|
|
1017 assert(arg.ident);
|
|
1018 TupleDeclaration v = new TupleDeclaration(loc, arg.ident, exps);
|
|
1019 //printf("declaring tuple %s\n", v.toChars());
|
|
1020 v.isexp = 1;
|
|
1021 if (!sc2.insert(v))
|
|
1022 error("parameter %s.%s is already defined", toChars(), v.toChars());
|
|
1023 localsymtab.insert(v);
|
|
1024 v.parent = this;
|
|
1025 }
|
|
1026 }
|
|
1027 }
|
|
1028
|
|
1029 /* Do the semantic analysis on the [in] preconditions and
|
|
1030 * [out] postconditions.
|
|
1031 */
|
|
1032 sc2.incontract++;
|
|
1033
|
|
1034 if (frequire)
|
|
1035 { /* frequire is composed of the [in] contracts
|
|
1036 */
|
|
1037 // BUG: need to error if accessing out parameters
|
|
1038 // BUG: need to treat parameters as const
|
|
1039 // BUG: need to disallow returns and throws
|
|
1040 // BUG: verify that all in and ref parameters are read
|
|
1041 frequire = frequire.semantic(sc2);
|
|
1042 labtab = null; // so body can't refer to labels
|
|
1043 }
|
|
1044
|
|
1045 if (fensure || addPostInvariant())
|
|
1046 { /* fensure is composed of the [out] contracts
|
|
1047 */
|
|
1048 ScopeDsymbol sym = new ScopeDsymbol();
|
|
1049 sym.parent = sc2.scopesym;
|
|
1050 sc2 = sc2.push(sym);
|
|
1051
|
|
1052 assert(type.nextOf());
|
|
1053 if (type.nextOf().ty == TY.Tvoid)
|
|
1054 {
|
|
1055 if (outId)
|
|
1056 error("void functions have no result");
|
|
1057 }
|
|
1058 else
|
|
1059 {
|
|
1060 if (!outId)
|
|
1061 outId = Id.result; // provide a default
|
|
1062 }
|
|
1063
|
|
1064 if (outId)
|
|
1065 { // Declare result variable
|
|
1066 VarDeclaration v;
|
|
1067 Loc loc = this.loc;
|
|
1068
|
|
1069 if (fensure)
|
|
1070 loc = fensure.loc;
|
|
1071
|
|
1072 v = new VarDeclaration(loc, type.nextOf(), outId, null);
|
|
1073 v.noauto = true;
|
|
1074 version (DMDV2) {
|
|
1075 if (f.isref)
|
|
1076 {
|
|
1077 v.storage_class |= STC.STCref | STC.STCforeach;
|
|
1078 }
|
|
1079 }
|
|
1080 sc2.incontract--;
|
|
1081 v.semantic(sc2);
|
|
1082 sc2.incontract++;
|
|
1083 if (!sc2.insert(v))
|
|
1084 error("out result %s is already defined", v.toChars());
|
|
1085 v.parent = this;
|
|
1086 vresult = v;
|
|
1087
|
|
1088 // vresult gets initialized with the function return value
|
|
1089 // in ReturnStatement.semantic()
|
|
1090 }
|
|
1091
|
|
1092 // BUG: need to treat parameters as const
|
|
1093 // BUG: need to disallow returns and throws
|
|
1094 if (fensure)
|
|
1095 { fensure = fensure.semantic(sc2);
|
|
1096 labtab = null; // so body can't refer to labels
|
|
1097 }
|
|
1098
|
|
1099 if (!global.params.useOut)
|
|
1100 { fensure = null; // discard
|
|
1101 vresult = null;
|
|
1102 }
|
|
1103
|
|
1104 // Postcondition invariant
|
|
1105 if (addPostInvariant())
|
|
1106 {
|
|
1107 Expression e = null;
|
|
1108 if (isCtorDeclaration())
|
|
1109 {
|
|
1110 // Call invariant directly only if it exists
|
|
1111 InvariantDeclaration inv = ad.inv;
|
|
1112 ClassDeclaration cd = ad.isClassDeclaration();
|
|
1113
|
|
1114 while (!inv && cd)
|
|
1115 {
|
|
1116 cd = cd.baseClass;
|
|
1117 if (!cd)
|
|
1118 break;
|
|
1119 inv = cd.inv;
|
|
1120 }
|
|
1121 if (inv)
|
|
1122 {
|
|
1123 e = new DsymbolExp(Loc(0), inv);
|
|
1124 e = new CallExp(Loc(0), e);
|
|
1125 e = e.semantic(sc2);
|
|
1126 }
|
|
1127 }
|
|
1128 else
|
|
1129 { // Call invariant virtually
|
|
1130 Expression v = new ThisExp(Loc(0));
|
|
1131 v.type = vthis.type;
|
|
1132 version (STRUCTTHISREF) {
|
|
1133 if (ad.isStructDeclaration())
|
|
1134 v = v.addressOf(sc);
|
|
1135 }
|
|
1136 e = new AssertExp(Loc(0), v);
|
|
1137 }
|
|
1138 if (e)
|
|
1139 {
|
|
1140 ExpStatement s = new ExpStatement(Loc(0), e);
|
|
1141 if (fensure)
|
|
1142 fensure = new CompoundStatement(Loc(0), s, fensure);
|
|
1143 else
|
|
1144 fensure = s;
|
|
1145 }
|
|
1146 }
|
|
1147
|
|
1148 if (fensure)
|
|
1149 { returnLabel = new LabelDsymbol(Id.returnLabel);
|
|
1150 LabelStatement ls = new LabelStatement(Loc(0), Id.returnLabel, fensure);
|
|
1151 ls.isReturnLabel = 1;
|
|
1152 returnLabel.statement = ls;
|
|
1153 }
|
|
1154 sc2 = sc2.pop();
|
|
1155 }
|
|
1156
|
|
1157 sc2.incontract--;
|
|
1158
|
|
1159 if (fbody)
|
|
1160 { ClassDeclaration cd = isClassMember();
|
|
1161
|
|
1162 /* If this is a class constructor
|
|
1163 */
|
|
1164 if (isCtorDeclaration() && cd)
|
|
1165 {
|
|
1166 for (int i = 0; i < cd.fields.dim; i++)
|
|
1167 { VarDeclaration v = cast(VarDeclaration)cd.fields.data[i];
|
|
1168
|
|
1169 v.ctorinit = 0;
|
|
1170 }
|
|
1171 }
|
|
1172
|
|
1173 if (inferRetType || f.retStyle() != RET.RETstack)
|
|
1174 nrvo_can = 0;
|
|
1175
|
|
1176 fbody = fbody.semantic(sc2);
|
|
1177 if (!fbody)
|
|
1178 fbody = new CompoundStatement(Loc(0), new Statements());
|
|
1179
|
|
1180 if (inferRetType)
|
|
1181 { // If no return type inferred yet, then infer a void
|
|
1182 if (!type.nextOf())
|
|
1183 {
|
|
1184 (cast(TypeFunction)type).next = Type.tvoid;
|
|
1185 type = type.semantic(loc, sc);
|
|
1186 }
|
|
1187 f = cast(TypeFunction)type;
|
|
1188 }
|
|
1189
|
|
1190 if (isStaticCtorDeclaration())
|
|
1191 {
|
|
1192 /* It's a static constructor. Ensure that all
|
|
1193 * ctor consts were initialized.
|
|
1194 */
|
|
1195
|
|
1196 Dsymbol p = toParent();
|
|
1197 ScopeDsymbol add = p.isScopeDsymbol();
|
|
1198 if (!add)
|
|
1199 {
|
|
1200 error("static constructor can only be member of struct/class/module, not %s %s", p.kind(), p.toChars());
|
|
1201 }
|
|
1202 else
|
|
1203 {
|
|
1204 for (int i = 0; i < add.members.dim; i++)
|
|
1205 { Dsymbol s = cast(Dsymbol)add.members.data[i];
|
|
1206
|
|
1207 s.checkCtorConstInit();
|
|
1208 }
|
|
1209 }
|
|
1210 }
|
|
1211
|
|
1212 if (isCtorDeclaration() && cd)
|
|
1213 {
|
|
1214 //printf("callSuper = x%x\n", sc2.callSuper);
|
|
1215
|
|
1216 // Verify that all the ctorinit fields got initialized
|
|
1217 if (!(sc2.callSuper & CSX.CSXthis_ctor))
|
|
1218 {
|
|
1219 for (int i = 0; i < cd.fields.dim; i++)
|
|
1220 { VarDeclaration v = cast(VarDeclaration)cd.fields.data[i];
|
|
1221
|
|
1222 if (v.ctorinit == 0 && v.isCtorinit())
|
|
1223 error("missing initializer for final field %s", v.toChars());
|
|
1224 }
|
|
1225 }
|
|
1226
|
|
1227 if (!(sc2.callSuper & CSX.CSXany_ctor) &&
|
|
1228 cd.baseClass && cd.baseClass.ctor)
|
|
1229 {
|
|
1230 sc2.callSuper = 0;
|
|
1231
|
|
1232 // Insert implicit super() at start of fbody
|
|
1233 Expression e1 = new SuperExp(Loc(0));
|
|
1234 Expression e = new CallExp(Loc(0), e1);
|
|
1235
|
|
1236 e = e.trySemantic(sc2);
|
|
1237 if (!e)
|
|
1238 error("no match for implicit super() call in constructor");
|
|
1239 else
|
|
1240 {
|
|
1241 Statement s = new ExpStatement(Loc(0), e);
|
|
1242 fbody = new CompoundStatement(Loc(0), s, fbody);
|
|
1243 }
|
|
1244 }
|
|
1245 }
|
|
1246 else if (fes)
|
|
1247 { // For foreach(){} body, append a return 0;
|
|
1248 Expression e = new IntegerExp(0);
|
|
1249 Statement s = new ReturnStatement(Loc(0), e);
|
|
1250 fbody = new CompoundStatement(Loc(0), fbody, s);
|
|
1251 assert(!returnLabel);
|
|
1252 }
|
|
1253 else if (!hasReturnExp && type.nextOf().ty != TY.Tvoid)
|
|
1254 error("expected to return a value of type %s", type.nextOf().toChars());
|
|
1255 else if (!inlineAsm)
|
|
1256 {
|
|
1257 version (DMDV2) {
|
|
1258 BE blockexit = fbody ? fbody.blockExit() : BE.BEfallthru;
|
|
1259 if (f.isnothrow && blockexit & BE.BEthrow)
|
|
1260 error("'%s' is nothrow yet may throw", toChars());
|
|
1261
|
|
1262 int offend = blockexit & BE.BEfallthru;
|
|
1263 }
|
|
1264 if (type.nextOf().ty == TY.Tvoid)
|
|
1265 {
|
|
1266 if (offend && isMain())
|
|
1267 { // Add a return 0; statement
|
|
1268 Statement s = new ReturnStatement(Loc(0), new IntegerExp(0));
|
|
1269 fbody = new CompoundStatement(Loc(0), fbody, s);
|
|
1270 }
|
|
1271 }
|
|
1272 else
|
|
1273 {
|
|
1274 if (offend)
|
|
1275 {
|
|
1276 Expression e;
|
|
1277 version (DMDV1) {
|
|
1278 warning(loc, "no return exp; or assert(0); at end of function");
|
|
1279 } else {
|
|
1280 error("no return exp; or assert(0); at end of function");
|
|
1281 }
|
|
1282 if (global.params.useAssert &&
|
|
1283 !global.params.useInline)
|
|
1284 { /* Add an assert(0, msg); where the missing return
|
|
1285 * should be.
|
|
1286 */
|
|
1287 e = new AssertExp(
|
|
1288 endloc,
|
|
1289 new IntegerExp(0),
|
|
1290 new StringExp(loc, "missing return expression")
|
|
1291 );
|
|
1292 }
|
|
1293 else
|
|
1294 e = new HaltExp(endloc);
|
|
1295
|
|
1296 e = new CommaExp(Loc(0), e, type.nextOf().defaultInit(Loc(0)));
|
|
1297 e = e.semantic(sc2);
|
|
1298 Statement s = new ExpStatement(Loc(0), e);
|
|
1299 fbody = new CompoundStatement(Loc(0), fbody, s);
|
|
1300 }
|
|
1301 }
|
|
1302 }
|
|
1303 }
|
|
1304
|
|
1305 {
|
|
1306 Statements a = new Statements();
|
|
1307
|
|
1308 // Merge in initialization of 'out' parameters
|
|
1309 if (parameters)
|
|
1310 { for (size_t i = 0; i < parameters.dim; i++)
|
|
1311 {
|
|
1312 VarDeclaration v = cast(VarDeclaration)parameters.data[i];
|
|
1313 if (v.storage_class & STC.STCout)
|
|
1314 {
|
|
1315 assert(v.init);
|
|
1316 ExpInitializer ie = v.init.isExpInitializer();
|
|
1317 assert(ie);
|
|
1318 a.push(cast(void*)new ExpStatement(Loc(0), ie.exp));
|
|
1319 }
|
|
1320 }
|
|
1321 }
|
|
1322
|
|
1323 if (argptr)
|
|
1324 { // Initialize _argptr to point past non-variadic arg
|
|
1325 version (IN_GCC) {
|
|
1326 // Handled in FuncDeclaration.toObjFile
|
|
1327 v_argptr = argptr;
|
|
1328 v_argptr.init = new VoidInitializer(loc);
|
|
1329 } else {
|
|
1330 Expression e1;
|
|
1331 Expression e;
|
|
1332 Type t = argptr.type;
|
|
1333 VarDeclaration p;
|
|
1334 uint offset;
|
|
1335
|
|
1336 e1 = new VarExp(Loc(0), argptr);
|
|
1337 if (parameters && parameters.dim)
|
|
1338 p = cast(VarDeclaration)parameters.data[parameters.dim - 1];
|
|
1339 else
|
|
1340 p = v_arguments; // last parameter is _arguments[]
|
|
1341 offset = cast(uint)p.type.size(); ///
|
|
1342 offset = (offset + 3) & ~3; // assume stack aligns on 4
|
|
1343 e = new SymOffExp(Loc(0), p, offset);
|
|
1344 e = new AssignExp(Loc(0), e1, e);
|
|
1345 e.type = t;
|
|
1346 a.push(cast(void*)new ExpStatement(Loc(0), e));
|
|
1347 }
|
|
1348 }
|
|
1349
|
|
1350 if (_arguments)
|
|
1351 {
|
|
1352 /* Advance to elements[] member of TypeInfo_Tuple with:
|
|
1353 * _arguments = v_arguments.elements;
|
|
1354 */
|
|
1355 Expression e = new VarExp(Loc(0), v_arguments);
|
|
1356 e = new DotIdExp(Loc(0), e, Id.elements);
|
|
1357 Expression e1 = new VarExp(Loc(0), _arguments);
|
|
1358 e = new AssignExp(Loc(0), e1, e);
|
|
1359 e.op = TOK.TOKconstruct;
|
|
1360 e = e.semantic(sc2);
|
|
1361 a.push(cast(void*)new ExpStatement(Loc(0), e));
|
|
1362 }
|
|
1363
|
|
1364 // Merge contracts together with body into one compound statement
|
|
1365
|
|
1366 version (_DH) {
|
|
1367 if (frequire && global.params.useIn)
|
|
1368 { frequire.incontract = 1;
|
|
1369 a.push(frequire);
|
|
1370 }
|
|
1371 } else {
|
|
1372 if (frequire && global.params.useIn)
|
|
1373 a.push(cast(void*)frequire);
|
|
1374 }
|
|
1375
|
|
1376 // Precondition invariant
|
|
1377 if (addPreInvariant())
|
|
1378 {
|
|
1379 Expression e = null;
|
|
1380 if (isDtorDeclaration())
|
|
1381 {
|
|
1382 // Call invariant directly only if it exists
|
|
1383 InvariantDeclaration inv = ad.inv;
|
|
1384 ClassDeclaration cd = ad.isClassDeclaration();
|
|
1385
|
|
1386 while (!inv && cd)
|
|
1387 {
|
|
1388 cd = cd.baseClass;
|
|
1389 if (!cd)
|
|
1390 break;
|
|
1391 inv = cd.inv;
|
|
1392 }
|
|
1393 if (inv)
|
|
1394 {
|
|
1395 e = new DsymbolExp(Loc(0), inv);
|
|
1396 e = new CallExp(Loc(0), e);
|
|
1397 e = e.semantic(sc2);
|
|
1398 }
|
|
1399 }
|
|
1400 else
|
|
1401 { // Call invariant virtually
|
|
1402 Expression v = new ThisExp(Loc(0));
|
|
1403 v.type = vthis.type;
|
|
1404 version (STRUCTTHISREF) {
|
|
1405 if (ad.isStructDeclaration())
|
|
1406 v = v.addressOf(sc);
|
|
1407 }
|
|
1408 Expression se = new StringExp(Loc(0), "null this");
|
|
1409 se = se.semantic(sc);
|
|
1410 se.type = Type.tchar.arrayOf();
|
|
1411 e = new AssertExp(loc, v, se);
|
|
1412 }
|
|
1413 if (e)
|
|
1414 {
|
|
1415 ExpStatement s = new ExpStatement(Loc(0), e);
|
|
1416 a.push(cast(void*)s);
|
|
1417 }
|
|
1418 }
|
|
1419
|
|
1420 if (fbody)
|
|
1421 a.push(cast(void*)fbody);
|
|
1422
|
|
1423 if (fensure)
|
|
1424 {
|
|
1425 a.push(cast(void*)returnLabel.statement);
|
|
1426
|
|
1427 if (type.nextOf().ty != TY.Tvoid)
|
|
1428 {
|
|
1429 // Create: return vresult;
|
|
1430 assert(vresult);
|
|
1431 Expression e = new VarExp(Loc(0), vresult);
|
|
1432 if (tintro)
|
|
1433 { e = e.implicitCastTo(sc, tintro.nextOf());
|
|
1434 e = e.semantic(sc);
|
|
1435 }
|
|
1436 ReturnStatement s = new ReturnStatement(Loc(0), e);
|
|
1437 a.push(cast(void*)s);
|
|
1438 }
|
|
1439 }
|
|
1440
|
|
1441 fbody = new CompoundStatement(Loc(0), a);
|
|
1442 version (DMDV2) {
|
|
1443 /* Append destructor calls for parameters as finally blocks.
|
|
1444 */
|
|
1445 if (parameters)
|
|
1446 { for (size_t i = 0; i < parameters.dim; i++)
|
|
1447 {
|
|
1448 VarDeclaration v = cast(VarDeclaration)parameters.data[i];
|
|
1449
|
|
1450 if (v.storage_class & (STC.STCref | STC.STCout))
|
|
1451 continue;
|
|
1452
|
|
1453 /* Don't do this for static arrays, since static
|
|
1454 * arrays are called by reference. Remove this
|
|
1455 * when we change them to call by value.
|
|
1456 */
|
|
1457 if (v.type.toBasetype().ty == TY.Tsarray)
|
|
1458 continue;
|
|
1459
|
|
1460 Expression e = v.callAutoDtor(sc);
|
|
1461 if (e)
|
|
1462 { Statement s = new ExpStatement(Loc(0), e);
|
|
1463 s = s.semantic(sc);
|
|
1464 if (fbody.blockExit() == BE.BEfallthru)
|
|
1465 fbody = new CompoundStatement(Loc(0), fbody, s);
|
|
1466 else
|
|
1467 fbody = new TryFinallyStatement(Loc(0), fbody, s);
|
|
1468 }
|
|
1469 }
|
|
1470 }
|
|
1471 }
|
|
1472
|
|
1473 static if (true) {
|
|
1474 if (isSynchronized())
|
|
1475 { /* Wrap the entire function body in a synchronized statement
|
|
1476 */
|
|
1477 ClassDeclaration cd = parent.isClassDeclaration();
|
|
1478 if (cd)
|
|
1479 {
|
|
1480 ///version (TARGET_WINDOS) {
|
|
1481 if (/*config.flags2 & CFG2.CFG2seh &&*/ // always on for WINDOS
|
|
1482 !isStatic() && !fbody.usesEH())
|
|
1483 {
|
|
1484 /* The back end uses the "jmonitor" hack for syncing;
|
|
1485 * no need to do the sync at this level.
|
|
1486 */
|
|
1487 }
|
|
1488 else
|
|
1489 ///}
|
|
1490 {
|
|
1491 Expression vsync;
|
|
1492 if (isStatic())
|
|
1493 {
|
|
1494 // The monitor is in the ClassInfo
|
|
1495 vsync = new DotIdExp(loc, new DsymbolExp(loc, cd), Id.classinfo_);
|
|
1496 }
|
|
1497 else
|
|
1498 { // 'this' is the monitor
|
|
1499 vsync = new VarExp(loc, vthis);
|
|
1500 }
|
|
1501 fbody = new PeelStatement(fbody); // don't redo semantic()
|
|
1502 fbody = new SynchronizedStatement(loc, vsync, fbody);
|
|
1503 fbody = fbody.semantic(sc2);
|
|
1504 }
|
|
1505 }
|
|
1506 else
|
|
1507 {
|
|
1508 error("synchronized function %s must be a member of a class", toChars());
|
|
1509 }
|
|
1510 }
|
|
1511 }
|
|
1512 }
|
|
1513
|
|
1514 sc2.callSuper = 0;
|
|
1515 sc2.pop();
|
|
1516 }
|
|
1517 semanticRun = 4;
|
|
1518 }
|
|
1519
|
|
1520 // called from semantic3
|
|
1521 void varArgs(Scope sc, TypeFunction, ref VarDeclaration, ref VarDeclaration)
|
|
1522 {
|
|
1523 assert(false);
|
|
1524 }
|
|
1525
|
|
1526 void toCBuffer(OutBuffer buf, HdrGenState* hgs)
|
|
1527 {
|
|
1528 assert(false);
|
|
1529 }
|
|
1530
|
|
1531 void bodyToCBuffer(OutBuffer buf, HdrGenState* hgs)
|
|
1532 {
|
|
1533 assert(false);
|
|
1534 }
|
|
1535
|
|
1536 /****************************************************
|
|
1537 * Determine if 'this' overrides fd.
|
|
1538 * Return true if it does.
|
|
1539 */
|
|
1540 bool overrides(FuncDeclaration fd)
|
|
1541 {
|
|
1542 bool result = false;
|
|
1543
|
|
1544 if (fd.ident == ident)
|
|
1545 {
|
|
1546 int cov = type.covariant(fd.type);
|
|
1547 if (cov)
|
|
1548 {
|
|
1549 ClassDeclaration cd1 = toParent().isClassDeclaration();
|
|
1550 ClassDeclaration cd2 = fd.toParent().isClassDeclaration();
|
|
1551
|
|
1552 if (cd1 && cd2 && cd2.isBaseOf(cd1, null))
|
|
1553 result = true;
|
|
1554 }
|
|
1555 }
|
|
1556 return result;
|
|
1557 }
|
|
1558
|
|
1559 /*************************************************
|
|
1560 * Find index of function in vtbl[0..dim] that
|
|
1561 * this function overrides.
|
|
1562 * Returns:
|
|
1563 * -1 didn't find one
|
|
1564 * -2 can't determine because of forward references
|
|
1565 */
|
|
1566 int findVtblIndex(Array vtbl, int dim)
|
|
1567 {
|
|
1568 for (int vi = 0; vi < dim; vi++)
|
|
1569 {
|
|
1570 FuncDeclaration fdv = (cast(Dsymbol)vtbl.data[vi]).isFuncDeclaration();
|
|
1571 if (fdv && fdv.ident is ident)
|
|
1572 {
|
|
1573 int cov = type.covariant(fdv.type);
|
|
1574 //printf("\tbaseclass cov = %d\n", cov);
|
|
1575 switch (cov)
|
|
1576 {
|
|
1577 case 0: // types are distinct
|
|
1578 break;
|
|
1579
|
|
1580 case 1:
|
|
1581 return vi;
|
|
1582
|
|
1583 case 2:
|
|
1584 //type.print();
|
|
1585 //fdv.type.print();
|
|
1586 //printf("%s %s\n", type.deco, fdv.type.deco);
|
|
1587 error("of type %s overrides but is not covariant with %s of type %s",
|
|
1588 type.toChars(), fdv.toPrettyChars(), fdv.type.toChars());
|
|
1589 break;
|
|
1590
|
|
1591 case 3:
|
|
1592 return -2; // forward references
|
|
1593 }
|
|
1594 }
|
|
1595 }
|
|
1596 return -1;
|
|
1597 }
|
|
1598
|
|
1599 /****************************************************
|
|
1600 * Overload this FuncDeclaration with the new one f.
|
|
1601 * Return !=0 if successful; i.e. no conflict.
|
|
1602 */
|
|
1603 bool overloadInsert(Dsymbol s)
|
|
1604 {
|
|
1605 FuncDeclaration f;
|
|
1606 AliasDeclaration a;
|
|
1607
|
|
1608 //writef("FuncDeclaration.overloadInsert(%s)\n", s.toChars());
|
|
1609 a = s.isAliasDeclaration();
|
|
1610 if (a)
|
|
1611 {
|
|
1612 if (overnext)
|
|
1613 return overnext.overloadInsert(a);
|
|
1614
|
|
1615 if (!a.aliassym && a.type.ty != TY.Tident && a.type.ty != TY.Tinstance)
|
|
1616 {
|
|
1617 //writef("\ta = '%s'\n", a.type.toChars());
|
|
1618 return false;
|
|
1619 }
|
|
1620 overnext = a;
|
|
1621 //printf("\ttrue: no conflict\n");
|
|
1622 return true;
|
|
1623 }
|
|
1624 f = s.isFuncDeclaration();
|
|
1625 if (!f)
|
|
1626 return false;
|
|
1627
|
|
1628 static if (false) {
|
|
1629 /* Disable this check because:
|
|
1630 * const void foo();
|
|
1631 * semantic() isn't run yet on foo(), so the const hasn't been
|
|
1632 * applied yet.
|
|
1633 */
|
|
1634 if (type)
|
|
1635 {
|
|
1636 printf("type = %s\n", type.toChars());
|
|
1637 printf("f.type = %s\n", f.type.toChars());
|
|
1638 }
|
|
1639 if (type && f.type && // can be null for overloaded constructors
|
|
1640 f.type.covariant(type) &&
|
|
1641 f.type.mod == type.mod &&
|
|
1642 !isFuncAliasDeclaration())
|
|
1643 {
|
|
1644 //printf("\tfalse: conflict %s\n", kind());
|
|
1645 return false;
|
|
1646 }
|
|
1647 }
|
|
1648
|
|
1649 if (overnext)
|
|
1650 return overnext.overloadInsert(f);
|
|
1651 overnext = f;
|
|
1652 //printf("\ttrue: no conflict\n");
|
|
1653 return true;
|
|
1654 }
|
|
1655
|
|
1656 FuncDeclaration overloadExactMatch(Type t)
|
|
1657 {
|
|
1658 Param1 p;
|
|
1659 p.t = t;
|
|
1660 p.f = null;
|
|
1661 overloadApply(this, &p.fp1);
|
|
1662 return p.f;
|
|
1663 }
|
|
1664
|
|
1665 FuncDeclaration overloadResolve(Loc loc, Expression ethis, Expressions arguments, int flags = 0)
|
|
1666 {
|
|
1667 TypeFunction tf;
|
|
1668 Match m;
|
|
1669
|
|
1670 static if (false) {
|
|
1671 printf("FuncDeclaration.overloadResolve('%s')\n", toChars());
|
|
1672 if (arguments)
|
|
1673 {
|
|
1674 int i;
|
|
1675
|
|
1676 for (i = 0; i < arguments.dim; i++)
|
|
1677 {
|
|
1678 Expression arg;
|
|
1679
|
|
1680 arg = cast(Expression)arguments.data[i];
|
|
1681 assert(arg.type);
|
|
1682 printf("\t%s: ", arg.toChars());
|
|
1683 arg.type.print();
|
|
1684 }
|
|
1685 }
|
|
1686 }
|
|
1687
|
|
1688 m.last = MATCH.MATCHnomatch;
|
|
1689 overloadResolveX(&m, this, ethis, arguments);
|
|
1690
|
|
1691 if (m.count == 1) // exactly one match
|
|
1692 {
|
|
1693 return m.lastf;
|
|
1694 }
|
|
1695 else
|
|
1696 {
|
|
1697 scope OutBuffer buf = new OutBuffer();
|
|
1698
|
|
1699 buf.writeByte('(');
|
|
1700 if (arguments)
|
|
1701 {
|
|
1702 HdrGenState hgs;
|
|
1703
|
|
1704 argExpTypesToCBuffer(buf, arguments, &hgs);
|
|
1705 buf.writeByte(')');
|
|
1706 if (ethis)
|
|
1707 ethis.type.modToBuffer(buf);
|
|
1708 }
|
|
1709 else
|
|
1710 buf.writeByte(')');
|
|
1711
|
|
1712 if (m.last == MATCH.MATCHnomatch)
|
|
1713 {
|
|
1714 if (flags & 1) // if do not print error messages
|
|
1715 return null; // no match
|
|
1716
|
|
1717 tf = cast(TypeFunction)type;
|
|
1718
|
|
1719 scope OutBuffer buf2 = new OutBuffer();
|
|
1720 tf.modToBuffer(buf2);
|
|
1721
|
|
1722 //printf("tf = %s, args = %s\n", tf.deco, ((Expression *)arguments.data[0]).type.deco);
|
|
1723 error(loc, "%s%s is not callable using argument types %s",
|
|
1724 Argument.argsTypesToChars(tf.parameters, tf.varargs),
|
|
1725 buf2.toChars(),
|
|
1726 buf.toChars());
|
|
1727 return m.anyf; // as long as it's not a FuncAliasDeclaration
|
|
1728 }
|
|
1729 else
|
|
1730 {
|
|
1731 static if (true) {
|
|
1732 TypeFunction t1 = cast(TypeFunction)m.lastf.type;
|
|
1733 TypeFunction t2 = cast(TypeFunction)m.nextf.type;
|
|
1734
|
|
1735 error(loc, "called with argument types:\n\t(%s)\nmatches both:\n\t%s%s\nand:\n\t%s%s",
|
|
1736 buf.toChars(),
|
|
1737 m.lastf.toPrettyChars(), Argument.argsTypesToChars(t1.parameters, t1.varargs),
|
|
1738 m.nextf.toPrettyChars(), Argument.argsTypesToChars(t2.parameters, t2.varargs));
|
|
1739 } else {
|
|
1740 error(loc, "overloads %s and %s both match argument list for %s",
|
|
1741 m.lastf.type.toChars(),
|
|
1742 m.nextf.type.toChars(),
|
|
1743 m.lastf.toChars());
|
|
1744 }
|
|
1745 return m.lastf;
|
|
1746 }
|
|
1747 }
|
|
1748 }
|
|
1749
|
|
1750 /*************************************
|
|
1751 * Determine partial specialization order of 'this' vs g.
|
|
1752 * This is very similar to TemplateDeclaration.leastAsSpecialized().
|
|
1753 * Returns:
|
|
1754 * match 'this' is at least as specialized as g
|
|
1755 * 0 g is more specialized than 'this'
|
|
1756 */
|
|
1757 MATCH leastAsSpecialized(FuncDeclaration g)
|
|
1758 {
|
|
1759 version (LOG_LEASTAS) {
|
|
1760 printf("%s.leastAsSpecialized(%s)\n", toChars(), g.toChars());
|
|
1761 }
|
|
1762
|
|
1763 /* This works by calling g() with f()'s parameters, and
|
|
1764 * if that is possible, then f() is at least as specialized
|
|
1765 * as g() is.
|
|
1766 */
|
|
1767
|
|
1768 TypeFunction tf = cast(TypeFunction)type;
|
|
1769 TypeFunction tg = cast(TypeFunction)g.type;
|
|
1770 size_t nfparams = Argument.dim(tf.parameters);
|
|
1771 size_t ngparams = Argument.dim(tg.parameters);
|
|
1772 MATCH match = MATCHexact;
|
|
1773
|
|
1774 /* If both functions have a 'this' pointer, and the mods are not
|
|
1775 * the same and g's is not const, then this is less specialized.
|
|
1776 */
|
|
1777 if (needThis() && g.needThis())
|
|
1778 {
|
|
1779 if (tf.mod != tg.mod)
|
|
1780 {
|
|
1781 if (tg.mod == MODconst)
|
|
1782 match = MATCHconst;
|
|
1783 else
|
|
1784 return MATCHnomatch;
|
|
1785 }
|
|
1786 }
|
|
1787
|
|
1788 /* Create a dummy array of arguments out of the parameters to f()
|
|
1789 */
|
|
1790 scope Expressions args = new Expressions();
|
|
1791 args.setDim(nfparams);
|
|
1792 for (int u = 0; u < nfparams; u++)
|
|
1793 {
|
|
1794 Argument p = Argument.getNth(tf.parameters, u);
|
|
1795 Expression e;
|
|
1796 if (p.storageClass & (STCref | STCout))
|
|
1797 {
|
|
1798 e = new IdentifierExp(Loc(0), p.ident);
|
|
1799 e.type = p.type;
|
|
1800 }
|
|
1801 else
|
|
1802 e = p.type.defaultInit(Loc(0));
|
|
1803
|
|
1804 args.data[u] = cast(void*)e;
|
|
1805 }
|
|
1806
|
|
1807 MATCH m = cast(MATCH) tg.callMatch(null, args);
|
|
1808 if (m)
|
|
1809 {
|
|
1810 /* A variadic parameter list is less specialized than a
|
|
1811 * non-variadic one.
|
|
1812 */
|
|
1813 if (tf.varargs && !tg.varargs)
|
|
1814 goto L1; // less specialized
|
|
1815
|
|
1816 version (LOG_LEASTAS) {
|
|
1817 printf(" matches %d, so is least as specialized\n", m);
|
|
1818 }
|
|
1819 return m;
|
|
1820 }
|
|
1821 L1:
|
|
1822 version (LOG_LEASTAS) {
|
|
1823 printf(" doesn't match, so is not as specialized\n");
|
|
1824 }
|
|
1825 return MATCHnomatch;
|
|
1826 }
|
|
1827
|
|
1828 /********************************
|
|
1829 * Labels are in a separate scope, one per function.
|
|
1830 */
|
|
1831 LabelDsymbol searchLabel(Identifier ident)
|
|
1832 {
|
|
1833 Dsymbol s;
|
|
1834
|
|
1835 if (!labtab)
|
|
1836 labtab = new DsymbolTable(); // guess we need one
|
|
1837
|
|
1838 s = labtab.lookup(ident);
|
|
1839 if (!s)
|
|
1840 {
|
|
1841 s = new LabelDsymbol(ident);
|
|
1842 labtab.insert(s);
|
|
1843 }
|
|
1844
|
|
1845 return cast(LabelDsymbol)s;
|
|
1846 }
|
|
1847
|
|
1848 /****************************************
|
|
1849 * If non-static member function that has a 'this' pointer,
|
|
1850 * return the aggregate it is a member of.
|
|
1851 * Otherwise, return null.
|
|
1852 */
|
|
1853 AggregateDeclaration isThis()
|
|
1854 {
|
|
1855 AggregateDeclaration ad = null;
|
|
1856
|
|
1857 //printf("+FuncDeclaration.isThis() '%s'\n", toChars());
|
|
1858 if ((storage_class & STC.STCstatic) == 0)
|
|
1859 {
|
|
1860 ad = isMember2();
|
|
1861 }
|
|
1862 //printf("-FuncDeclaration.isThis() %p\n", ad);
|
|
1863 return ad;
|
|
1864 }
|
|
1865
|
|
1866 AggregateDeclaration isMember2()
|
|
1867 {
|
|
1868 AggregateDeclaration ad = null;
|
|
1869
|
|
1870 //printf("+FuncDeclaration.isMember2() '%s'\n", toChars());
|
|
1871 for (Dsymbol s = this; s; s = s.parent)
|
|
1872 {
|
|
1873 //printf("\ts = '%s', parent = '%s', kind = %s\n", s.toChars(), s.parent.toChars(), s.parent.kind());
|
|
1874 ad = s.isMember();
|
|
1875 if (ad)
|
|
1876 { //printf("test4\n");
|
|
1877 break;
|
|
1878 }
|
|
1879 if (!s.parent || (!s.parent.isTemplateInstance()))
|
|
1880 { //printf("test5\n");
|
|
1881 break;
|
|
1882 }
|
|
1883 }
|
|
1884 //printf("-FuncDeclaration.isMember2() %p\n", ad);
|
|
1885 return ad;
|
|
1886 }
|
|
1887
|
|
1888 /*****************************************
|
|
1889 * Determine lexical level difference from 'this' to nested function 'fd'.
|
|
1890 * Error if this cannot call fd.
|
|
1891 * Returns:
|
|
1892 * 0 same level
|
|
1893 * -1 increase nesting by 1 (fd is nested within 'this')
|
|
1894 * >0 decrease nesting by number
|
|
1895 */
|
|
1896 int getLevel(Loc loc, FuncDeclaration fd) // lexical nesting level difference
|
|
1897 {
|
|
1898 int level;
|
|
1899 Dsymbol s;
|
|
1900 Dsymbol fdparent;
|
|
1901
|
|
1902 //printf("FuncDeclaration.getLevel(fd = '%s')\n", fd.toChars());
|
|
1903 fdparent = fd.toParent2();
|
|
1904 if (fdparent == this)
|
|
1905 return -1;
|
|
1906 s = this;
|
|
1907 level = 0;
|
|
1908 while (fd != s && fdparent != s.toParent2())
|
|
1909 {
|
|
1910 //printf("\ts = '%s'\n", s.toChars());
|
|
1911 FuncDeclaration thisfd = s.isFuncDeclaration();
|
|
1912 if (thisfd)
|
|
1913 {
|
|
1914 if (!thisfd.isNested() && !thisfd.vthis)
|
|
1915 goto Lerr;
|
|
1916 }
|
|
1917 else
|
|
1918 {
|
|
1919 AggregateDeclaration thiscd = s.isAggregateDeclaration();
|
|
1920 if (thiscd)
|
|
1921 {
|
|
1922 if (!thiscd.isNested())
|
|
1923 goto Lerr;
|
|
1924 }
|
|
1925 else
|
|
1926 goto Lerr;
|
|
1927 }
|
|
1928
|
|
1929 s = s.toParent2();
|
|
1930 assert(s);
|
|
1931 level++;
|
|
1932 }
|
|
1933 return level;
|
|
1934
|
|
1935 Lerr:
|
|
1936 error(loc, "cannot access frame of function %s", fd.toChars());
|
|
1937 return 1;
|
|
1938 }
|
|
1939
|
|
1940 void appendExp(Expression e)
|
|
1941 {
|
|
1942 assert(false);
|
|
1943 }
|
|
1944
|
|
1945 void appendState(Statement s)
|
|
1946 {
|
|
1947 assert(false);
|
|
1948 }
|
|
1949
|
|
1950 string mangle()
|
|
1951 out (result)
|
|
1952 {
|
|
1953 assert(result.length > 0);
|
|
1954 }
|
|
1955 body
|
|
1956 {
|
|
1957 if (isMain()) {
|
|
1958 return "_Dmain";
|
|
1959 }
|
|
1960
|
|
1961 if (isWinMain() || isDllMain() || ident == Id.tls_get_addr)
|
|
1962 return ident.toChars();
|
|
1963
|
|
1964 assert(this);
|
|
1965
|
|
1966 return Declaration.mangle();
|
|
1967 }
|
|
1968
|
|
1969 string toPrettyChars()
|
|
1970 {
|
|
1971 if (isMain())
|
|
1972 return "D main";
|
|
1973 else
|
|
1974 return Dsymbol.toPrettyChars();
|
|
1975 }
|
|
1976
|
|
1977 int isMain()
|
|
1978 {
|
|
1979 return ident is Id.main && linkage != LINK.LINKc && !isMember() && !isNested();
|
|
1980 }
|
|
1981
|
|
1982 int isWinMain()
|
|
1983 {
|
|
1984 //printf("FuncDeclaration::isWinMain() %s\n", toChars());
|
|
1985 static if (false) {
|
|
1986 int x = ident == Id.WinMain &&
|
|
1987 linkage != LINK.LINKc && !isMember();
|
|
1988 printf("%s\n", x ? "yes" : "no");
|
|
1989 return x;
|
|
1990 } else {
|
|
1991 return ident == Id.WinMain && linkage != LINK.LINKc && !isMember();
|
|
1992 }
|
|
1993 }
|
|
1994
|
|
1995 int isDllMain()
|
|
1996 {
|
|
1997 return ident == Id.DllMain && linkage != LINK.LINKc && !isMember();
|
|
1998 }
|
|
1999
|
|
2000 /**********************************
|
|
2001 * Determine if function is a builtin one that we can
|
|
2002 * evaluate at compile time.
|
|
2003 */
|
|
2004 BUILTIN isBuiltin()
|
|
2005 {
|
|
2006 static string FeZe = "FNaNbeZe"; // pure nothrow real function(real)
|
|
2007
|
|
2008 //printf("FuncDeclaration::isBuiltin() %s\n", toChars());
|
|
2009 if (builtin == BUILTIN.BUILTINunknown)
|
|
2010 {
|
|
2011 builtin = BUILTIN.BUILTINnot;
|
|
2012 if (parent && parent.isModule())
|
|
2013 {
|
|
2014 // If it's in the std.math package
|
|
2015 if (parent.ident == Id.math && parent.parent && parent.parent.ident == Id.std && !parent.parent.parent)
|
|
2016 {
|
|
2017 //printf("deco = %s\n", type.deco);
|
|
2018 if (type.deco == FeZe)
|
|
2019 {
|
|
2020 if (ident == Id.sin)
|
|
2021 builtin = BUILTIN.BUILTINsin;
|
|
2022 else if (ident == Id.cos)
|
|
2023 builtin = BUILTIN.BUILTINcos;
|
|
2024 else if (ident == Id.tan)
|
|
2025 builtin = BUILTIN.BUILTINtan;
|
|
2026 else if (ident == Id._sqrt)
|
|
2027 builtin = BUILTIN.BUILTINsqrt;
|
|
2028 else if (ident == Id.fabs)
|
|
2029 builtin = BUILTIN.BUILTINfabs;
|
|
2030 //printf("builtin = %d\n", builtin);
|
|
2031 }
|
|
2032 // if float or double versions
|
|
2033 else if (type.deco == "FNaNbdZd" || type.deco == "FNaNbfZf")
|
|
2034 {
|
|
2035 if (ident == Id._sqrt)
|
|
2036 builtin = BUILTIN.BUILTINsqrt;
|
|
2037 }
|
|
2038 }
|
|
2039 }
|
|
2040 }
|
|
2041
|
|
2042 return builtin;
|
|
2043 }
|
|
2044
|
|
2045 bool isExport()
|
|
2046 {
|
|
2047 return protection == PROT.PROTexport;
|
|
2048 }
|
|
2049
|
|
2050 bool isImportedSymbol()
|
|
2051 {
|
|
2052 //printf("isImportedSymbol()\n");
|
|
2053 //printf("protection = %d\n", protection);
|
|
2054 return (protection == PROT.PROTexport) && !fbody;
|
|
2055 }
|
|
2056
|
|
2057 bool isAbstract()
|
|
2058 {
|
|
2059 return (storage_class & STC.STCabstract) != 0;
|
|
2060 }
|
|
2061
|
|
2062 bool isCodeseg()
|
|
2063 {
|
|
2064 assert(false);
|
|
2065 }
|
|
2066
|
|
2067 bool isOverloadable()
|
|
2068 {
|
|
2069 assert(false);
|
|
2070 }
|
|
2071
|
|
2072 bool isPure()
|
|
2073 {
|
|
2074 //printf("FuncDeclaration::isPure() '%s'\n", toChars());
|
|
2075 assert(type.ty == TY.Tfunction);
|
|
2076 return (cast(TypeFunction)this.type).ispure;
|
|
2077 }
|
|
2078
|
|
2079 bool isNested()
|
|
2080 {
|
|
2081 //if (!toParent())
|
|
2082 //printf("FuncDeclaration.isNested('%s') parent=%p\n", toChars(), parent);
|
|
2083 //printf("\ttoParent2() = '%s'\n", toParent2().toChars());
|
|
2084 return ((storage_class & STC.STCstatic) == 0) &&
|
|
2085 (toParent2().isFuncDeclaration() !is null);
|
|
2086 }
|
|
2087
|
|
2088 bool needThis()
|
|
2089 {
|
|
2090 //printf("FuncDeclaration.needThis() '%s'\n", toChars());
|
|
2091 bool needThis = isThis() !is null;
|
|
2092
|
|
2093 //printf("\t%d\n", i);
|
|
2094 if (!needThis) {
|
|
2095 if (auto fa = isFuncAliasDeclaration()) {
|
|
2096 needThis = fa.funcalias.needThis();
|
|
2097 }
|
|
2098 }
|
|
2099
|
|
2100 return needThis;
|
|
2101 }
|
|
2102
|
|
2103 bool isVirtual()
|
|
2104 {
|
|
2105 static if (false) {
|
|
2106 printf("FuncDeclaration.isVirtual(%s)\n", toChars());
|
|
2107 printf("isMember:%p isStatic:%d private:%d ctor:%d !Dlinkage:%d\n", isMember(), isStatic(), protection == PROT.PROTprivate, isCtorDeclaration(), linkage != LINK.LINKd);
|
|
2108 printf("result is %d\n",
|
|
2109 isMember() && !(isStatic() || protection == PROT.PROTprivate || protection == PROT.PROTpackage) && toParent().isClassDeclaration());
|
|
2110 }
|
|
2111 return isMember() && !(isStatic() || protection == PROT.PROTprivate || protection == PROT.PROTpackage) && toParent().isClassDeclaration();
|
|
2112 }
|
|
2113
|
|
2114 int isFinal()
|
|
2115 {
|
|
2116 ClassDeclaration cd;
|
|
2117 static if (false) {
|
|
2118 printf("FuncDeclaration.isFinal(%s)\n", toChars());
|
|
2119 printf("%p %d %d %d %d\n", isMember(), isStatic(), protection == PROT.PROTprivate, isCtorDeclaration(), linkage != LINK.LINKd);
|
|
2120 printf("result is %d\n",
|
|
2121 isMember() && !(isStatic() || protection == PROT.PROTprivate || protection == PROT.PROTpackage) && (cd = toParent().isClassDeclaration()) !is null && cd.storage_class & STC.STCfinal);
|
|
2122 }
|
|
2123 return isMember() && (Declaration.isFinal() || ((cd = toParent().isClassDeclaration()) !is null && cd.storage_class & STC.STCfinal));
|
|
2124 }
|
|
2125
|
|
2126 bool addPreInvariant()
|
|
2127 {
|
|
2128 AggregateDeclaration ad = isThis();
|
|
2129 return (ad &&
|
|
2130 //ad.isClassDeclaration() &&
|
|
2131 global.params.useInvariants &&
|
|
2132 (protection == PROT.PROTpublic || protection == PROT.PROTexport) &&
|
|
2133 !naked &&
|
|
2134 ident !is Id.cpctor);
|
|
2135 }
|
|
2136
|
|
2137 bool addPostInvariant()
|
|
2138 {
|
|
2139 AggregateDeclaration ad = isThis();
|
|
2140 return (ad && ad.inv &&
|
|
2141 //ad.isClassDeclaration() &&
|
|
2142 global.params.useInvariants &&
|
|
2143 (protection == PROT.PROTpublic || protection == PROT.PROTexport) &&
|
|
2144 !naked &&
|
|
2145 ident !is Id.cpctor);
|
|
2146 }
|
|
2147
|
|
2148 Expression interpret(InterState* istate, Expressions arguments, Expression thisexp = null)
|
|
2149 {
|
|
2150 assert(false);
|
|
2151 }
|
|
2152
|
|
2153 void inlineScan()
|
|
2154 {
|
|
2155 InlineScanState iss;
|
|
2156
|
|
2157 version (LOG) {
|
|
2158 printf("FuncDeclaration.inlineScan('%s')\n", toChars());
|
|
2159 }
|
|
2160 ///memset(&iss, 0, sizeof(iss));
|
|
2161 iss.fd = this;
|
|
2162 if (fbody)
|
|
2163 {
|
|
2164 inlineNest++;
|
|
2165 fbody = fbody.inlineScan(&iss);
|
|
2166 inlineNest--;
|
|
2167 }
|
|
2168 }
|
|
2169
|
|
2170 int canInline(int hasthis, int hdrscan = 0)
|
|
2171 {
|
|
2172 int cost;
|
|
2173
|
|
2174 // #define CANINLINE_LOG 0
|
|
2175
|
|
2176 version (CANINLINE_LOG) {
|
|
2177 printf("FuncDeclaration.canInline(hasthis = %d, '%s')\n", hasthis, toChars());
|
|
2178 }
|
|
2179
|
|
2180 if (needThis() && !hasthis)
|
|
2181 return 0;
|
|
2182
|
|
2183 if (inlineNest || (semanticRun < 3 && !hdrscan))
|
|
2184 {
|
|
2185 version (CANINLINE_LOG) {
|
|
2186 printf("\t1: no, inlineNest = %d, semanticRun = %d\n", inlineNest, semanticRun);
|
|
2187 }
|
|
2188 return 0;
|
|
2189 }
|
|
2190
|
|
2191 switch (inlineStatus)
|
|
2192 {
|
|
2193 case ILS.ILSyes:
|
|
2194 version (CANINLINE_LOG) {
|
|
2195 printf("\t1: yes %s\n", toChars());
|
|
2196 }
|
|
2197 return 1;
|
|
2198
|
|
2199 case ILS.ILSno:
|
|
2200 version (CANINLINE_LOG) {
|
|
2201 printf("\t1: no %s\n", toChars());
|
|
2202 }
|
|
2203 return 0;
|
|
2204
|
|
2205 case ILS.ILSuninitialized:
|
|
2206 break;
|
|
2207
|
|
2208 default:
|
|
2209 assert(0);
|
|
2210 }
|
|
2211
|
|
2212 if (type)
|
|
2213 {
|
|
2214 assert(type.ty == Tfunction);
|
|
2215 TypeFunction tf = cast(TypeFunction)type;
|
|
2216 if (tf.varargs == 1) // no variadic parameter lists
|
|
2217 goto Lno;
|
|
2218
|
|
2219 /* Don't inline a function that returns non-void, but has
|
|
2220 * no return expression.
|
|
2221 */
|
|
2222 if (tf.next && tf.next.ty != Tvoid &&
|
|
2223 !(hasReturnExp & 1) &&
|
|
2224 !hdrscan)
|
|
2225 goto Lno;
|
|
2226 }
|
|
2227 else
|
|
2228 {
|
|
2229 CtorDeclaration ctor = isCtorDeclaration();
|
|
2230 if (ctor && ctor.varargs == 1)
|
|
2231 goto Lno;
|
|
2232 }
|
|
2233
|
|
2234 if (
|
|
2235 !fbody ||
|
|
2236 !hdrscan &&
|
|
2237 (
|
|
2238 /// static if (false) {
|
|
2239 /// isCtorDeclaration() || // cannot because need to convert:
|
|
2240 /// // return;
|
|
2241 /// // to:
|
|
2242 /// // return this;
|
|
2243 /// }
|
|
2244 isSynchronized() ||
|
|
2245 isImportedSymbol() ||
|
|
2246 /// version (DMDV2) {
|
|
2247 closureVars.dim || // no nested references to this frame
|
|
2248 /// } else {
|
|
2249 /// nestedFrameRef || // no nested references to this frame
|
|
2250 /// }
|
|
2251 (isVirtual() && !isFinal())
|
|
2252 ))
|
|
2253 {
|
|
2254 goto Lno;
|
|
2255 }
|
|
2256
|
|
2257 /* If any parameters are Tsarray's (which are passed by reference)
|
|
2258 * or out parameters (also passed by reference), don't do inlining.
|
|
2259 */
|
|
2260 if (parameters)
|
|
2261 {
|
|
2262 for (int i = 0; i < parameters.dim; i++)
|
|
2263 {
|
|
2264 VarDeclaration v = cast(VarDeclaration)parameters.data[i];
|
|
2265 if (v.isOut() || v.isRef() || v.type.toBasetype().ty == Tsarray)
|
|
2266 goto Lno;
|
|
2267 }
|
|
2268 }
|
|
2269
|
|
2270 InlineCostState ics;
|
|
2271 ///memset(&ics, 0, sizeof(ics));
|
|
2272 ics.hasthis = hasthis;
|
|
2273 ics.fd = this;
|
|
2274 ics.hdrscan = hdrscan;
|
|
2275 cost = fbody.inlineCost(&ics);
|
|
2276 version (CANINLINE_LOG) {
|
|
2277 printf("cost = %d\n", cost);
|
|
2278 }
|
|
2279 if (cost >= COST_MAX)
|
|
2280 goto Lno;
|
|
2281
|
|
2282 if (!hdrscan) // Don't scan recursively for header content scan
|
|
2283 inlineScan();
|
|
2284
|
|
2285 Lyes:
|
|
2286 if (!hdrscan) // Don't modify inlineStatus for header content scan
|
|
2287 inlineStatus = ILS.ILSyes;
|
|
2288 version (CANINLINE_LOG) {
|
|
2289 printf("\t2: yes %s\n", toChars());
|
|
2290 }
|
|
2291 return 1;
|
|
2292
|
|
2293 Lno:
|
|
2294 if (!hdrscan) // Don't modify inlineStatus for header content scan
|
|
2295 inlineStatus = ILS.ILSno;
|
|
2296 version (CANINLINE_LOG) {
|
|
2297 printf("\t2: no %s\n", toChars());
|
|
2298 }
|
|
2299 return 0;
|
|
2300 }
|
|
2301
|
|
2302 Expression doInline(InlineScanState* iss, Expression ethis, Array arguments)
|
|
2303 {
|
|
2304 InlineDoState ids = new InlineDoState();
|
|
2305 DeclarationExp de;
|
|
2306 Expression e = null;
|
|
2307
|
|
2308 version (LOG) {
|
|
2309 printf("FuncDeclaration.doInline('%s')\n", toChars());
|
|
2310 }
|
|
2311
|
|
2312 ///memset(&ids, 0, sizeof(ids));
|
|
2313 ids.parent = iss.fd;
|
|
2314
|
|
2315 // Set up vthis
|
|
2316 if (ethis)
|
|
2317 {
|
|
2318 VarDeclaration vthis;
|
|
2319 ExpInitializer ei;
|
|
2320 VarExp ve;
|
|
2321
|
|
2322 version (STRUCTTHISREF) {
|
|
2323 if (ethis.type.ty == Tpointer)
|
|
2324 {
|
|
2325 Type t = ethis.type.nextOf();
|
|
2326 ethis = new PtrExp(ethis.loc, ethis);
|
|
2327 ethis.type = t;
|
|
2328 }
|
|
2329 ei = new ExpInitializer(ethis.loc, ethis);
|
|
2330
|
|
2331 vthis = new VarDeclaration(ethis.loc, ethis.type, Id.This, ei);
|
|
2332 if (ethis.type.ty != Tclass)
|
|
2333 vthis.storage_class = STCref;
|
|
2334 else
|
|
2335 vthis.storage_class = STCin;
|
|
2336 } else {
|
|
2337 if (ethis.type.ty != Tclass && ethis.type.ty != Tpointer)
|
|
2338 {
|
|
2339 ethis = ethis.addressOf(null);
|
|
2340 }
|
|
2341
|
|
2342 ei = new ExpInitializer(ethis.loc, ethis);
|
|
2343
|
|
2344 vthis = new VarDeclaration(ethis.loc, ethis.type, Id.This, ei);
|
|
2345 vthis.storage_class = STCin;
|
|
2346 }
|
|
2347 vthis.linkage = LINKd;
|
|
2348 vthis.parent = iss.fd;
|
|
2349
|
|
2350 ve = new VarExp(vthis.loc, vthis);
|
|
2351 ve.type = vthis.type;
|
|
2352
|
|
2353 ei.exp = new AssignExp(vthis.loc, ve, ethis);
|
|
2354 ei.exp.type = ve.type;
|
|
2355 version (STRUCTTHISREF) {
|
|
2356 if (ethis.type.ty != Tclass)
|
|
2357 {
|
|
2358 /* This is a reference initialization, not a simple assignment.
|
|
2359 */
|
|
2360 ei.exp.op = TOKconstruct;
|
|
2361 }
|
|
2362 }
|
|
2363
|
|
2364 ids.vthis = vthis;
|
|
2365 }
|
|
2366
|
|
2367 // Set up parameters
|
|
2368 if (ethis)
|
|
2369 {
|
|
2370 e = new DeclarationExp(Loc(0), ids.vthis);
|
|
2371 e.type = Type.tvoid;
|
|
2372 }
|
|
2373
|
|
2374 if (arguments && arguments.dim)
|
|
2375 {
|
|
2376 assert(parameters.dim == arguments.dim);
|
|
2377
|
|
2378 for (int i = 0; i < arguments.dim; i++)
|
|
2379 {
|
|
2380 VarDeclaration vfrom = cast(VarDeclaration)parameters.data[i];
|
|
2381 VarDeclaration vto;
|
|
2382 Expression arg = cast(Expression)arguments.data[i];
|
|
2383 ExpInitializer ei;
|
|
2384 VarExp ve;
|
|
2385
|
|
2386 ei = new ExpInitializer(arg.loc, arg);
|
|
2387
|
|
2388 vto = new VarDeclaration(vfrom.loc, vfrom.type, vfrom.ident, ei);
|
|
2389 vto.storage_class |= vfrom.storage_class & (STCin | STCout | STClazy | STCref);
|
|
2390 vto.linkage = vfrom.linkage;
|
|
2391 vto.parent = iss.fd;
|
|
2392 //printf("vto = '%s', vto.storage_class = x%x\n", vto.toChars(), vto.storage_class);
|
|
2393 //printf("vto.parent = '%s'\n", iss.fd.toChars());
|
|
2394
|
|
2395 ve = new VarExp(vto.loc, vto);
|
|
2396 //ve.type = vto.type;
|
|
2397 ve.type = arg.type;
|
|
2398
|
|
2399 ei.exp = new AssignExp(vto.loc, ve, arg);
|
|
2400 ei.exp.type = ve.type;
|
|
2401 //ve.type.print();
|
|
2402 //arg.type.print();
|
|
2403 //ei.exp.print();
|
|
2404
|
|
2405 ids.from.push(cast(void*)vfrom);
|
|
2406 ids.to.push(cast(void*)vto);
|
|
2407
|
|
2408 de = new DeclarationExp(Loc(0), vto);
|
|
2409 de.type = Type.tvoid;
|
|
2410
|
|
2411 e = Expression.combine(e, de);
|
|
2412 }
|
|
2413 }
|
|
2414
|
|
2415 inlineNest++;
|
|
2416 Expression eb = fbody.doInline(ids);
|
|
2417 inlineNest--;
|
|
2418 //eb.type.print();
|
|
2419 //eb.print();
|
|
2420 //eb.dump(0);
|
|
2421 return Expression.combine(e, eb);
|
|
2422 }
|
|
2423
|
|
2424 string kind()
|
|
2425 {
|
|
2426 return "function";
|
|
2427 }
|
|
2428
|
|
2429 void toDocBuffer(OutBuffer buf)
|
|
2430 {
|
|
2431 assert(false);
|
|
2432 }
|
|
2433
|
|
2434 FuncDeclaration isUnique()
|
|
2435 {
|
|
2436 assert(false);
|
|
2437 }
|
|
2438
|
|
2439 /*******************************
|
|
2440 * Look at all the variables in this function that are referenced
|
|
2441 * by nested functions, and determine if a closure needs to be
|
|
2442 * created for them.
|
|
2443 */
|
|
2444 bool needsClosure()
|
|
2445 {
|
|
2446 /* Need a closure for all the closureVars[] if any of the
|
|
2447 * closureVars[] are accessed by a
|
|
2448 * function that escapes the scope of this function.
|
|
2449 * We take the conservative approach and decide that any function that:
|
|
2450 * 1) is a virtual function
|
|
2451 * 2) has its address taken
|
|
2452 * 3) has a parent that escapes
|
|
2453 *
|
|
2454 * Note that since a non-virtual function can be called by
|
|
2455 * a virtual one, if that non-virtual function accesses a closure
|
|
2456 * var, the closure still has to be taken. Hence, we check for isThis()
|
|
2457 * instead of isVirtual(). (thanks to David Friedman)
|
|
2458 */
|
|
2459
|
|
2460 //printf("FuncDeclaration.needsClosure() %s\n", toChars());
|
|
2461 for (int i = 0; i < closureVars.dim; i++)
|
|
2462 {
|
|
2463 VarDeclaration v = cast(VarDeclaration)closureVars.data[i];
|
|
2464 assert(v.isVarDeclaration());
|
|
2465 //printf("\tv = %s\n", v.toChars());
|
|
2466
|
|
2467 for (int j = 0; j < v.nestedrefs.dim; j++)
|
|
2468 { FuncDeclaration f = cast(FuncDeclaration)v.nestedrefs.data[j];
|
|
2469 assert(f != this);
|
|
2470
|
|
2471 //printf("\t\tf = %s, %d, %p, %d\n", f.toChars(), f.isVirtual(), f.isThis(), f.tookAddressOf);
|
|
2472 if (f.isThis() || f.tookAddressOf)
|
|
2473 goto Lyes; // assume f escapes this function's scope
|
|
2474
|
|
2475 // Look to see if any parents of f that are below this escape
|
|
2476 for (Dsymbol s = f.parent; s && s !is this; s = s.parent)
|
|
2477 {
|
|
2478 f = s.isFuncDeclaration();
|
|
2479 if (f && (f.isThis() || f.tookAddressOf)) {
|
|
2480 goto Lyes;
|
|
2481 }
|
|
2482 }
|
|
2483 }
|
|
2484 }
|
|
2485 return false;
|
|
2486
|
|
2487 Lyes:
|
|
2488 //printf("\tneeds closure\n");
|
|
2489 return true;
|
|
2490 }
|
|
2491
|
|
2492 static FuncDeclaration genCfunc(Type treturn, string name)
|
|
2493 {
|
|
2494 return genCfunc(treturn, Lexer.idPool(name));
|
|
2495 }
|
|
2496
|
|
2497 /**********************************
|
|
2498 * Generate a FuncDeclaration for a runtime library function.
|
|
2499 */
|
|
2500 static FuncDeclaration genCfunc(Type treturn, Identifier id)
|
|
2501 {
|
|
2502 FuncDeclaration fd;
|
|
2503 TypeFunction tf;
|
|
2504 Dsymbol s;
|
|
2505 static DsymbolTable st = null;
|
|
2506
|
|
2507 //printf("genCfunc(name = '%s')\n", id.toChars());
|
|
2508 //printf("treturn\n\t"); treturn.print();
|
|
2509
|
|
2510 // See if already in table
|
|
2511 if (!st)
|
|
2512 st = new DsymbolTable();
|
|
2513
|
|
2514 s = st.lookup(id);
|
|
2515 if (s)
|
|
2516 {
|
|
2517 fd = s.isFuncDeclaration();
|
|
2518 assert(fd);
|
|
2519 assert(fd.type.nextOf().equals(treturn));
|
|
2520 }
|
|
2521 else
|
|
2522 {
|
|
2523 tf = new TypeFunction(null, treturn, 0, LINK.LINKc);
|
|
2524 fd = new FuncDeclaration(Loc(0), Loc(0), id, STCstatic, tf);
|
|
2525 fd.protection = PROT.PROTpublic;
|
|
2526 fd.linkage = LINK.LINKc;
|
|
2527
|
|
2528 st.insert(fd);
|
|
2529 }
|
|
2530 return fd;
|
|
2531 }
|
|
2532
|
|
2533 Symbol* toSymbol()
|
|
2534 {
|
|
2535 if (!csym)
|
|
2536 {
|
|
2537 Symbol* s;
|
|
2538 TYPE* t;
|
|
2539 string id;
|
|
2540
|
|
2541 static if (false) {
|
|
2542 id = ident.toChars();
|
|
2543 } else {
|
|
2544 id = mangle();
|
|
2545 }
|
|
2546 //writef("FuncDeclaration.toSymbol(%s %s)\n", kind(), toChars());
|
|
2547 //writef("\tid = '%s'\n", id);
|
|
2548 //writef("\ttype = %s\n", type.toChars());
|
|
2549 s = symbol_calloc(toStringz(id));
|
|
2550 slist_add(s);
|
|
2551
|
|
2552 {
|
|
2553 s.prettyIdent = toStringz(toPrettyChars());
|
|
2554 s.Sclass = SC.SCglobal;
|
|
2555 symbol_func(s);
|
|
2556 func_t* f = s.Sfunc;
|
|
2557 if (isVirtual())
|
|
2558 f.Fflags |= F.Fvirtual;
|
|
2559 else if (isMember2())
|
|
2560 f.Fflags |= F.Fstatic;
|
|
2561 f.Fstartline.Slinnum = loc.linnum;
|
|
2562 f.Fstartline.Sfilename = cast(char*)toStringz(loc.filename);
|
|
2563 if (endloc.linnum)
|
|
2564 {
|
|
2565 f.Fendline.Slinnum = endloc.linnum;
|
|
2566 f.Fendline.Sfilename = cast(char*)toStringz(endloc.filename);
|
|
2567 }
|
|
2568 else
|
|
2569 {
|
|
2570 f.Fendline.Slinnum = loc.linnum;
|
|
2571 f.Fendline.Sfilename = cast(char*)toStringz(loc.filename);
|
|
2572 }
|
|
2573 t = type.toCtype();
|
|
2574 }
|
|
2575
|
|
2576 mangle_t msave = t.Tmangle;
|
|
2577 if (isMain())
|
|
2578 {
|
|
2579 t.Tty = TYM.TYnfunc;
|
|
2580 t.Tmangle = mTYman.mTYman_c;
|
|
2581 }
|
|
2582 else
|
|
2583 {
|
|
2584 switch (linkage)
|
|
2585 {
|
|
2586 case LINK.LINKwindows:
|
|
2587 t.Tmangle = mTYman.mTYman_std;
|
|
2588 break;
|
|
2589
|
|
2590 case LINK.LINKpascal:
|
|
2591 t.Tty = TYM.TYnpfunc;
|
|
2592 t.Tmangle = mTYman.mTYman_pas;
|
|
2593 break;
|
|
2594
|
|
2595 case LINK.LINKc:
|
|
2596 t.Tmangle = mTYman.mTYman_c;
|
|
2597 break;
|
|
2598
|
|
2599 case LINK.LINKd:
|
|
2600 t.Tmangle = mTYman.mTYman_d;
|
|
2601 break;
|
|
2602
|
|
2603 case LINK.LINKcpp:
|
|
2604 { t.Tmangle = mTYman.mTYman_cpp;
|
|
2605 version (TARGET_WINDOS) {
|
|
2606 if (isThis())
|
|
2607 t.Tty = TYM.TYmfunc;
|
|
2608 }
|
|
2609 s.Sflags |= SFL.SFLpublic;
|
|
2610 Dsymbol parent = toParent();
|
|
2611 ClassDeclaration cd = parent.isClassDeclaration();
|
|
2612 if (cd)
|
|
2613 {
|
|
2614 .type* tt = cd.type.toCtype();
|
|
2615 s.Sscope = tt.Tnext.Ttag;
|
|
2616 }
|
|
2617 break;
|
|
2618 }
|
|
2619 default:
|
|
2620 writef("linkage = %d\n", linkage);
|
|
2621 assert(0);
|
|
2622 }
|
|
2623 }
|
|
2624 if (msave)
|
|
2625 assert(msave == t.Tmangle);
|
|
2626 //printf("Tty = %x, mangle = x%x\n", t.Tty, t.Tmangle);
|
|
2627 t.Tcount++;
|
|
2628 s.Stype = t;
|
|
2629 //s.Sfielddef = this;
|
|
2630
|
|
2631 csym = s;
|
|
2632 }
|
|
2633 return csym;
|
|
2634 }
|
|
2635
|
|
2636 Symbol* toThunkSymbol(int offset) // thunk version
|
|
2637 {
|
|
2638 Symbol *sthunk;
|
|
2639
|
|
2640 toSymbol();
|
|
2641
|
|
2642 static if (false) {
|
|
2643 char *id;
|
|
2644 char *n;
|
|
2645 type *t;
|
|
2646
|
|
2647 n = sym.Sident;
|
|
2648 id = cast(char*) alloca(8 + 5 + strlen(n) + 1);
|
|
2649 sprintf(id, "_thunk%d__%s", offset, n);
|
|
2650 s = symbol_calloc(id);
|
|
2651 slist_add(s);
|
|
2652 s.Stype = csym.Stype;
|
|
2653 s.Stype.Tcount++;
|
|
2654 }
|
|
2655 sthunk = symbol_generate(SCstatic, csym.Stype);
|
|
2656 sthunk.Sflags |= SFLimplem;
|
|
2657 cod3_thunk(sthunk, csym, 0, TYnptr, -offset, -1, 0);
|
|
2658 return sthunk;
|
|
2659 }
|
|
2660
|
|
2661 void toObjFile(int multiobj) // compile to .obj file
|
|
2662 {
|
|
2663 Symbol* s;
|
|
2664 func_t* f;
|
|
2665 Symbol* senter;
|
|
2666 Symbol* sexit;
|
|
2667
|
|
2668 FuncDeclaration func = this;
|
|
2669 ClassDeclaration cd = func.parent.isClassDeclaration();
|
|
2670 int reverse;
|
|
2671 int i;
|
|
2672 int has_arguments;
|
|
2673
|
|
2674 //printf("FuncDeclaration.toObjFile(%p, %s.%s)\n", func, parent.toChars(), func.toChars());
|
|
2675 static if (false) {
|
|
2676 //printf("line = %d\n",func.getWhere() / LINEINC);
|
|
2677 EEcontext ee = env.getEEcontext();
|
|
2678 if (ee.EEcompile == 2)
|
|
2679 {
|
|
2680 if (ee.EElinnum < (func.getWhere() / LINEINC) ||
|
|
2681 ee.EElinnum > (func.endwhere / LINEINC)
|
|
2682 )
|
|
2683 return; // don't compile this function
|
|
2684 ee.EEfunc = func.toSymbol();
|
|
2685 }
|
|
2686 }
|
|
2687
|
|
2688 if (multiobj && !isStaticDtorDeclaration() && !isStaticCtorDeclaration())
|
|
2689 {
|
|
2690 obj_append(this);
|
|
2691 return;
|
|
2692 }
|
|
2693
|
|
2694 if (semanticRun >= 5) // if toObjFile() already run
|
|
2695 return;
|
|
2696
|
|
2697 semanticRun = 5;
|
|
2698
|
|
2699 if (!func.fbody)
|
|
2700 {
|
|
2701 return;
|
|
2702 }
|
|
2703
|
|
2704 if (func.isUnitTestDeclaration() && !global.params.useUnitTests)
|
|
2705 return;
|
|
2706
|
|
2707 if (global.params.verbose)
|
|
2708 writef("function %s\n",func.toChars());
|
|
2709
|
|
2710 s = func.toSymbol();
|
|
2711 f = s.Sfunc;
|
|
2712
|
|
2713 version (TARGET_OSX) {
|
|
2714 s.Sclass = SC.SCcomdat;
|
|
2715 } else {
|
|
2716 s.Sclass = SC.SCglobal;
|
|
2717 }
|
|
2718
|
|
2719 for (Dsymbol p = parent; p; p = p.parent)
|
|
2720 {
|
|
2721 if (p.isTemplateInstance())
|
|
2722 {
|
|
2723 s.Sclass = SC.SCcomdat;
|
|
2724 break;
|
|
2725 }
|
|
2726 }
|
|
2727
|
|
2728 if (isNested())
|
|
2729 {
|
|
2730 // if (!(config.flags3 & CFG3pic))
|
|
2731 // s.Sclass = SCstatic;
|
|
2732 f.Fflags3 |= F3.Fnested;
|
|
2733 }
|
|
2734 else
|
|
2735 {
|
|
2736 const(char)* libname = (global.params.symdebug) ? global.params.debuglibname : global.params.defaultlibname;
|
|
2737
|
|
2738 // Pull in RTL startup code
|
|
2739 if (func.isMain())
|
|
2740 { objextdef("_main");
|
|
2741 version (XXX) { ///TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS
|
|
2742 obj_ehsections(); // initialize exception handling sections
|
|
2743 } else {
|
|
2744 objextdef("__acrtused_con");
|
|
2745 }
|
|
2746 obj_includelib(libname);
|
|
2747 s.Sclass = SC.SCglobal;
|
|
2748 }
|
|
2749 else if (strcmp(s.Sident.ptr, "main".ptr) == 0 && linkage == LINK.LINKc)
|
|
2750 s.Sclass = SC.SCglobal;
|
|
2751
|
|
2752 else if (func.isWinMain())
|
|
2753 {
|
|
2754 objextdef("__acrtused");
|
|
2755 obj_includelib(libname);
|
|
2756 s.Sclass = SC.SCglobal;
|
|
2757 }
|
|
2758
|
|
2759 // Pull in RTL startup code
|
|
2760 else if (func.isDllMain())
|
|
2761 {
|
|
2762 objextdef("__acrtused_dll");
|
|
2763 obj_includelib(libname);
|
|
2764 s.Sclass = SC.SCglobal;
|
|
2765 }
|
|
2766 }
|
|
2767
|
|
2768 cstate.CSpsymtab = &f.Flocsym;
|
|
2769
|
|
2770 // Find module m for this function
|
|
2771 Module m = null;
|
|
2772 for (Dsymbol p = parent; p; p = p.parent)
|
|
2773 {
|
|
2774 m = p.isModule();
|
|
2775 if (m)
|
|
2776 break;
|
|
2777 }
|
|
2778
|
|
2779 IRState irs = IRState(m, func);
|
|
2780 Array deferToObj = new Array(); // write these to OBJ file later
|
|
2781 irs.deferToObj = deferToObj;
|
|
2782
|
|
2783 TypeFunction tf;
|
|
2784 RET retmethod;
|
|
2785 Symbol* shidden = null;
|
|
2786 Symbol* sthis = null;
|
|
2787 tym_t tyf;
|
|
2788
|
|
2789 tyf = tybasic(s.Stype.Tty);
|
|
2790 //printf("linkage = %d, tyf = x%x\n", linkage, tyf);
|
|
2791 reverse = tyrevfunc(s.Stype.Tty);
|
|
2792
|
|
2793 assert(func.type.ty == TY.Tfunction);
|
|
2794 tf = cast(TypeFunction)(func.type);
|
|
2795 has_arguments = (tf.linkage == LINK.LINKd) && (tf.varargs == 1);
|
|
2796 retmethod = tf.retStyle();
|
|
2797 if (retmethod == RET.RETstack)
|
|
2798 {
|
|
2799 // If function returns a struct, put a pointer to that
|
|
2800 // as the first argument
|
|
2801 .type* thidden = tf.next.pointerTo().toCtype();
|
|
2802 char hiddenparam[5+4+1];
|
|
2803 static int hiddenparami; // how many we've generated so far
|
|
2804
|
|
2805 sprintf(hiddenparam.ptr, "__HID%d".ptr, ++hiddenparami);
|
|
2806 shidden = symbol_name(hiddenparam.ptr, SC.SCparameter, thidden);
|
|
2807 shidden.Sflags |= SFL.SFLtrue | SFL.SFLfree;
|
|
2808
|
|
2809 version (DMDV1) {
|
|
2810 bool nestedref = func.nrvo_can && func.nrvo_var && func.nrvo_var.nestedref;
|
|
2811 } else {
|
|
2812 bool nestedref = func.nrvo_can && func.nrvo_var && (func.nrvo_var.nestedrefs.dim != 0);
|
|
2813 }
|
|
2814 if (nestedref) {
|
|
2815 type_setcv(&shidden.Stype, shidden.Stype.Tty | mTY.mTYvolatile);
|
|
2816 }
|
|
2817
|
|
2818 irs.shidden = shidden;
|
|
2819 this.shidden = shidden;
|
|
2820 }
|
|
2821
|
|
2822 if (vthis)
|
|
2823 {
|
|
2824 assert(!vthis.csym);
|
|
2825 sthis = vthis.toSymbol();
|
|
2826 irs.sthis = sthis;
|
|
2827 if (!(f.Fflags3 & F3.Fnested))
|
|
2828 f.Fflags3 |= F3.Fmember;
|
|
2829 }
|
|
2830
|
|
2831 Symbol** params;
|
|
2832 uint pi;
|
|
2833
|
|
2834 // Estimate number of parameters, pi
|
|
2835 pi = (v_arguments !is null);
|
|
2836 if (parameters)
|
|
2837 pi += parameters.dim;
|
|
2838
|
|
2839 // Allow extra 2 for sthis and shidden
|
|
2840 params = cast(Symbol**)alloca((pi + 2) * (Symbol*).sizeof);
|
|
2841
|
|
2842 // Get the actual number of parameters, pi, and fill in the params[]
|
|
2843 pi = 0;
|
|
2844 if (v_arguments)
|
|
2845 {
|
|
2846 params[pi] = v_arguments.toSymbol();
|
|
2847 pi += 1;
|
|
2848 }
|
|
2849 if (parameters)
|
|
2850 {
|
|
2851 for (i = 0; i < parameters.dim; i++)
|
|
2852 {
|
|
2853 VarDeclaration v = cast(VarDeclaration)parameters.data[i];
|
|
2854 debug {
|
|
2855 if (v.csym)
|
|
2856 writef("parameter '%s'\n", v.toChars());
|
|
2857 }
|
|
2858 assert(!v.csym);
|
|
2859 params[pi + i] = v.toSymbol();
|
|
2860 }
|
|
2861 pi += i;
|
|
2862 }
|
|
2863
|
|
2864 if (reverse)
|
|
2865 {
|
|
2866 // Reverse params[] entries
|
|
2867 for (i = 0; i < pi/2; i++)
|
|
2868 {
|
|
2869 Symbol* sptmp = params[i];
|
|
2870 params[i] = params[pi - 1 - i];
|
|
2871 params[pi - 1 - i] = sptmp;
|
|
2872 }
|
|
2873 }
|
|
2874
|
|
2875 if (shidden)
|
|
2876 {
|
|
2877 static if (false) {
|
|
2878 // shidden becomes last parameter
|
|
2879 params[pi] = shidden;
|
|
2880 } else {
|
|
2881 // shidden becomes first parameter
|
|
2882 memmove(params + 1, params, pi * (*params).sizeof);
|
|
2883 params[0] = shidden;
|
|
2884 }
|
|
2885 pi++;
|
|
2886 }
|
|
2887
|
|
2888
|
|
2889 if (sthis)
|
|
2890 {
|
|
2891 static if (false) {
|
|
2892 // sthis becomes last parameter
|
|
2893 params[pi] = sthis;
|
|
2894 } else {
|
|
2895 // sthis becomes first parameter
|
|
2896 memmove(params + 1, params, pi * (*params).sizeof);
|
|
2897 params[0] = sthis;
|
|
2898 }
|
|
2899 pi++;
|
|
2900 }
|
|
2901
|
|
2902 if ((global.params.isLinux || global.params.isOSX || global.params.isFreeBSD || global.params.isSolaris) &&
|
|
2903 linkage != LINK.LINKd && shidden && sthis)
|
|
2904 {
|
|
2905 /* swap shidden and sthis
|
|
2906 */
|
|
2907 Symbol* sp = params[0];
|
|
2908 params[0] = params[1];
|
|
2909 params[1] = sp;
|
|
2910 }
|
|
2911
|
|
2912 for (i = 0; i < pi; i++)
|
|
2913 {
|
|
2914 Symbol *sp = params[i];
|
|
2915 sp.Sclass = SC.SCparameter;
|
|
2916 sp.Sflags &= ~SFL.SFLspill;
|
|
2917 sp.Sfl = FL.FLpara;
|
|
2918 symbol_add(sp);
|
|
2919 }
|
|
2920
|
|
2921 // First parameter goes in register
|
|
2922 if (pi)
|
|
2923 {
|
|
2924 Symbol* sp = params[0];
|
|
2925 if ((tyf == TYM.TYjfunc || tyf == TYM.TYmfunc) && type_jparam(sp.Stype))
|
|
2926 {
|
|
2927 sp.Sclass = SC.SCfastpar;
|
|
2928 sp.Spreg = (tyf == TYM.TYjfunc) ? REG.AX : REG.CX;
|
|
2929 sp.Sfl = FL.FLauto;
|
|
2930 //printf("'%s' is SCfastpar\n",sp.Sident);
|
|
2931 }
|
|
2932 }
|
|
2933
|
|
2934 if (func.fbody)
|
|
2935 {
|
|
2936 block* b;
|
|
2937 Blockx bx;
|
|
2938 Statement sbody;
|
|
2939
|
|
2940 localgot = null;
|
|
2941
|
|
2942 sbody = func.fbody;
|
|
2943 ///memset(&bx, 0, (bx).sizeof);
|
|
2944 bx.startblock = block_calloc();
|
|
2945 bx.curblock = bx.startblock;
|
|
2946 bx.funcsym = s;
|
|
2947 bx.scope_index = -1;
|
|
2948 bx.classdec = cd;
|
|
2949 bx.member = func;
|
|
2950 bx.module_ = getModule();
|
|
2951 irs.blx = &bx;
|
|
2952
|
|
2953 buildClosure(&irs);
|
|
2954
|
|
2955 static if (false) {
|
|
2956 if (func.isSynchronized())
|
|
2957 {
|
|
2958 if (cd)
|
|
2959 {
|
|
2960 elem *esync;
|
|
2961 if (func.isStatic())
|
|
2962 { // monitor is in ClassInfo
|
|
2963 esync = el_ptr(cd.toSymbol());
|
|
2964 }
|
|
2965 else
|
|
2966 { // 'this' is the monitor
|
|
2967 esync = el_var(sthis);
|
|
2968 }
|
|
2969
|
|
2970 if (func.isStatic() || sbody.usesEH() ||
|
|
2971 !(config.flags2 & CFG2.CFG2seh))
|
|
2972 { // BUG: what if frequire or fensure uses EH?
|
|
2973
|
|
2974 sbody = new SynchronizedStatement(func.loc, esync, sbody);
|
|
2975 }
|
|
2976 else
|
|
2977 {
|
|
2978 version (TARGET_WINDOS) {
|
|
2979 if (config.flags2 & CFG2.CFG2seh)
|
|
2980 {
|
|
2981 /* The "jmonitor" uses an optimized exception handling frame
|
|
2982 * which is a little shorter than the more general EH frame.
|
|
2983 * It isn't strictly necessary.
|
|
2984 */
|
|
2985 s.Sfunc.Fflags3 |= Fjmonitor;
|
|
2986 }
|
|
2987 }
|
|
2988 el_free(esync);
|
|
2989 }
|
|
2990 }
|
|
2991 else
|
|
2992 {
|
|
2993 error("synchronized function %s must be a member of a class", func.toChars());
|
|
2994 }
|
|
2995 }
|
|
2996 } else version (TARGET_WINDOS) {
|
|
2997 if (func.isSynchronized() && cd && config.flags2 & CFG2.CFG2seh &&
|
|
2998 !func.isStatic() && !sbody.usesEH())
|
|
2999 {
|
|
3000 /* The "jmonitor" hack uses an optimized exception handling frame
|
|
3001 * which is a little shorter than the more general EH frame.
|
|
3002 */
|
|
3003 s.Sfunc.Fflags3 |= F3.Fjmonitor;
|
|
3004 }
|
|
3005 }
|
|
3006
|
|
3007 sbody.toIR(&irs);
|
|
3008 bx.curblock.BC = BC.BCret;
|
|
3009
|
|
3010 f.Fstartblock = bx.startblock;
|
|
3011 // einit = el_combine(einit,bx.init);
|
|
3012
|
|
3013 if (isCtorDeclaration())
|
|
3014 {
|
|
3015 assert(sthis);
|
|
3016 for (b = f.Fstartblock; b; b = b.Bnext)
|
|
3017 {
|
|
3018 if (b.BC == BC.BCret)
|
|
3019 {
|
|
3020 b.BC = BC.BCretexp;
|
|
3021 b.Belem = el_combine(b.Belem, el_var(sthis));
|
|
3022 }
|
|
3023 }
|
|
3024 }
|
|
3025 }
|
|
3026
|
|
3027 // If static constructor
|
|
3028 if (isStaticConstructor())
|
|
3029 {
|
|
3030 elem* e = el_una(OPER.OPucall, TYM.TYvoid, el_var(s));
|
|
3031 ector = el_combine(ector, e);
|
|
3032 }
|
|
3033
|
|
3034 // If static destructor
|
|
3035 if (isStaticDestructor())
|
|
3036 {
|
|
3037 elem* e;
|
|
3038
|
|
3039 version (STATICCTOR) {
|
|
3040 e = el_bin(OPER.OPcall, TYM.TYvoid, el_var(rtlsym[RTLSYM.RTLSYM_FATEXIT]), el_ptr(s));
|
|
3041 ector = el_combine(ector, e);
|
|
3042 dtorcount++;
|
|
3043 } else {
|
|
3044 StaticDtorDeclaration f2 = isStaticDtorDeclaration();
|
|
3045 assert(f2);
|
|
3046 if (f2.vgate)
|
|
3047 {
|
|
3048 /* Increment destructor's vgate at construction time
|
|
3049 */
|
|
3050 ectorgates.push(cast(void*)f2);
|
|
3051 }
|
|
3052
|
|
3053 e = el_una(OPER.OPucall, TYM.TYvoid, el_var(s));
|
|
3054 edtor = el_combine(e, edtor);
|
|
3055 }
|
|
3056 }
|
|
3057
|
|
3058 // If unit test
|
|
3059 if (isUnitTestDeclaration())
|
|
3060 {
|
|
3061 elem* e = el_una(OPER.OPucall, TYM.TYvoid, el_var(s));
|
|
3062 etest = el_combine(etest, e);
|
|
3063 }
|
|
3064
|
|
3065 if (global.errors)
|
|
3066 return;
|
|
3067
|
|
3068 writefunc(s);
|
|
3069
|
|
3070 if (isExport()) {
|
|
3071 obj_export(s, Poffset);
|
|
3072 }
|
|
3073
|
|
3074 for (i = 0; i < irs.deferToObj.dim; i++)
|
|
3075 {
|
|
3076 Dsymbol ss = cast(Dsymbol)irs.deferToObj.data[i];
|
|
3077 ss.toObjFile(0);
|
|
3078 }
|
|
3079
|
|
3080 version (XXX) { ///TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS
|
|
3081 // A hack to get a pointer to this function put in the .dtors segment
|
|
3082 if (ident && ident.toChars() == "_STD") {
|
|
3083 obj_staticdtor(s);
|
|
3084 }
|
|
3085 }
|
|
3086 version (DMDV2) {
|
|
3087 if (irs.startaddress)
|
|
3088 {
|
|
3089 writef("Setting start address\n");
|
|
3090 obj_startaddress(irs.startaddress);
|
|
3091 }
|
|
3092 }
|
|
3093 }
|
|
3094
|
|
3095 int cvMember(ubyte* p)
|
|
3096 {
|
|
3097 assert(false);
|
|
3098 }
|
|
3099
|
|
3100 /*************************************
|
|
3101 * Closures are implemented by taking the local variables that
|
|
3102 * need to survive the scope of the function, and copying them
|
|
3103 * into a gc allocated chuck of memory. That chunk, called the
|
|
3104 * closure here, is inserted into the linked list of stack
|
|
3105 * frames instead of the usual stack frame.
|
|
3106 *
|
|
3107 * buildClosure() inserts code just after the function prolog
|
|
3108 * is complete. It allocates memory for the closure, allocates
|
|
3109 * a local variable (sclosure) to point to it, inserts into it
|
|
3110 * the link to the enclosing frame, and copies into it the parameters
|
|
3111 * that are referred to in nested functions.
|
|
3112 * In VarExp.toElem and SymOffExp.toElem, when referring to a
|
|
3113 * variable that is in a closure, takes the offset from sclosure rather
|
|
3114 * than from the frame pointer.
|
|
3115 *
|
|
3116 * getEthis() and NewExp.toElem need to use sclosure, if set, rather
|
|
3117 * than the current frame pointer.
|
|
3118 */
|
|
3119 void buildClosure(IRState* irs)
|
|
3120 {
|
|
3121 if (needsClosure())
|
|
3122 {
|
|
3123 // Generate closure on the heap
|
|
3124 // BUG: doesn't capture variadic arguments passed to this function
|
|
3125
|
|
3126 version (DMDV2) {
|
|
3127 /* BUG: doesn't handle destructors for the local variables.
|
|
3128 * The way to do it is to make the closure variables the fields
|
|
3129 * of a class object:
|
|
3130 * class Closure
|
|
3131 * { vtbl[]
|
|
3132 * monitor
|
|
3133 * ptr to destructor
|
|
3134 * sthis
|
|
3135 * ... closure variables ...
|
|
3136 * ~this() { call destructor }
|
|
3137 * }
|
|
3138 */
|
|
3139 }
|
|
3140 //printf("FuncDeclaration.buildClosure()\n");
|
|
3141 Symbol* sclosure;
|
|
3142 sclosure = symbol_name("__closptr".ptr, SC.SCauto, Type.tvoidptr.toCtype());
|
|
3143 sclosure.Sflags |= SFL.SFLtrue | SFL.SFLfree;
|
|
3144 symbol_add(sclosure);
|
|
3145 irs.sclosure = sclosure;
|
|
3146
|
|
3147 uint offset = PTRSIZE; // leave room for previous sthis
|
|
3148 for (int i = 0; i < closureVars.dim; i++)
|
|
3149 {
|
|
3150 VarDeclaration v = cast(VarDeclaration)closureVars.data[i];
|
|
3151 assert(v.isVarDeclaration());
|
|
3152
|
|
3153 version (DMDV2) {
|
|
3154 if (v.needsAutoDtor())
|
|
3155 v.error("has scoped destruction, cannot build closure");
|
|
3156 }
|
|
3157 /* Align and allocate space for v in the closure
|
|
3158 * just like AggregateDeclaration.addField() does.
|
|
3159 */
|
|
3160 uint memsize;
|
|
3161 uint memalignsize;
|
|
3162 uint xalign;
|
|
3163 /// version (DMDV2) {
|
|
3164 if (v.storage_class & STC.STClazy)
|
|
3165 {
|
|
3166 /* Lazy variables are really delegates,
|
|
3167 * so give same answers that TypeDelegate would
|
|
3168 */
|
|
3169 memsize = PTRSIZE * 2;
|
|
3170 memalignsize = memsize;
|
|
3171 xalign = global.structalign;
|
|
3172 }
|
|
3173 else
|
|
3174 /// }
|
|
3175 {
|
|
3176 memsize = cast(uint)v.type.size();
|
|
3177 memalignsize = v.type.alignsize();
|
|
3178 xalign = v.type.memalign(global.structalign);
|
|
3179 }
|
|
3180 AggregateDeclaration.alignmember(xalign, memalignsize, &offset);
|
|
3181 v.offset = offset;
|
|
3182 offset += memsize;
|
|
3183
|
|
3184 /* Can't do nrvo if the variable is put in a closure, since
|
|
3185 * what the shidden points to may no longer exist.
|
|
3186 */
|
|
3187 if (nrvo_can && nrvo_var == v)
|
|
3188 {
|
|
3189 nrvo_can = 0;
|
|
3190 }
|
|
3191 }
|
|
3192 // offset is now the size of the closure
|
|
3193
|
|
3194 // Allocate memory for the closure
|
|
3195 elem* e;
|
|
3196 e = el_long(TYM.TYint, offset);
|
|
3197 e = el_bin(OPER.OPcall, TYM.TYnptr, el_var(rtlsym[RTLSYM.RTLSYM_ALLOCMEMORY]), e);
|
|
3198
|
|
3199 // Assign block of memory to sclosure
|
|
3200 // sclosure = allocmemory(sz);
|
|
3201 e = el_bin(OPER.OPeq, TYM.TYvoid, el_var(sclosure), e);
|
|
3202
|
|
3203 // Set the first element to sthis
|
|
3204 // *(sclosure + 0) = sthis;
|
|
3205 elem* ethis;
|
|
3206 if (irs.sthis)
|
|
3207 ethis = el_var(irs.sthis);
|
|
3208 else
|
|
3209 ethis = el_long(TYM.TYnptr, 0);
|
|
3210 elem *ex = el_una(OPER.OPind, TYM.TYnptr, el_var(sclosure));
|
|
3211 ex = el_bin(OPER.OPeq, TYM.TYnptr, ex, ethis);
|
|
3212 e = el_combine(e, ex);
|
|
3213
|
|
3214 // Copy function parameters into closure
|
|
3215 for (int i = 0; i < closureVars.dim; i++)
|
|
3216 { VarDeclaration v = cast(VarDeclaration)closureVars.data[i];
|
|
3217
|
|
3218 if (!v.isParameter())
|
|
3219 continue;
|
|
3220 TYM tym = v.type.totym();
|
|
3221 if (v.type.toBasetype().ty == TY.Tsarray || v.isOut() || v.isRef())
|
|
3222 tym = TYM.TYnptr; // reference parameters are just pointers
|
|
3223 /// version (DMDV2) {
|
|
3224 else if (v.storage_class & STC.STClazy)
|
|
3225 tym = TYM.TYdelegate;
|
|
3226 /// }
|
|
3227 ex = el_bin(OPER.OPadd, TYM.TYnptr, el_var(sclosure), el_long(TYM.TYint, v.offset));
|
|
3228 ex = el_una(OPER.OPind, tym, ex);
|
|
3229 if (ex.Ety == TYM.TYstruct)
|
|
3230 {
|
|
3231 ex.Enumbytes = cast(uint)v.type.size();
|
|
3232 ex = el_bin(OPER.OPstreq, tym, ex, el_var(v.toSymbol()));
|
|
3233 ex.Enumbytes = cast(uint)v.type.size();
|
|
3234 }
|
|
3235 else
|
|
3236 {
|
|
3237 ex = el_bin(OPER.OPeq, tym, ex, el_var(v.toSymbol()));
|
|
3238 }
|
|
3239
|
|
3240 e = el_combine(e, ex);
|
|
3241 }
|
|
3242
|
|
3243 block_appendexp(irs.blx.curblock, e);
|
|
3244 }
|
|
3245 }
|
|
3246
|
|
3247 FuncDeclaration isFuncDeclaration() { return this; }
|
|
3248 } |