Internally these would treat the cast same as a normal conversion from int[7] to int[], which allows code at CTFE to erroneously succeed where it would raise a SEGV at run-time.
1 |
/**
|
|
2 |
* Struct and union declarations.
|
|
3 |
*
|
|
4 |
* Specification: $(LINK2 https://dlang.org/spec/struct.html, Structs, Unions)
|
|
5 |
*
|
|
6 |
* Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
|
|
7 |
* Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
|
|
8 |
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
|
|
9 |
* Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dstruct.d, _dstruct.d)
|
|
10 |
* Documentation: https://dlang.org/phobos/dmd_dstruct.html
|
|
11 |
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dstruct.d
|
|
12 |
*/
|
|
13 |
|
|
14 |
module dmd.dstruct; |
|
15 |
|
|
16 |
import dmd.aggregate; |
|
17 |
import dmd.arraytypes; |
|
18 |
import dmd.declaration; |
|
19 |
import dmd.dmodule; |
|
20 |
import dmd.dscope; |
|
21 |
import dmd.dsymbol; |
|
22 |
import dmd.dsymbolsem; |
|
23 |
import dmd.dtemplate; |
|
24 |
import dmd.errors; |
|
25 |
import dmd.expression; |
|
26 |
import dmd.expressionsem; |
|
27 |
import dmd.func; |
|
28 |
import dmd.globals; |
|
29 |
import dmd.id; |
|
30 |
import dmd.identifier; |
|
31 |
import dmd.mtype; |
|
32 |
import dmd.opover; |
|
33 |
import dmd.semantic3; |
|
34 |
import dmd.target; |
|
35 |
import dmd.tokens; |
|
36 |
import dmd.typesem; |
|
37 |
import dmd.typinf; |
|
38 |
import dmd.visitor; |
|
39 |
|
|
40 |
/***************************************
|
|
41 |
* Search sd for a member function of the form:
|
|
42 |
* `extern (D) string toString();`
|
|
43 |
* Params:
|
|
44 |
* sd = struct declaration to search
|
|
45 |
* Returns:
|
|
46 |
* FuncDeclaration of `toString()` if found, `null` if not
|
|
47 |
*/
|
|
48 |
extern (C++) FuncDeclaration search_toString(StructDeclaration sd) |
|
49 |
{
|
|
50 | 1 |
Dsymbol s = search_function(sd, Id.tostring); |
51 | 1 |
FuncDeclaration fd = s ? s.isFuncDeclaration() : null; |
52 | 1 |
if (fd) |
53 |
{
|
|
54 | 1 |
__gshared TypeFunction tftostring; |
55 | 1 |
if (!tftostring) |
56 |
{
|
|
57 | 1 |
tftostring = new TypeFunction(ParameterList(), Type.tstring, LINK.d); |
58 | 1 |
tftostring = tftostring.merge().toTypeFunction(); |
59 |
}
|
|
60 | 1 |
fd = fd.overloadExactMatch(tftostring); |
61 |
}
|
|
62 | 1 |
return fd; |
63 |
}
|
|
64 |
|
|
65 |
/***************************************
|
|
66 |
* Request additional semantic analysis for TypeInfo generation.
|
|
67 |
* Params:
|
|
68 |
* sc = context
|
|
69 |
* t = type that TypeInfo is being generated for
|
|
70 |
*/
|
|
71 |
extern (C++) void semanticTypeInfo(Scope* sc, Type t) |
|
72 |
{
|
|
73 | 1 |
if (sc) |
74 |
{
|
|
75 | 1 |
if (sc.intypeof) |
76 | 1 |
return; |
77 | 1 |
if (sc.flags & (SCOPE.ctfe | SCOPE.compile)) |
78 | 1 |
return; |
79 |
}
|
|
80 |
|
|
81 | 1 |
if (!t) |
82 | 1 |
return; |
83 |
|
|
84 |
void visitVector(TypeVector t) |
|
85 |
{
|
|
86 | 1 |
semanticTypeInfo(sc, t.basetype); |
87 |
}
|
|
88 |
|
|
89 |
void visitAArray(TypeAArray t) |
|
90 |
{
|
|
91 | 1 |
semanticTypeInfo(sc, t.index); |
92 | 1 |
semanticTypeInfo(sc, t.next); |
93 |
}
|
|
94 |
|
|
95 |
void visitStruct(TypeStruct t) |
|
96 |
{
|
|
97 |
//printf("semanticTypeInfo.visit(TypeStruct = %s)\n", t.toChars());
|
|
98 | 1 |
StructDeclaration sd = t.sym; |
99 |
|
|
100 |
/* Step 1: create TypeInfoDeclaration
|
|
101 |
*/
|
|
102 | 1 |
if (!sc) // inline may request TypeInfo. |
103 |
{
|
|
104 | 1 |
Scope scx; |
105 | 1 |
scx._module = sd.getModule(); |
106 | 1 |
getTypeInfoType(sd.loc, t, &scx); |
107 | 1 |
sd.requestTypeInfo = true; |
108 |
}
|
|
109 | 1 |
else if (!sc.minst) |
110 |
{
|
|
111 |
// don't yet have to generate TypeInfo instance if
|
|
112 |
// the typeid(T) expression exists in speculative scope.
|
|
113 |
}
|
|
114 |
else
|
|
115 |
{
|
|
116 | 1 |
getTypeInfoType(sd.loc, t, sc); |
117 | 1 |
sd.requestTypeInfo = true; |
118 |
|
|
119 |
// https://issues.dlang.org/show_bug.cgi?id=15149
|
|
120 |
// if the typeid operand type comes from a
|
|
121 |
// result of auto function, it may be yet speculative.
|
|
122 |
// unSpeculative(sc, sd);
|
|
123 |
}
|
|
124 |
|
|
125 |
/* Step 2: If the TypeInfo generation requires sd.semantic3, run it later.
|
|
126 |
* This should be done even if typeid(T) exists in speculative scope.
|
|
127 |
* Because it may appear later in non-speculative scope.
|
|
128 |
*/
|
|
129 | 1 |
if (!sd.members) |
130 | 1 |
return; // opaque struct |
131 | 1 |
if (!sd.xeq && !sd.xcmp && !sd.postblit && !sd.dtor && !sd.xhash && !search_toString(sd)) |
132 | 1 |
return; // none of TypeInfo-specific members |
133 |
|
|
134 |
// If the struct is in a non-root module, run semantic3 to get
|
|
135 |
// correct symbols for the member function.
|
|
136 | 1 |
if (sd.semanticRun >= PASS.semantic3) |
137 |
{
|
|
138 |
// semantic3 is already done
|
|
139 |
}
|
|
140 | 1 |
else if (TemplateInstance ti = sd.isInstantiated()) |
141 |
{
|
|
142 | 1 |
if (ti.minst && !ti.minst.isRoot()) |
143 | 1 |
Module.addDeferredSemantic3(sd); |
144 |
}
|
|
145 |
else
|
|
146 |
{
|
|
147 | 1 |
if (sd.inNonRoot()) |
148 |
{
|
|
149 |
//printf("deferred sem3 for TypeInfo - sd = %s, inNonRoot = %d\n", sd.toChars(), sd.inNonRoot());
|
|
150 | 1 |
Module.addDeferredSemantic3(sd); |
151 |
}
|
|
152 |
}
|
|
153 |
}
|
|
154 |
|
|
155 |
void visitTuple(TypeTuple t) |
|
156 |
{
|
|
157 | 1 |
if (t.arguments) |
158 |
{
|
|
159 | 1 |
foreach (arg; *t.arguments) |
160 |
{
|
|
161 | 1 |
semanticTypeInfo(sc, arg.type); |
162 |
}
|
|
163 |
}
|
|
164 |
}
|
|
165 |
|
|
166 |
/* Note structural similarity of this Type walker to that in isSpeculativeType()
|
|
167 |
*/
|
|
168 |
|
|
169 | 1 |
Type tb = t.toBasetype(); |
170 | 1 |
switch (tb.ty) |
171 |
{
|
|
172 | 1 |
case Tvector: visitVector(tb.isTypeVector()); break; |
173 | 1 |
case Taarray: visitAArray(tb.isTypeAArray()); break; |
174 | 1 |
case Tstruct: visitStruct(tb.isTypeStruct()); break; |
175 | 1 |
case Ttuple: visitTuple (tb.isTypeTuple()); break; |
176 |
|
|
177 | 1 |
case Tclass: |
178 | 1 |
case Tenum: break; |
179 |
|
|
180 | 1 |
default: semanticTypeInfo(sc, tb.nextOf()); break; |
181 |
}
|
|
182 |
}
|
|
183 |
|
|
184 |
enum StructFlags : int |
|
185 |
{
|
|
186 |
none = 0x0, |
|
187 |
hasPointers = 0x1, // NB: should use noPointers as in ClassFlags |
|
188 |
}
|
|
189 |
|
|
190 |
enum StructPOD : int |
|
191 |
{
|
|
192 |
no, // struct is not POD |
|
193 |
yes, // struct is POD |
|
194 |
fwd, // POD not yet computed |
|
195 |
}
|
|
196 |
|
|
197 |
/***********************************************************
|
|
198 |
* All `struct` declarations are an instance of this.
|
|
199 |
*/
|
|
200 |
extern (C++) class StructDeclaration : AggregateDeclaration |
|
201 |
{
|
|
202 |
bool zeroInit; // !=0 if initialize with 0 fill |
|
203 |
bool hasIdentityAssign; // true if has identity opAssign |
|
204 |
bool hasBlitAssign; // true if opAssign is a blit |
|
205 |
bool hasIdentityEquals; // true if has identity opEquals |
|
206 |
bool hasNoFields; // has no fields |
|
207 |
bool hasCopyCtor; // copy constructor |
|
208 |
// Even if struct is defined as non-root symbol, some built-in operations
|
|
209 |
// (e.g. TypeidExp, NewExp, ArrayLiteralExp, etc) request its TypeInfo.
|
|
210 |
// For those, today TypeInfo_Struct is generated in COMDAT.
|
|
211 |
bool requestTypeInfo; |
|
212 |
|
|
213 |
FuncDeclarations postblits; // Array of postblit functions |
|
214 |
FuncDeclaration postblit; // aggregate postblit |
|
215 |
|
|
216 |
FuncDeclaration xeq; // TypeInfo_Struct.xopEquals |
|
217 |
FuncDeclaration xcmp; // TypeInfo_Struct.xopCmp |
|
218 |
FuncDeclaration xhash; // TypeInfo_Struct.xtoHash |
|
219 |
extern (C++) __gshared FuncDeclaration xerreq; // object.xopEquals |
|
220 |
extern (C++) __gshared FuncDeclaration xerrcmp; // object.xopCmp |
|
221 |
|
|
222 |
structalign_t alignment; // alignment applied outside of the struct |
|
223 |
StructPOD ispod; // if struct is POD |
|
224 |
|
|
225 |
// ABI-specific type(s) if the struct can be passed in registers
|
|
226 |
TypeTuple argTypes; |
|
227 |
|
|
228 | 1 |
extern (D) this(const ref Loc loc, Identifier id, bool inObject) |
229 |
{
|
|
230 | 1 |
super(loc, id); |
231 | 1 |
zeroInit = false; // assume false until we do semantic processing |
232 | 1 |
ispod = StructPOD.fwd; |
233 |
// For forward references
|
|
234 | 1 |
type = new TypeStruct(this); |
235 |
|
|
236 | 1 |
if (inObject) |
237 |
{
|
|
238 | 1 |
if (id == Id.ModuleInfo && !Module.moduleinfo) |
239 | 1 |
Module.moduleinfo = this; |
240 |
}
|
|
241 |
}
|
|
242 |
|
|
243 |
static StructDeclaration create(Loc loc, Identifier id, bool inObject) |
|
244 |
{
|
|
245 |
return new StructDeclaration(loc, id, inObject); |
|
246 |
}
|
|
247 |
|
|
248 |
override Dsymbol syntaxCopy(Dsymbol s) |
|
249 |
{
|
|
250 | 1 |
StructDeclaration sd = |
251 | 1 |
s ? cast(StructDeclaration)s |
252 | 1 |
: new StructDeclaration(loc, ident, false); |
253 | 1 |
return ScopeDsymbol.syntaxCopy(sd); |
254 |
}
|
|
255 |
|
|
256 |
final void semanticTypeInfoMembers() |
|
257 |
{
|
|
258 | 1 |
if (xeq && |
259 | 1 |
xeq._scope && |
260 | 1 |
xeq.semanticRun < PASS.semantic3done) |
261 |
{
|
|
262 | 1 |
uint errors = global.startGagging(); |
263 | 1 |
xeq.semantic3(xeq._scope); |
264 | 1 |
if (global.endGagging(errors)) |
265 | 1 |
xeq = xerreq; |
266 |
}
|
|
267 |
|
|
268 | 1 |
if (xcmp && |
269 | 1 |
xcmp._scope && |
270 | 1 |
xcmp.semanticRun < PASS.semantic3done) |
271 |
{
|
|
272 | 1 |
uint errors = global.startGagging(); |
273 | 1 |
xcmp.semantic3(xcmp._scope); |
274 | 1 |
if (global.endGagging(errors)) |
275 | 1 |
xcmp = xerrcmp; |
276 |
}
|
|
277 |
|
|
278 | 1 |
FuncDeclaration ftostr = search_toString(this); |
279 | 1 |
if (ftostr && |
280 | 1 |
ftostr._scope && |
281 | 1 |
ftostr.semanticRun < PASS.semantic3done) |
282 |
{
|
|
283 |
ftostr.semantic3(ftostr._scope); |
|
284 |
}
|
|
285 |
|
|
286 | 1 |
if (xhash && |
287 | 1 |
xhash._scope && |
288 | 1 |
xhash.semanticRun < PASS.semantic3done) |
289 |
{
|
|
290 | 1 |
xhash.semantic3(xhash._scope); |
291 |
}
|
|
292 |
|
|
293 | 1 |
if (postblit && |
294 | 1 |
postblit._scope && |
295 | 1 |
postblit.semanticRun < PASS.semantic3done) |
296 |
{
|
|
297 | 1 |
postblit.semantic3(postblit._scope); |
298 |
}
|
|
299 |
|
|
300 | 1 |
if (dtor && |
301 | 1 |
dtor._scope && |
302 | 1 |
dtor.semanticRun < PASS.semantic3done) |
303 |
{
|
|
304 | 1 |
dtor.semantic3(dtor._scope); |
305 |
}
|
|
306 |
}
|
|
307 |
|
|
308 |
override final Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) |
|
309 |
{
|
|
310 |
//printf("%s.StructDeclaration::search('%s', flags = x%x)\n", toChars(), ident.toChars(), flags);
|
|
311 | 1 |
if (_scope && !symtab) |
312 | 1 |
dsymbolSemantic(this, _scope); |
313 |
|
|
314 | 1 |
if (!members || !symtab) // opaque or semantic() is not yet called |
315 |
{
|
|
316 |
// .stringof is always defined (but may be hidden by some other symbol)
|
|
317 | 1 |
if(ident != Id.stringof) |
318 | 1 |
error("is forward referenced when looking for `%s`", ident.toChars()); |
319 | 1 |
return null; |
320 |
}
|
|
321 |
|
|
322 | 1 |
return ScopeDsymbol.search(loc, ident, flags); |
323 |
}
|
|
324 |
|
|
325 |
override const(char)* kind() const |
|
326 |
{
|
|
327 | 1 |
return "struct"; |
328 |
}
|
|
329 |
|
|
330 |
override final void finalizeSize() |
|
331 |
{
|
|
332 |
//printf("StructDeclaration::finalizeSize() %s, sizeok = %d\n", toChars(), sizeok);
|
|
333 | 1 |
assert(sizeok != Sizeok.done); |
334 |
|
|
335 | 1 |
if (sizeok == Sizeok.inProcess) |
336 |
{
|
|
337 | 1 |
return; |
338 |
}
|
|
339 | 1 |
sizeok = Sizeok.inProcess; |
340 |
|
|
341 |
//printf("+StructDeclaration::finalizeSize() %s, fields.dim = %d, sizeok = %d\n", toChars(), fields.dim, sizeok);
|
|
342 |
|
|
343 | 1 |
fields.setDim(0); // workaround |
344 |
|
|
345 |
// Set the offsets of the fields and determine the size of the struct
|
|
346 | 1 |
uint offset = 0; |
347 | 1 |
bool isunion = isUnionDeclaration() !is null; |
348 | 1 |
for (size_t i = 0; i < members.dim; i++) |
349 |
{
|
|
350 | 1 |
Dsymbol s = (*members)[i]; |
351 | 1 |
s.setFieldOffset(this, &offset, isunion); |
352 |
}
|
|
353 | 1 |
if (type.ty == Terror) |
354 |
{
|
|
355 | 1 |
errors = true; |
356 | 1 |
return; |
357 |
}
|
|
358 |
|
|
359 |
// 0 sized struct's are set to 1 byte
|
|
360 | 1 |
if (structsize == 0) |
361 |
{
|
|
362 | 1 |
hasNoFields = true; |
363 | 1 |
structsize = 1; |
364 | 1 |
alignsize = 1; |
365 |
}
|
|
366 |
|
|
367 |
// Round struct size up to next alignsize boundary.
|
|
368 |
// This will ensure that arrays of structs will get their internals
|
|
369 |
// aligned properly.
|
|
370 | 1 |
if (alignment == STRUCTALIGN_DEFAULT) |
371 | 1 |
structsize = (structsize + alignsize - 1) & ~(alignsize - 1); |
372 |
else
|
|
373 | 1 |
structsize = (structsize + alignment - 1) & ~(alignment - 1); |
374 |
|
|
375 | 1 |
sizeok = Sizeok.done; |
376 |
|
|
377 |
//printf("-StructDeclaration::finalizeSize() %s, fields.dim = %d, structsize = %d\n", toChars(), fields.dim, structsize);
|
|
378 |
|
|
379 | 1 |
if (errors) |
380 |
return; |
|
381 |
|
|
382 |
// Calculate fields[i].overlapped
|
|
383 | 1 |
if (checkOverlappedFields()) |
384 |
{
|
|
385 | 1 |
errors = true; |
386 | 1 |
return; |
387 |
}
|
|
388 |
|
|
389 |
// Determine if struct is all zeros or not
|
|
390 | 1 |
zeroInit = true; |
391 | 1 |
foreach (vd; fields) |
392 |
{
|
|
393 | 1 |
if (vd._init) |
394 |
{
|
|
395 | 1 |
if (vd._init.isVoidInitializer()) |
396 |
/* Treat as 0 for the purposes of putting the initializer
|
|
397 |
* in the BSS segment, or doing a mass set to 0
|
|
398 |
*/
|
|
399 | 1 |
continue; |
400 |
|
|
401 |
// Zero size fields are zero initialized
|
|
402 | 1 |
if (vd.type.size(vd.loc) == 0) |
403 |
continue; |
|
404 |
|
|
405 |
// Examine init to see if it is all 0s.
|
|
406 | 1 |
auto exp = vd.getConstInitializer(); |
407 | 1 |
if (!exp || !_isZeroInit(exp)) |
408 |
{
|
|
409 | 1 |
zeroInit = false; |
410 | 1 |
break; |
411 |
}
|
|
412 |
}
|
|
413 | 1 |
else if (!vd.type.isZeroInit(loc)) |
414 |
{
|
|
415 | 1 |
zeroInit = false; |
416 | 1 |
break; |
417 |
}
|
|
418 |
}
|
|
419 |
|
|
420 | 1 |
argTypes = target.toArgTypes(type); |
421 |
}
|
|
422 |
|
|
423 |
/***************************************
|
|
424 |
* Fit elements[] to the corresponding types of the struct's fields.
|
|
425 |
*
|
|
426 |
* Params:
|
|
427 |
* loc = location to use for error messages
|
|
428 |
* sc = context
|
|
429 |
* elements = explicit arguments used to construct object
|
|
430 |
* stype = the constructed object type.
|
|
431 |
* Returns:
|
|
432 |
* false if any errors occur,
|
|
433 |
* otherwise true and elements[] are rewritten for the output.
|
|
434 |
*/
|
|
435 |
final bool fit(const ref Loc loc, Scope* sc, Expressions* elements, Type stype) |
|
436 |
{
|
|
437 | 1 |
if (!elements) |
438 |
return true; |
|
439 |
|
|
440 | 1 |
const nfields = nonHiddenFields(); |
441 | 1 |
size_t offset = 0; |
442 | 1 |
for (size_t i = 0; i < elements.dim; i++) |
443 |
{
|
|
444 | 1 |
Expression e = (*elements)[i]; |
445 | 1 |
if (!e) |
446 |
continue; |
|
447 |
|
|
448 | 1 |
e = resolveProperties(sc, e); |
449 | 1 |
if (i >= nfields) |
450 |
{
|
|
451 | 1 |
if (i <= fields.dim && e.op == TOK.null_) |
452 |
{
|
|
453 |
// CTFE sometimes creates null as hidden pointer; we'll allow this.
|
|
454 | 1 |
continue; |
455 |
}
|
|
456 | 1 |
.error(loc, "more initializers than fields (%llu) of `%s`", cast(ulong) nfields, toChars()); |
457 | 1 |
return false; |
458 |
}
|
|
459 | 1 |
VarDeclaration v = fields[i]; |
460 | 1 |
if (v.offset < offset) |
461 |
{
|
|
462 | 1 |
.error(loc, "overlapping initialization for `%s`", v.toChars()); |
463 | 1 |
if (!isUnionDeclaration()) |
464 |
{
|
|
465 |
enum errorMsg = "`struct` initializers that contain anonymous unions" ~ |
|
466 |
" must initialize only the first member of a `union`. All subsequent" ~ |
|
467 |
" non-overlapping fields are default initialized"; |
|
468 | 1 |
.errorSupplemental(loc, errorMsg); |
469 |
}
|
|
470 | 1 |
return false; |
471 |
}
|
|
472 | 1 |
offset = cast(uint)(v.offset + v.type.size()); |
473 |
|
|
474 | 1 |
Type t = v.type; |
475 | 1 |
if (stype) |
476 | 1 |
t = t.addMod(stype.mod); |
477 | 1 |
Type origType = t; |
478 | 1 |
Type tb = t.toBasetype(); |
479 |
|
|
480 | 1 |
const hasPointers = tb.hasPointers(); |
481 | 1 |
if (hasPointers) |
482 |
{
|
|
483 | 1 |
if ((stype.alignment() < target.ptrsize || |
484 | 1 |
(v.offset & (target.ptrsize - 1))) && |
485 | 1 |
(sc.func && sc.func.setUnsafe())) |
486 |
{
|
|
487 | 1 |
.error(loc, "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", |
488 |
toChars(), v.toChars()); |
|
489 | 1 |
return false; |
490 |
}
|
|
491 |
}
|
|
492 |
|
|
493 |
/* Look for case of initializing a static array with a too-short
|
|
494 |
* string literal, such as:
|
|
495 |
* char[5] foo = "abc";
|
|
496 |
* Allow this by doing an explicit cast, which will lengthen the string
|
|
497 |
* literal.
|
|
498 |
*/
|
|
499 | 1 |
if (e.op == TOK.string_ && tb.ty == Tsarray) |
500 |
{
|
|
501 | 1 |
StringExp se = cast(StringExp)e; |
502 | 1 |
Type typeb = se.type.toBasetype(); |
503 | 1 |
TY tynto = tb.nextOf().ty; |
504 | 1 |
if (!se.committed && |
505 | 1 |
(typeb.ty == Tarray || typeb.ty == Tsarray) && tynto.isSomeChar && |
506 | 1 |
se.numberOfCodeUnits(tynto) < (cast(TypeSArray)tb).dim.toInteger()) |
507 |
{
|
|
508 |
e = se.castTo(sc, t); |
|
509 |
goto L1; |
|
510 |
}
|
|
511 |
}
|
|
512 |
|
|
513 | 1 |
while (!e.implicitConvTo(t) && tb.ty == Tsarray) |
514 |
{
|
|
515 |
/* Static array initialization, as in:
|
|
516 |
* T[3][5] = e;
|
|
517 |
*/
|
|
518 | 1 |
t = tb.nextOf(); |
519 | 1 |
tb = t.toBasetype(); |
520 |
}
|
|
521 | 1 |
if (!e.implicitConvTo(t)) |
522 | 1 |
t = origType; // restore type for better diagnostic |
523 |
|
|
524 | 1 |
e = e.implicitCastTo(sc, t); |
525 |
L1: |
|
526 | 1 |
if (e.op == TOK.error) |
527 | 1 |
return false; |
528 |
|
|
529 | 1 |
(*elements)[i] = doCopyOrMove(sc, e); |
530 |
}
|
|
531 | 1 |
return true; |
532 |
}
|
|
533 |
|
|
534 |
/***************************************
|
|
535 |
* Determine if struct is POD (Plain Old Data).
|
|
536 |
*
|
|
537 |
* POD is defined as:
|
|
538 |
* $(OL
|
|
539 |
* $(LI not nested)
|
|
540 |
* $(LI no postblits, destructors, or assignment operators)
|
|
541 |
* $(LI no `ref` fields or fields that are themselves non-POD)
|
|
542 |
* )
|
|
543 |
* The idea being these are compatible with C structs.
|
|
544 |
*
|
|
545 |
* Returns:
|
|
546 |
* true if struct is POD
|
|
547 |
*/
|
|
548 |
final bool isPOD() |
|
549 |
{
|
|
550 |
// If we've already determined whether this struct is POD.
|
|
551 | 1 |
if (ispod != StructPOD.fwd) |
552 | 1 |
return (ispod == StructPOD.yes); |
553 |
|
|
554 | 1 |
ispod = StructPOD.yes; |
555 |
|
|
556 | 1 |
if (enclosing || postblit || dtor || hasCopyCtor) |
557 |
{
|
|
558 | 1 |
ispod = StructPOD.no; |
559 | 1 |
return false; |
560 |
}
|
|
561 |
|
|
562 |
// Recursively check all fields are POD.
|
|
563 | 1 |
for (size_t i = 0; i < fields.dim; i++) |
564 |
{
|
|
565 | 1 |
VarDeclaration v = fields[i]; |
566 | 1 |
if (v.storage_class & STC.ref_) |
567 |
{
|
|
568 |
ispod = StructPOD.no; |
|
569 |
return false; |
|
570 |
}
|
|
571 |
|
|
572 | 1 |
Type tv = v.type.baseElemOf(); |
573 | 1 |
if (tv.ty == Tstruct) |
574 |
{
|
|
575 | 1 |
TypeStruct ts = cast(TypeStruct)tv; |
576 | 1 |
StructDeclaration sd = ts.sym; |
577 | 1 |
if (!sd.isPOD()) |
578 |
{
|
|
579 | 1 |
ispod = StructPOD.no; |
580 | 1 |
return false; |
581 |
}
|
|
582 |
}
|
|
583 |
}
|
|
584 |
|
|
585 | 1 |
return (ispod == StructPOD.yes); |
586 |
}
|
|
587 |
|
|
588 |
override final inout(StructDeclaration) isStructDeclaration() inout |
|
589 |
{
|
|
590 | 1 |
return this; |
591 |
}
|
|
592 |
|
|
593 |
override void accept(Visitor v) |
|
594 |
{
|
|
595 | 1 |
v.visit(this); |
596 |
}
|
|
597 |
|
|
598 |
final uint numArgTypes() const |
|
599 |
{
|
|
600 | 1 |
return argTypes && argTypes.arguments ? cast(uint) argTypes.arguments.dim : 0; |
601 |
}
|
|
602 |
|
|
603 |
final Type argType(uint index) |
|
604 |
{
|
|
605 | 1 |
return index < numArgTypes() ? (*argTypes.arguments)[index].type : null; |
606 |
}
|
|
607 |
|
|
608 |
final bool hasNonDisabledCtor() |
|
609 |
{
|
|
610 |
static extern (C++) class HasNonDisabledCtorVisitor : Visitor |
|
611 |
{
|
|
612 |
bool result; |
|
613 |
|
|
614 | 1 |
this() {} |
615 |
|
|
616 |
alias visit = Visitor.visit; |
|
617 |
|
|
618 |
override void visit(CtorDeclaration cd) |
|
619 |
{
|
|
620 | 1 |
if (!(cd.storage_class & STC.disable)) |
621 | 1 |
result = true; |
622 |
}
|
|
623 |
|
|
624 |
override void visit(TemplateDeclaration td) |
|
625 |
{
|
|
626 |
result = true; |
|
627 |
}
|
|
628 |
|
|
629 |
override void visit(OverloadSet os) |
|
630 |
{
|
|
631 |
for (size_t i = 0; i < os.a.dim; i++) |
|
632 |
os.a[i].accept(this); |
|
633 |
}
|
|
634 |
}
|
|
635 |
|
|
636 | 1 |
if (!ctor) |
637 | 1 |
return false; |
638 | 1 |
scope v = new HasNonDisabledCtorVisitor(); |
639 | 1 |
ctor.accept(v); |
640 | 1 |
return v.result; |
641 |
}
|
|
642 |
}
|
|
643 |
|
|
644 |
/**********************************
|
|
645 |
* Determine if exp is all binary zeros.
|
|
646 |
* Params:
|
|
647 |
* exp = expression to check
|
|
648 |
* Returns:
|
|
649 |
* true if it's all binary 0
|
|
650 |
*/
|
|
651 |
private bool _isZeroInit(Expression exp) |
|
652 |
{
|
|
653 | 1 |
switch (exp.op) |
654 |
{
|
|
655 | 1 |
case TOK.int64: |
656 | 1 |
return exp.toInteger() == 0; |
657 |
|
|
658 | 1 |
case TOK.null_: |
659 | 1 |
case TOK.false_: |
660 | 1 |
return true; |
661 |
|
|
662 | 1 |
case TOK.structLiteral: |
663 |
{
|
|
664 | 1 |
auto sle = cast(StructLiteralExp) exp; |
665 | 1 |
foreach (i; 0 .. sle.sd.fields.dim) |
666 |
{
|
|
667 | 1 |
auto field = sle.sd.fields[i]; |
668 | 1 |
if (field.type.size(field.loc)) |
669 |
{
|
|
670 | 1 |
auto e = (*sle.elements)[i]; |
671 | 1 |
if (e ? !_isZeroInit(e) |
672 | 1 |
: !field.type.isZeroInit(field.loc)) |
673 | 1 |
return false; |
674 |
}
|
|
675 |
}
|
|
676 | 1 |
return true; |
677 |
}
|
|
678 |
|
|
679 | 1 |
case TOK.arrayLiteral: |
680 |
{
|
|
681 | 1 |
auto ale = cast(ArrayLiteralExp)exp; |
682 |
|
|
683 | 1 |
const dim = ale.elements ? ale.elements.dim : 0; |
684 |
|
|
685 | 1 |
if (ale.type.toBasetype().ty == Tarray) // if initializing a dynamic array |
686 | 1 |
return dim == 0; |
687 |
|
|
688 | 1 |
foreach (i; 0 .. dim) |
689 |
{
|
|
690 | 1 |
if (!_isZeroInit(ale[i])) |
691 | 1 |
return false; |
692 |
}
|
|
693 |
|
|
694 |
/* Note that true is returned for all T[0]
|
|
695 |
*/
|
|
696 | 1 |
return true; |
697 |
}
|
|
698 |
|
|
699 | 1 |
case TOK.string_: |
700 |
{
|
|
701 | 1 |
StringExp se = cast(StringExp)exp; |
702 |
|
|
703 | 1 |
if (se.type.toBasetype().ty == Tarray) // if initializing a dynamic array |
704 | 1 |
return se.len == 0; |
705 |
|
|
706 | 1 |
foreach (i; 0 .. se.len) |
707 |
{
|
|
708 | 1 |
if (se.getCodeUnit(i)) |
709 | 1 |
return false; |
710 |
}
|
|
711 |
return true; |
|
712 |
}
|
|
713 |
|
|
714 | 1 |
case TOK.vector: |
715 |
{
|
|
716 | 1 |
auto ve = cast(VectorExp) exp; |
717 | 1 |
return _isZeroInit(ve.e1); |
718 |
}
|
|
719 |
|
|
720 | 1 |
case TOK.float64: |
721 | 1 |
case TOK.complex80: |
722 |
{
|
|
723 |
import dmd.root.ctfloat : CTFloat; |
|
724 | 1 |
return (exp.toReal() is CTFloat.zero) && |
725 | 1 |
(exp.toImaginary() is CTFloat.zero); |
726 |
}
|
|
727 |
|
|
728 | 1 |
default: |
729 | 1 |
return false; |
730 |
}
|
|
731 |
}
|
|
732 |
|
|
733 |
/***********************************************************
|
|
734 |
* Unions are a variation on structs.
|
|
735 |
*/
|
|
736 |
extern (C++) final class UnionDeclaration : StructDeclaration |
|
737 |
{
|
|
738 | 1 |
extern (D) this(const ref Loc loc, Identifier id) |
739 |
{
|
|
740 | 1 |
super(loc, id, false); |
741 |
}
|
|
742 |
|
|
743 |
override Dsymbol syntaxCopy(Dsymbol s) |
|
744 |
{
|
|
745 | 1 |
assert(!s); |
746 | 1 |
auto ud = new UnionDeclaration(loc, ident); |
747 | 1 |
return StructDeclaration.syntaxCopy(ud); |
748 |
}
|
|
749 |
|
|
750 |
override const(char)* kind() const |
|
751 |
{
|
|
752 | 1 |
return "union"; |
753 |
}
|
|
754 |
|
|
755 |
override inout(UnionDeclaration) isUnionDeclaration() inout |
|
756 |
{
|
|
757 | 1 |
return this; |
758 |
}
|
|
759 |
|
|
760 |
override void accept(Visitor v) |
|
761 |
{
|
|
762 | 1 |
v.visit(this); |
763 |
}
|
|
764 |
}
|
Read our documentation on viewing source code .