Mercurial > projects > ddmd
annotate dmd/TypeFunction.d @ 132:c494af1dba80
Fixes for dmd 2.037
author | Eldar Insafutdinov <e.insafutdinov@gmail.com> |
---|---|
date | Fri, 10 Sep 2010 19:14:09 +0100 |
parents | 206db751bd4c |
children | af1bebfd96a4 |
rev | line source |
---|---|
0 | 1 module dmd.TypeFunction; |
2 | |
114 | 3 import dmd.common; |
0 | 4 import dmd.TypeNext; |
5 import dmd.TypeSArray; | |
6 import dmd.TypeArray; | |
123 | 7 import dmd.TemplateTupleParameter; |
0 | 8 import dmd.ArrayTypes; |
9 import dmd.LINK; | |
10 import dmd.StructDeclaration; | |
11 import dmd.TypeStruct; | |
12 import dmd.Global; | |
13 import dmd.STC; | |
14 import dmd.MOD; | |
73 | 15 import dmd.PROT; |
123 | 16 import dmd.TypeIdentifier; |
17 import dmd.TemplateParameter; | |
129 | 18 import dmd.TypeInfoFunctionDeclaration; |
123 | 19 import dmd.Tuple; |
0 | 20 import dmd.Type; |
21 import dmd.Loc; | |
22 import dmd.Scope; | |
23 import dmd.Identifier; | |
24 import dmd.OutBuffer; | |
25 import dmd.HdrGenState; | |
26 import dmd.CppMangleState; | |
27 import dmd.TypeInfoDeclaration; | |
28 import dmd.MATCH; | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
29 import dmd.Parameter; |
0 | 30 import dmd.Expression; |
31 import dmd.RET; | |
32 import dmd.TY; | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
33 import dmd.TRUST; |
0 | 34 import dmd.Util; |
131
206db751bd4c
dmdfe 2.037 compiles now
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
130
diff
changeset
|
35 import dmd.FuncDeclaration; |
206db751bd4c
dmdfe 2.037 compiles now
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
130
diff
changeset
|
36 import dmd.Dsymbol; |
123 | 37 import dmd.TemplateInstance : isTuple; |
0 | 38 |
39 import dmd.backend.TYPE; | |
40 import dmd.backend.PARAM; | |
41 import dmd.backend.Util; | |
42 import dmd.backend.TYM; | |
43 import dmd.backend.TF; | |
44 import dmd.backend.mTY; | |
45 | |
46 import core.stdc.stdlib; | |
47 import core.stdc.string; | |
48 | |
129 | 49 import std.stdio; |
50 | |
0 | 51 class TypeFunction : TypeNext |
52 { | |
53 // .next is the return type | |
54 | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
55 Parameters parameters; // function parameters |
0 | 56 int varargs; // 1: T t, ...) style for variable number of arguments |
57 // 2: T t ...) style for variable number of arguments | |
58 bool isnothrow; // true: nothrow | |
59 bool ispure; // true: pure | |
60 bool isproperty; // can be called without parentheses | |
61 bool isref; // true: returns a reference | |
62 LINK linkage; // calling convention | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
63 TRUST trust; // level of trust |
0 | 64 |
65 int inuse; | |
66 | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
67 this(Parameters parameters, Type treturn, int varargs, LINK linkage) |
0 | 68 { |
69 super(TY.Tfunction, treturn); | |
70 | |
71 //if (!treturn) *(char*)0=0; | |
72 // assert(treturn); | |
73 assert(0 <= varargs && varargs <= 2); | |
74 this.parameters = parameters; | |
75 this.varargs = varargs; | |
76 this.linkage = linkage; | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
77 this.trust = TRUSTdefault; |
0 | 78 } |
79 | |
72 | 80 override Type syntaxCopy() |
0 | 81 { |
82 Type treturn = next ? next.syntaxCopy() : null; | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
83 auto params = Parameter.arraySyntaxCopy(parameters); |
0 | 84 TypeFunction t = new TypeFunction(params, treturn, varargs, linkage); |
85 t.mod = mod; | |
86 t.isnothrow = isnothrow; | |
87 t.ispure = ispure; | |
88 t.isproperty = isproperty; | |
89 t.isref = isref; | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
90 t.trust = trust; |
0 | 91 |
92 return t; | |
93 } | |
94 | |
95 version (DumbClone) { | |
96 } else { | |
97 final TypeFunction cloneTo(TypeFunction t) | |
98 { | |
99 super.cloneTo(t); | |
100 | |
101 // these 3 should be set by ctor | |
102 assert(t.parameters is null); | |
103 assert(t.varargs == varargs); | |
104 assert(t.linkage == linkage); | |
105 | |
106 t.isnothrow = isnothrow; | |
107 t.ispure = ispure; | |
108 t.isproperty = isproperty; | |
109 t.isref = isref; | |
110 t.inuse = inuse; | |
111 | |
112 if (parameters) | |
113 { | |
114 t.parameters = parameters.copy(); | |
129 | 115 foreach (arg; parameters) |
0 | 116 { |
117 Argument cpy = arg.clone(); | |
129 | 118 t.parameters[i] = cpy; |
0 | 119 } |
120 } | |
121 | |
122 return t; | |
123 } | |
124 | |
125 TypeFunction clone() | |
126 { | |
129 | 127 assert(this.classinfo is TypeFunction.classinfo); |
0 | 128 return cloneTo(new TypeFunction(null, next, varargs, linkage)); |
129 } | |
130 } | |
72 | 131 override Type semantic(Loc loc, Scope sc) |
0 | 132 { |
133 if (deco) // if semantic() already run | |
134 { | |
135 //printf("already done\n"); | |
136 return this; | |
137 } | |
138 //printf("TypeFunction.semantic() this = %p\n", this); | |
139 //printf("TypeFunction.semantic() %s, sc.stc = %x\n", toChars(), sc.stc); | |
140 | |
141 /* Copy in order to not mess up original. | |
142 * This can produce redundant copies if inferring return type, | |
143 * as semantic() will get called again on this. | |
144 */ | |
145 | |
129 | 146 TypeFunction tf = cloneThis(this); |
0 | 147 |
148 if (sc.stc & STC.STCpure) | |
149 tf.ispure = true; | |
150 if (sc.stc & STC.STCnothrow) | |
151 tf.isnothrow = true; | |
152 if (sc.stc & STC.STCref) | |
153 tf.isref = true; | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
154 if (sc.stc & STCsafe) |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
155 tf.trust = TRUST.TRUSTsafe; |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
156 if (sc.stc & STCtrusted) |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
157 tf.trust = TRUST.TRUSTtrusted; |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
158 if (sc.stc & STCproperty) |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
159 tf.isproperty = true; |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
160 |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
161 tf.linkage = sc.linkage; |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
162 |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
163 /* If the parent is @safe, then this function defaults to safe |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
164 * too. |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
165 */ |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
166 if (tf.trust == TRUST.TRUSTdefault) |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
167 for (Dsymbol p = sc.func; p; p = p.toParent2()) |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
168 { FuncDeclaration fd = p.isFuncDeclaration(); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
169 if (fd) |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
170 { |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
171 if (fd.isSafe()) |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
172 tf.trust = TRUST.TRUSTsafe; // default to @safe |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
173 break; |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
174 } |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
175 } |
0 | 176 |
177 if (tf.next) | |
178 { | |
179 tf.next = tf.next.semantic(loc,sc); | |
96 | 180 version(SARRAYVALUE) {} else |
181 { | |
0 | 182 if (tf.next.toBasetype().ty == TY.Tsarray) |
129 | 183 { |
184 error(loc, "functions cannot return static array %s", tf.next.toChars()); | |
0 | 185 tf.next = Type.terror; |
186 } | |
96 | 187 } |
0 | 188 if (tf.next.toBasetype().ty == TY.Tfunction) |
129 | 189 { |
190 error(loc, "functions cannot return a function"); | |
0 | 191 tf.next = Type.terror; |
192 } | |
193 if (tf.next.toBasetype().ty == TY.Ttuple) | |
129 | 194 { |
195 error(loc, "functions cannot return a tuple"); | |
0 | 196 tf.next = Type.terror; |
197 } | |
198 if (tf.next.isauto() && !(sc.flags & SCOPE.SCOPEctor)) | |
129 | 199 error(loc, "functions cannot return scope %s", tf.next.toChars()); |
0 | 200 } |
201 | |
202 if (tf.parameters) | |
73 | 203 { |
204 /* Create a scope for evaluating the default arguments for the parameters | |
205 */ | |
206 Scope argsc = sc.push(); | |
207 argsc.stc = STCundefined; // don't inherit storage class | |
208 argsc.protection = PROT.PROTpublic; | |
209 | |
131
206db751bd4c
dmdfe 2.037 compiles now
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
130
diff
changeset
|
210 size_t dim = Parameter.dim(tf.parameters); |
0 | 211 |
212 for (size_t i = 0; i < dim; i++) | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
213 { auto arg = Parameter.getNth(tf.parameters, i); |
0 | 214 |
215 tf.inuse++; | |
73 | 216 arg.type = arg.type.semantic(loc, argsc); |
0 | 217 if (tf.inuse == 1) tf.inuse--; |
218 | |
219 arg.type = arg.type.addStorageClass(arg.storageClass); | |
220 | |
221 if (arg.storageClass & (STC.STCauto | STC.STCalias | STC.STCstatic)) | |
222 { | |
223 if (!arg.type) | |
224 continue; | |
225 } | |
226 | |
227 Type t = arg.type.toBasetype(); | |
228 | |
229 if (arg.storageClass & (STC.STCout | STC.STCref | STC.STClazy)) | |
230 { | |
96 | 231 //if (t.ty == TY.Tsarray) |
232 //error(loc, "cannot have out or ref parameter of type %s", t.toChars()); | |
233 if (arg.storageClass & STC.STCout && arg.type.mod & (STCconst | STCimmutable)) | |
234 error(loc, "cannot have const or immutabl out parameter of type %s", t.toChars()); | |
0 | 235 } |
236 if (!(arg.storageClass & STC.STClazy) && t.ty == TY.Tvoid) | |
237 error(loc, "cannot have parameter of type %s", arg.type.toChars()); | |
238 | |
239 if (arg.defaultArg) | |
240 { | |
73 | 241 arg.defaultArg = arg.defaultArg.semantic(argsc); |
242 arg.defaultArg = resolveProperties(argsc, arg.defaultArg); | |
243 arg.defaultArg = arg.defaultArg.implicitCastTo(argsc, arg.type); | |
0 | 244 } |
245 | |
246 /* If arg turns out to be a tuple, the number of parameters may | |
247 * change. | |
248 */ | |
249 if (t.ty == TY.Ttuple) | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
250 { dim = Parameter.dim(tf.parameters); |
0 | 251 i--; |
252 } | |
253 } | |
73 | 254 argsc.pop(); |
0 | 255 } |
256 if (tf.next) | |
257 tf.deco = tf.merge().deco; | |
258 | |
259 if (tf.inuse) | |
260 { error(loc, "recursive type"); | |
261 tf.inuse = 0; | |
262 return terror; | |
263 } | |
264 | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
265 if (tf.isproperty && (tf.varargs || Parameter.dim(tf.parameters) > 1)) |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
266 error(loc, "properties can only have zero or one parameter"); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
267 |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
268 if (tf.varargs == 1 && tf.linkage != LINK.LINKd && Parameter.dim(tf.parameters) == 0) |
0 | 269 error(loc, "variadic functions with non-D linkage must have at least one parameter"); |
270 | |
271 /* Don't return merge(), because arg identifiers and default args | |
272 * can be different | |
273 * even though the types match | |
274 */ | |
275 return tf; | |
276 } | |
277 | |
72 | 278 override void toDecoBuffer(OutBuffer buf, int flag) |
0 | 279 { |
280 ubyte mc; | |
281 | |
282 //printf("TypeFunction.toDecoBuffer() this = %p %s\n", this, toChars()); | |
283 //static int nest; if (++nest == 50) *(char*)0=0; | |
284 if (inuse) | |
285 { | |
286 inuse = 2; // flag error to caller | |
287 return; | |
288 } | |
289 inuse++; | |
290 static if (true) { | |
291 if (mod & MOD.MODshared) | |
292 buf.writeByte('O'); | |
293 if (mod & MOD.MODconst) | |
294 buf.writeByte('x'); | |
295 else if (mod & MOD.MODinvariant) | |
296 buf.writeByte('y'); | |
297 } | |
298 switch (linkage) | |
299 { | |
300 case LINK.LINKd: mc = 'F'; break; | |
301 case LINK.LINKc: mc = 'U'; break; | |
302 case LINK.LINKwindows: mc = 'W'; break; | |
303 case LINK.LINKpascal: mc = 'V'; break; | |
304 case LINK.LINKcpp: mc = 'R'; break; | |
305 } | |
306 buf.writeByte(mc); | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
307 if (ispure || isnothrow || isproperty || isref || trust) |
0 | 308 { |
309 if (ispure) | |
310 buf.writestring("Na"); | |
311 if (isnothrow) | |
312 buf.writestring("Nb"); | |
313 if (isref) | |
314 buf.writestring("Nc"); | |
315 if (isproperty) | |
316 buf.writestring("Nd"); | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
317 switch (trust) |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
318 { |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
319 case TRUST.TRUSTtrusted: |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
320 buf.writestring("Ne"); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
321 break; |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
322 case TRUST.TRUSTsafe: |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
323 buf.writestring("Nd"); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
324 break; |
132
c494af1dba80
Fixes for dmd 2.037
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
131
diff
changeset
|
325 default: |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
326 } |
0 | 327 } |
328 // Write argument types | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
329 Parameter.argsToDecoBuffer(buf, parameters); |
0 | 330 //if (buf.data[buf.offset - 1] == '@') halt(); |
331 buf.writeByte('Z' - varargs); // mark end of arg list | |
79 | 332 assert(next); |
0 | 333 next.toDecoBuffer(buf); |
334 inuse--; | |
335 } | |
336 | |
72 | 337 override void toCBuffer(OutBuffer buf, Identifier ident, HdrGenState* hgs) |
0 | 338 { |
339 //printf("TypeFunction.toCBuffer() this = %p\n", this); | |
340 string p = null; | |
341 | |
342 if (inuse) | |
343 { | |
344 inuse = 2; // flag error to caller | |
345 return; | |
346 } | |
347 inuse++; | |
348 | |
349 /* Use 'storage class' style for attributes | |
350 */ | |
351 if (mod & MODconst) | |
352 buf.writestring("const "); | |
353 if (mod & MODinvariant) | |
354 buf.writestring("immutable "); | |
355 if (mod & MODshared) | |
356 buf.writestring("shared "); | |
357 | |
358 if (ispure) | |
359 buf.writestring("pure "); | |
360 if (isnothrow) | |
361 buf.writestring("nothrow "); | |
362 if (isproperty) | |
363 buf.writestring("@property "); | |
364 if (isref) | |
365 buf.writestring("ref "); | |
366 | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
367 switch (trust) |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
368 { |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
369 case TRUST.TRUSTtrusted: |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
370 buf.writestring("@trusted "); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
371 break; |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
372 |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
373 case TRUST.TRUSTsafe: |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
374 buf.writestring("@safe "); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
375 break; |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
376 } |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
377 |
0 | 378 if (next && (!ident || ident.toHChars2() == ident.toChars())) |
379 next.toCBuffer2(buf, hgs, MODundefined); | |
380 if (hgs.ddoc != 1) | |
381 { | |
382 switch (linkage) | |
383 { | |
384 case LINKd: p = null; break; | |
73 | 385 case LINKc: p = " C"; break; |
386 case LINKwindows: p = " Windows"; break; | |
387 case LINKpascal: p = " Pascal"; break; | |
388 case LINKcpp: p = " C++"; break; | |
0 | 389 default: |
390 assert(0); | |
391 } | |
392 } | |
393 | |
394 if (!hgs.hdrgen && p) | |
395 buf.writestring(p); | |
396 if (ident) | |
397 { | |
398 buf.writeByte(' '); | |
399 buf.writestring(ident.toHChars2()); | |
400 } | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
401 Parameter.argsToCBuffer(buf, hgs, parameters, varargs); |
0 | 402 inuse--; |
403 } | |
404 | |
72 | 405 override void toCBuffer2(OutBuffer buf, HdrGenState* hgs, MOD mod) |
0 | 406 { |
407 //printf("TypeFunction::toCBuffer2() this = %p, ref = %d\n", this, isref); | |
408 string p; | |
409 | |
410 if (inuse) | |
411 { | |
412 inuse = 2; // flag error to caller | |
413 return; | |
414 } | |
415 | |
416 inuse++; | |
417 if (next) | |
418 next.toCBuffer2(buf, hgs, MODundefined); | |
419 | |
420 if (hgs.ddoc != 1) | |
421 { | |
422 switch (linkage) | |
423 { | |
424 case LINKd: p = null; break; | |
425 case LINKc: p = "C "; break; | |
426 case LINKwindows: p = "Windows "; break; | |
427 case LINKpascal: p = "Pascal "; break; | |
428 case LINKcpp: p = "C++ "; break; | |
429 default: assert(0); | |
430 } | |
431 } | |
432 | |
433 if (!hgs.hdrgen && p) | |
434 buf.writestring(p); | |
435 buf.writestring(" function"); | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
436 Parameter.argsToCBuffer(buf, hgs, parameters, varargs); |
0 | 437 |
438 /* Use postfix style for attributes | |
439 */ | |
440 if (mod != this.mod) | |
441 { | |
442 modToBuffer(buf); | |
443 } | |
444 | |
445 if (ispure) | |
446 buf.writestring(" pure"); | |
447 if (isnothrow) | |
448 buf.writestring(" nothrow"); | |
449 if (isproperty) | |
450 buf.writestring(" @property"); | |
451 if (isref) | |
452 buf.writestring(" ref"); | |
453 | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
454 switch (trust) |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
455 { |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
456 case TRUSTtrusted: |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
457 buf.writestring(" @trusted"); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
458 break; |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
459 |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
460 case TRUSTsafe: |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
461 buf.writestring(" @safe"); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
462 break; |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
463 } |
0 | 464 inuse--; |
465 } | |
466 | |
72 | 467 override MATCH deduceType(Scope sc, Type tparam, TemplateParameters parameters, Objects dedtypes) |
0 | 468 { |
123 | 469 //printf("TypeFunction.deduceType()\n"); |
470 //printf("\tthis = %d, ", ty); print(); | |
471 //printf("\ttparam = %d, ", tparam.ty); tparam.print(); | |
472 | |
473 // Extra check that function characteristics must match | |
474 if (tparam && tparam.ty == Tfunction) | |
475 { | |
476 TypeFunction tp = cast(TypeFunction)tparam; | |
477 if (varargs != tp.varargs || | |
478 linkage != tp.linkage) | |
479 return MATCHnomatch; | |
480 | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
481 size_t nfargs = Parameter.dim(this.parameters); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
482 size_t nfparams = Parameter.dim(tp.parameters); |
123 | 483 |
484 /* See if tuple match | |
485 */ | |
486 if (nfparams > 0 && nfargs >= nfparams - 1) | |
487 { | |
488 /* See if 'A' of the template parameter matches 'A' | |
489 * of the type of the last function parameter. | |
490 */ | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
491 auto fparam = Parameter.getNth(tp.parameters, nfparams - 1); |
123 | 492 assert(fparam); |
493 assert(fparam.type); | |
494 if (fparam.type.ty != Tident) | |
495 goto L1; | |
496 TypeIdentifier tid = cast(TypeIdentifier)fparam.type; | |
497 if (tid.idents.dim) | |
498 goto L1; | |
499 | |
500 /* Look through parameters to find tuple matching tid.ident | |
501 */ | |
502 size_t tupi = 0; | |
503 for (; 1; tupi++) | |
504 { | |
505 if (tupi == parameters.dim) | |
506 goto L1; | |
507 TemplateParameter t = parameters[tupi]; | |
508 TemplateTupleParameter tup = t.isTemplateTupleParameter(); | |
509 if (tup && tup.ident.equals(tid.ident)) | |
510 break; | |
511 } | |
512 | |
513 /* The types of the function arguments [nfparams - 1 .. nfargs] | |
514 * now form the tuple argument. | |
515 */ | |
516 int tuple_dim = nfargs - (nfparams - 1); | |
517 | |
518 /* See if existing tuple, and whether it matches or not | |
519 */ | |
520 Object o = dedtypes[tupi]; | |
521 if (o) | |
522 { | |
523 // Existing deduced argument must be a tuple, and must match | |
524 Tuple t = isTuple(o); | |
525 if (!t || t.objects.dim != tuple_dim) | |
526 return MATCHnomatch; | |
527 for (size_t i = 0; i < tuple_dim; i++) | |
528 { | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
529 auto arg = Parameter.getNth(this.parameters, nfparams - 1 + i); |
123 | 530 if (!arg.type.equals(t.objects[i])) |
531 return MATCHnomatch; | |
532 } | |
533 } | |
534 else | |
535 { // Create new tuple | |
536 Tuple t = new Tuple(); | |
537 t.objects.setDim(tuple_dim); | |
538 for (size_t i = 0; i < tuple_dim; i++) | |
539 { | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
540 auto arg = Parameter.getNth(this.parameters, nfparams - 1 + i); |
123 | 541 t.objects[i] = arg.type; |
542 } | |
543 dedtypes[tupi] = t; | |
544 } | |
545 nfparams--; // don't consider the last parameter for type deduction | |
546 goto L2; | |
547 } | |
548 | |
549 L1: | |
550 if (nfargs != nfparams) | |
551 return MATCHnomatch; | |
552 L2: | |
553 for (size_t i = 0; i < nfparams; i++) | |
554 { | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
555 auto a = Parameter.getNth(this.parameters, i); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
556 auto ap = Parameter.getNth(tp.parameters, i); |
123 | 557 if (a.storageClass != ap.storageClass || |
558 !a.type.deduceType(sc, ap.type, parameters, dedtypes)) | |
559 return MATCHnomatch; | |
560 } | |
561 } | |
562 return Type.deduceType(sc, tparam, parameters, dedtypes); | |
0 | 563 } |
564 | |
72 | 565 override TypeInfoDeclaration getTypeInfoDeclaration() |
0 | 566 { |
129 | 567 return new TypeInfoFunctionDeclaration(this); |
0 | 568 } |
569 | |
72 | 570 override Type reliesOnTident() |
0 | 571 { |
572 if (parameters) | |
573 { | |
126
1765f3ef917d
ClassDeclarations, Arguments -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
123
diff
changeset
|
574 foreach (arg; parameters) |
0 | 575 { |
576 Type t = arg.type.reliesOnTident(); | |
577 if (t) | |
578 return t; | |
579 } | |
580 } | |
581 return next.reliesOnTident(); | |
582 } | |
583 | |
584 version (CPP_MANGLE) { | |
585 void toCppMangle(OutBuffer buf, CppMangleState* cms) | |
586 { | |
587 assert(false); | |
588 } | |
589 } | |
590 | |
591 /*************************** | |
592 * Examine function signature for parameter p and see if | |
593 * p can 'escape' the scope of the function. | |
594 */ | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
595 bool parameterEscapes(Parameter p) |
0 | 596 { |
597 /* Scope parameters do not escape. | |
598 * Allow 'lazy' to imply 'scope' - | |
599 * lazy parameters can be passed along | |
600 * as lazy parameters to the next function, but that isn't | |
601 * escaping. | |
602 */ | |
603 if (p.storageClass & (STC.STCscope | STC.STClazy)) | |
604 return false; | |
605 | |
606 if (ispure) | |
607 { /* With pure functions, we need only be concerned if p escapes | |
608 * via any return statement. | |
609 */ | |
610 Type tret = nextOf().toBasetype(); | |
611 if (!isref && !tret.hasPointers()) | |
612 { /* The result has no references, so p could not be escaping | |
613 * that way. | |
614 */ | |
615 return false; | |
616 } | |
617 } | |
618 | |
619 /* Assume it escapes in the absence of better information. | |
620 */ | |
621 return true; | |
622 } | |
623 | |
624 /******************************** | |
625 * 'args' are being matched to function 'this' | |
626 * Determine match level. | |
627 * Returns: | |
628 * MATCHxxxx | |
629 */ | |
630 MATCH callMatch(Expression ethis, Expressions args) | |
631 { | |
632 //printf("TypeFunction.callMatch() %s\n", toChars()); | |
633 MATCH match = MATCH.MATCHexact; // assume exact match | |
634 | |
635 if (ethis) | |
636 { | |
637 Type t = ethis.type; | |
638 if (t.toBasetype().ty == TY.Tpointer) | |
639 t = t.toBasetype().nextOf(); // change struct* to struct | |
640 | |
641 if (t.mod != mod) | |
642 { | |
643 if (mod == MOD.MODconst) | |
644 match = MATCH.MATCHconst; | |
645 else | |
646 return MATCH.MATCHnomatch; | |
647 } | |
648 } | |
649 | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
650 size_t nparams = Parameter.dim(parameters); |
0 | 651 size_t nargs = args ? args.dim : 0; |
652 if (nparams == nargs) { | |
653 ; | |
654 } else if (nargs > nparams) | |
655 { | |
656 if (varargs == 0) | |
657 goto Nomatch; // too many args; no match | |
658 match = MATCH.MATCHconvert; // match ... with a "conversion" match level | |
659 } | |
660 | |
661 for (size_t u = 0; u < nparams; u++) | |
662 { | |
663 MATCH m; | |
664 Expression arg; | |
665 | |
666 // BUG: what about out and ref? | |
667 | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
668 auto p = Parameter.getNth(parameters, u); |
0 | 669 assert(p); |
670 if (u >= nargs) | |
671 { | |
672 if (p.defaultArg) | |
673 continue; | |
674 if (varargs == 2 && u + 1 == nparams) | |
675 goto L1; | |
676 goto Nomatch; // not enough arguments | |
677 } | |
678 | |
113
3482c73a991b
More cleanup for arrays
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
96
diff
changeset
|
679 arg = cast(Expression)args[u]; |
0 | 680 assert(arg); |
96 | 681 // writef("arg: %s, type: %s\n", arg.toChars(), arg.type.toChars()); |
682 | |
0 | 683 |
684 // Non-lvalues do not match ref or out parameters | |
96 | 685 if (p.storageClass & (STC.STCref | STC.STCout)) |
686 { | |
687 if (!arg.isLvalue()) | |
688 goto Nomatch; | |
689 } | |
690 | |
691 if (p.storageClass & STCref) | |
692 { | |
693 /* Don't allow static arrays to be passed to mutable refereces | |
694 * to static arrays if the argument cannot be modified. | |
695 */ | |
696 Type targb = arg.type.toBasetype(); | |
697 Type tparb = p.type.toBasetype(); | |
698 //writef("%s\n", targb.toChars()); | |
699 //writef("%s\n", tparb.toChars()); | |
700 if (targb.nextOf() && tparb.ty == Tsarray && | |
701 targb.nextOf().mod != tparb.nextOf().mod && | |
702 !tparb.nextOf().isConst()) | |
703 goto Nomatch; | |
704 } | |
0 | 705 |
706 if (p.storageClass & STC.STClazy && p.type.ty == TY.Tvoid && arg.type.ty != TY.Tvoid) | |
707 m = MATCH.MATCHconvert; | |
708 else | |
709 m = arg.implicitConvTo(p.type); | |
710 //printf("\tm = %d\n", m); | |
711 if (m == MATCH.MATCHnomatch) // if no match | |
712 { | |
713 L1: | |
714 if (varargs == 2 && u + 1 == nparams) // if last varargs param | |
715 { | |
716 Type tb = p.type.toBasetype(); | |
717 TypeSArray tsa; | |
718 long sz; | |
719 | |
720 switch (tb.ty) | |
721 { | |
722 case TY.Tsarray: | |
723 tsa = cast(TypeSArray)tb; | |
724 sz = tsa.dim.toInteger(); | |
725 if (sz != nargs - u) | |
726 goto Nomatch; | |
727 case TY.Tarray: | |
728 { | |
729 TypeArray ta = cast(TypeArray)tb; | |
730 for (; u < nargs; u++) | |
731 { | |
113
3482c73a991b
More cleanup for arrays
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
96
diff
changeset
|
732 arg = cast(Expression)args[u]; |
0 | 733 assert(arg); |
734 static if (true) { | |
735 /* If lazy array of delegates, | |
736 * convert arg(s) to delegate(s) | |
737 */ | |
738 Type tret = p.isLazyArray(); | |
739 if (tret) | |
740 { | |
741 if (ta.next.equals(arg.type)) | |
742 { | |
743 m = MATCH.MATCHexact; | |
744 } | |
745 else | |
746 { | |
747 m = arg.implicitConvTo(tret); | |
748 if (m == MATCH.MATCHnomatch) | |
749 { | |
750 if (tret.toBasetype().ty == TY.Tvoid) | |
751 m = MATCH.MATCHconvert; | |
752 } | |
753 } | |
754 } | |
755 else | |
756 m = arg.implicitConvTo(ta.next); | |
757 } else { | |
758 m = arg.implicitConvTo(ta.next); | |
759 } | |
760 if (m == MATCH.MATCHnomatch) | |
761 goto Nomatch; | |
762 | |
763 if (m < match) | |
764 match = m; | |
765 } | |
766 goto Ldone; | |
767 } | |
768 | |
769 case TY.Tclass: | |
770 // Should see if there's a constructor match? | |
771 // Or just leave it ambiguous? | |
772 goto Ldone; | |
773 | |
774 default: | |
775 goto Nomatch; | |
776 } | |
777 } | |
778 | |
779 goto Nomatch; | |
780 } | |
781 | |
782 if (m < match) | |
783 match = m; // pick worst match | |
784 } | |
785 | |
786 Ldone: | |
787 //printf("match = %d\n", match); | |
788 return match; | |
789 | |
790 Nomatch: | |
791 //printf("no match\n"); | |
792 return MATCH.MATCHnomatch; | |
793 } | |
794 | |
96 | 795 override type* toCtype() |
0 | 796 { |
797 if (ctype) { | |
798 return ctype; | |
799 } | |
800 | |
801 type* t; | |
802 if (true) | |
803 { | |
804 param_t* paramtypes; | |
805 tym_t tyf; | |
806 type* tp; | |
807 | |
808 paramtypes = null; | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
809 size_t nparams = Parameter.dim(parameters); |
0 | 810 for (size_t i = 0; i < nparams; i++) |
811 { | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
129
diff
changeset
|
812 auto arg = Parameter.getNth(parameters, i); |
0 | 813 tp = arg.type.toCtype(); |
814 if (arg.storageClass & (STC.STCout | STC.STCref)) | |
815 { | |
816 // C doesn't have reference types, so it's really a pointer | |
817 // to the parameter type | |
818 tp = type_allocn(TYM.TYref, tp); | |
819 } | |
820 param_append_type(¶mtypes,tp); | |
821 } | |
822 tyf = totym(); | |
823 t = type_alloc(tyf); | |
824 t.Tflags |= TF.TFprototype; | |
825 if (varargs != 1) | |
826 t.Tflags |= TF.TFfixed; | |
827 ctype = t; | |
828 t.Tnext = next.toCtype(); | |
829 t.Tnext.Tcount++; | |
830 t.Tparamtypes = paramtypes; | |
831 } | |
832 ctype = t; | |
833 return t; | |
834 } | |
835 | |
836 /*************************** | |
837 * Determine return style of function - whether in registers or | |
838 * through a hidden pointer to the caller's stack. | |
839 */ | |
96 | 840 RET retStyle() |
0 | 841 { |
842 //printf("TypeFunction.retStyle() %s\n", toChars()); | |
95 | 843 version (DMDV2) |
844 { | |
0 | 845 if (isref) |
846 return RET.RETregs; // returns a pointer | |
847 } | |
848 | |
849 Type tn = next.toBasetype(); | |
95 | 850 Type tns = tn; |
851 ulong sz = tn.size(); | |
0 | 852 |
95 | 853 version(SARRAYVALUE) |
854 { | |
855 if (tn.ty == Tsarray) | |
856 { | |
857 do | |
858 { | |
859 tns = tns.nextOf().toBasetype(); | |
860 } while (tns.ty == Tsarray); | |
861 if (tns.ty != Tstruct) | |
862 { | |
863 if (global.params.isLinux && linkage != LINKd) | |
864 {} | |
865 else | |
866 { | |
867 switch (sz) | |
868 { case 1: | |
869 case 2: | |
870 case 4: | |
871 case 8: | |
96 | 872 return RET.RETregs; // return small structs in regs |
873 // (not 3 byte structs!) | |
95 | 874 default: |
875 break; | |
876 } | |
877 } | |
96 | 878 return RET.RETstack; |
95 | 879 } |
880 } | |
881 } | |
882 if (tns.ty == TY.Tstruct) | |
0 | 883 { |
884 StructDeclaration sd = (cast(TypeStruct)tn).sym; | |
885 if (global.params.isLinux && linkage != LINK.LINKd) { | |
886 ; | |
887 } | |
95 | 888 ///version (DMDV2) { // TODO: |
889 else if (sd.dtor || sd.cpctor) | |
890 { | |
0 | 891 } |
892 ///} | |
893 else | |
894 { | |
95 | 895 switch (sz) |
0 | 896 { |
897 case 1: | |
898 case 2: | |
899 case 4: | |
900 case 8: | |
901 return RET.RETregs; // return small structs in regs | |
902 // (not 3 byte structs!) | |
903 default: | |
904 break; | |
905 } | |
906 } | |
907 return RET.RETstack; | |
908 } | |
909 else if ((global.params.isLinux || global.params.isOSX || global.params.isFreeBSD || global.params.isSolaris) && | |
910 linkage == LINK.LINKc && | |
911 tn.iscomplex()) | |
912 { | |
913 if (tn.ty == TY.Tcomplex32) | |
914 return RET.RETregs; // in EDX:EAX, not ST1:ST0 | |
915 else | |
916 return RET.RETstack; | |
917 } | |
918 else | |
919 return RET.RETregs; | |
920 } | |
921 | |
72 | 922 override TYM totym() |
0 | 923 { |
924 TYM tyf; | |
925 | |
926 //printf("TypeFunction.totym(), linkage = %d\n", linkage); | |
927 switch (linkage) | |
928 { | |
929 case LINK.LINKwindows: | |
930 tyf = (varargs == 1) ? TYM.TYnfunc : TYM.TYnsfunc; | |
931 break; | |
932 | |
933 case LINK.LINKpascal: | |
934 tyf = (varargs == 1) ? TYM.TYnfunc : TYM.TYnpfunc; | |
935 break; | |
936 | |
937 case LINK.LINKc: | |
938 tyf = TYM.TYnfunc; | |
22
fd4acc376c45
Implemented object file output and linking on linux.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
939 version (POSIX) {///TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS |
0 | 940 if (retStyle() == RET.RETstack) |
941 tyf = TYM.TYhfunc; | |
942 } | |
943 break; | |
944 | |
945 case LINK.LINKd: | |
946 tyf = (varargs == 1) ? TYM.TYnfunc : TYM.TYjfunc; | |
947 break; | |
948 | |
949 case LINK.LINKcpp: | |
950 tyf = TYM.TYnfunc; | |
951 break; | |
952 | |
953 default: | |
954 writef("linkage = %d\n", linkage); | |
955 assert(0); | |
956 } | |
957 version (DMDV2) { | |
958 if (isnothrow) | |
959 tyf |= mTY.mTYnothrow; | |
960 } | |
961 return tyf; | |
962 } | |
22
fd4acc376c45
Implemented object file output and linking on linux.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
963 } |