d: Merge upstream dmd 568496d5b, druntime 178c44ff, phobos 574bf883b.
[official-gcc.git] / gcc / d / dmd / dstruct.d
blob0925e7cd38a2d1510a9d05599e9ee26d1a68f7c0
1 /**
2 * Struct and union declarations.
4 * Specification: $(LINK2 https://dlang.org/spec/struct.html, Structs, Unions)
6 * Copyright: Copyright (C) 1999-2021 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
14 module dmd.dstruct;
16 import dmd.aggregate;
17 import dmd.arraytypes;
18 import dmd.astenums;
19 import dmd.attrib;
20 import dmd.declaration;
21 import dmd.dmodule;
22 import dmd.dscope;
23 import dmd.dsymbol;
24 import dmd.dsymbolsem;
25 import dmd.dtemplate;
26 import dmd.errors;
27 import dmd.expression;
28 import dmd.func;
29 import dmd.globals;
30 import dmd.id;
31 import dmd.identifier;
32 import dmd.mtype;
33 import dmd.opover;
34 import dmd.target;
35 import dmd.tokens;
36 import dmd.typesem;
37 import dmd.typinf;
38 import dmd.visitor;
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
48 extern (C++) FuncDeclaration search_toString(StructDeclaration sd)
50 Dsymbol s = search_function(sd, Id.tostring);
51 FuncDeclaration fd = s ? s.isFuncDeclaration() : null;
52 if (fd)
54 __gshared TypeFunction tftostring;
55 if (!tftostring)
57 tftostring = new TypeFunction(ParameterList(), Type.tstring, LINK.d);
58 tftostring = tftostring.merge().toTypeFunction();
60 fd = fd.overloadExactMatch(tftostring);
62 return fd;
65 /***************************************
66 * Request additional semantic analysis for TypeInfo generation.
67 * Params:
68 * sc = context
69 * t = type that TypeInfo is being generated for
71 extern (C++) void semanticTypeInfo(Scope* sc, Type t)
73 if (sc)
75 if (sc.intypeof)
76 return;
77 if (sc.flags & (SCOPE.ctfe | SCOPE.compile))
78 return;
81 if (!t)
82 return;
84 void visitVector(TypeVector t)
86 semanticTypeInfo(sc, t.basetype);
89 void visitAArray(TypeAArray t)
91 semanticTypeInfo(sc, t.index);
92 semanticTypeInfo(sc, t.next);
95 void visitStruct(TypeStruct t)
97 //printf("semanticTypeInfo.visit(TypeStruct = %s)\n", t.toChars());
98 StructDeclaration sd = t.sym;
100 /* Step 1: create TypeInfoDeclaration
102 if (!sc) // inline may request TypeInfo.
104 Scope scx;
105 scx._module = sd.getModule();
106 getTypeInfoType(sd.loc, t, &scx);
107 sd.requestTypeInfo = true;
109 else if (!sc.minst)
111 // don't yet have to generate TypeInfo instance if
112 // the typeid(T) expression exists in speculative scope.
114 else
116 getTypeInfoType(sd.loc, t, sc);
117 sd.requestTypeInfo = true;
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);
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.
129 if (!sd.members)
130 return; // opaque struct
131 if (!sd.xeq && !sd.xcmp && !sd.postblit && !sd.tidtor && !sd.xhash && !search_toString(sd))
132 return; // none of TypeInfo-specific members
134 // If the struct is in a non-root module, run semantic3 to get
135 // correct symbols for the member function.
136 if (sd.semanticRun >= PASS.semantic3)
138 // semantic3 is already done
140 else if (TemplateInstance ti = sd.isInstantiated())
142 if (ti.minst && !ti.minst.isRoot())
143 Module.addDeferredSemantic3(sd);
145 else
147 if (sd.inNonRoot())
149 //printf("deferred sem3 for TypeInfo - sd = %s, inNonRoot = %d\n", sd.toChars(), sd.inNonRoot());
150 Module.addDeferredSemantic3(sd);
155 void visitTuple(TypeTuple t)
157 if (t.arguments)
159 foreach (arg; *t.arguments)
161 semanticTypeInfo(sc, arg.type);
166 /* Note structural similarity of this Type walker to that in isSpeculativeType()
169 Type tb = t.toBasetype();
170 switch (tb.ty)
172 case Tvector: visitVector(tb.isTypeVector()); break;
173 case Taarray: visitAArray(tb.isTypeAArray()); break;
174 case Tstruct: visitStruct(tb.isTypeStruct()); break;
175 case Ttuple: visitTuple (tb.isTypeTuple()); break;
177 case Tclass:
178 case Tenum: break;
180 default: semanticTypeInfo(sc, tb.nextOf()); break;
184 enum StructFlags : int
186 none = 0x0,
187 hasPointers = 0x1, // NB: should use noPointers as in ClassFlags
190 /***********************************************************
191 * All `struct` declarations are an instance of this.
193 extern (C++) class StructDeclaration : AggregateDeclaration
195 bool zeroInit; // !=0 if initialize with 0 fill
196 bool hasIdentityAssign; // true if has identity opAssign
197 bool hasBlitAssign; // true if opAssign is a blit
198 bool hasIdentityEquals; // true if has identity opEquals
199 bool hasNoFields; // has no fields
200 bool hasCopyCtor; // copy constructor
201 // Even if struct is defined as non-root symbol, some built-in operations
202 // (e.g. TypeidExp, NewExp, ArrayLiteralExp, etc) request its TypeInfo.
203 // For those, today TypeInfo_Struct is generated in COMDAT.
204 bool requestTypeInfo;
206 FuncDeclarations postblits; // Array of postblit functions
207 FuncDeclaration postblit; // aggregate postblit
209 FuncDeclaration xeq; // TypeInfo_Struct.xopEquals
210 FuncDeclaration xcmp; // TypeInfo_Struct.xopCmp
211 FuncDeclaration xhash; // TypeInfo_Struct.xtoHash
212 extern (C++) __gshared FuncDeclaration xerreq; // object.xopEquals
213 extern (C++) __gshared FuncDeclaration xerrcmp; // object.xopCmp
215 structalign_t alignment; // alignment applied outside of the struct
216 ThreeState ispod; // if struct is POD
218 // ABI-specific type(s) if the struct can be passed in registers
219 TypeTuple argTypes;
221 extern (D) this(const ref Loc loc, Identifier id, bool inObject)
223 super(loc, id);
224 zeroInit = false; // assume false until we do semantic processing
225 ispod = ThreeState.none;
226 // For forward references
227 type = new TypeStruct(this);
229 if (inObject)
231 if (id == Id.ModuleInfo && !Module.moduleinfo)
232 Module.moduleinfo = this;
236 static StructDeclaration create(const ref Loc loc, Identifier id, bool inObject)
238 return new StructDeclaration(loc, id, inObject);
241 override StructDeclaration syntaxCopy(Dsymbol s)
243 StructDeclaration sd =
244 s ? cast(StructDeclaration)s
245 : new StructDeclaration(loc, ident, false);
246 ScopeDsymbol.syntaxCopy(sd);
247 return sd;
250 override final Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
252 //printf("%s.StructDeclaration::search('%s', flags = x%x)\n", toChars(), ident.toChars(), flags);
253 if (_scope && !symtab)
254 dsymbolSemantic(this, _scope);
256 if (!members || !symtab) // opaque or semantic() is not yet called
258 // .stringof is always defined (but may be hidden by some other symbol)
259 if(ident != Id.stringof && !(flags & IgnoreErrors) && semanticRun < PASS.semanticdone)
260 error("is forward referenced when looking for `%s`", ident.toChars());
261 return null;
264 return ScopeDsymbol.search(loc, ident, flags);
267 override const(char)* kind() const
269 return "struct";
272 override final void finalizeSize()
274 //printf("StructDeclaration::finalizeSize() %s, sizeok = %d\n", toChars(), sizeok);
275 assert(sizeok != Sizeok.done);
277 if (sizeok == Sizeok.inProcess)
279 return;
281 sizeok = Sizeok.inProcess;
283 //printf("+StructDeclaration::finalizeSize() %s, fields.dim = %d, sizeok = %d\n", toChars(), fields.dim, sizeok);
285 fields.setDim(0); // workaround
287 // Set the offsets of the fields and determine the size of the struct
288 FieldState fieldState;
289 bool isunion = isUnionDeclaration() !is null;
290 for (size_t i = 0; i < members.dim; i++)
292 Dsymbol s = (*members)[i];
293 s.setFieldOffset(this, fieldState, isunion);
295 if (type.ty == Terror)
297 errors = true;
298 return;
301 if (structsize == 0)
303 hasNoFields = true;
304 alignsize = 1;
306 // A fine mess of what size a zero sized struct should be
307 final switch (classKind)
309 case ClassKind.d:
310 case ClassKind.cpp:
311 structsize = 1;
312 break;
314 case ClassKind.c:
315 case ClassKind.objc:
316 if (target.c.bitFieldStyle == TargetC.BitFieldStyle.MS)
318 /* Undocumented MS behavior for:
319 * struct S { int :0; };
321 structsize = 4;
323 else if (target.c.bitFieldStyle == TargetC.BitFieldStyle.DM)
325 structsize = 0;
326 alignsize = 0;
328 else
329 structsize = 0;
330 break;
334 // Round struct size up to next alignsize boundary.
335 // This will ensure that arrays of structs will get their internals
336 // aligned properly.
337 if (alignment.isDefault() || alignment.isPack())
338 structsize = (structsize + alignsize - 1) & ~(alignsize - 1);
339 else
340 structsize = (structsize + alignment.get() - 1) & ~(alignment.get() - 1);
342 sizeok = Sizeok.done;
344 //printf("-StructDeclaration::finalizeSize() %s, fields.dim = %d, structsize = %d\n", toChars(), fields.dim, structsize);
346 if (errors)
347 return;
349 // Calculate fields[i].overlapped
350 if (checkOverlappedFields())
352 errors = true;
353 return;
356 // Determine if struct is all zeros or not
357 zeroInit = true;
358 foreach (vd; fields)
360 if (vd._init)
362 if (vd._init.isVoidInitializer())
363 /* Treat as 0 for the purposes of putting the initializer
364 * in the BSS segment, or doing a mass set to 0
366 continue;
368 // Zero size fields are zero initialized
369 if (vd.type.size(vd.loc) == 0)
370 continue;
372 // Examine init to see if it is all 0s.
373 auto exp = vd.getConstInitializer();
374 if (!exp || !_isZeroInit(exp))
376 zeroInit = false;
377 break;
380 else if (!vd.type.isZeroInit(loc))
382 zeroInit = false;
383 break;
387 argTypes = target.toArgTypes(type);
390 /***************************************
391 * Determine if struct is POD (Plain Old Data).
393 * POD is defined as:
394 * $(OL
395 * $(LI not nested)
396 * $(LI no postblits, destructors, or assignment operators)
397 * $(LI no `ref` fields or fields that are themselves non-POD)
399 * The idea being these are compatible with C structs.
401 * Returns:
402 * true if struct is POD
404 final bool isPOD()
406 // If we've already determined whether this struct is POD.
407 if (ispod != ThreeState.none)
408 return (ispod == ThreeState.yes);
410 ispod = ThreeState.yes;
412 if (enclosing || postblit || dtor || hasCopyCtor)
414 ispod = ThreeState.no;
415 return false;
418 // Recursively check all fields are POD.
419 for (size_t i = 0; i < fields.dim; i++)
421 VarDeclaration v = fields[i];
422 if (v.storage_class & STC.ref_)
424 ispod = ThreeState.no;
425 return false;
428 Type tv = v.type.baseElemOf();
429 if (tv.ty == Tstruct)
431 TypeStruct ts = cast(TypeStruct)tv;
432 StructDeclaration sd = ts.sym;
433 if (!sd.isPOD())
435 ispod = ThreeState.no;
436 return false;
441 return (ispod == ThreeState.yes);
444 override final inout(StructDeclaration) isStructDeclaration() inout @nogc nothrow pure @safe
446 return this;
449 override void accept(Visitor v)
451 v.visit(this);
454 final uint numArgTypes() const
456 return argTypes && argTypes.arguments ? cast(uint) argTypes.arguments.dim : 0;
459 final Type argType(uint index)
461 return index < numArgTypes() ? (*argTypes.arguments)[index].type : null;
465 /***************************************
466 * Verifies whether the struct declaration has a
467 * constructor that is not a copy constructor.
468 * Optionally, it can check whether the struct
469 * declaration has a regular constructor, that
470 * is not disabled.
472 * Params:
473 * checkDisabled = if the struct has a regular
474 non-disabled constructor
475 * Returns:
476 * true, if the struct has a regular (optionally,
477 * not disabled) constructor, false otherwise.
479 final bool hasRegularCtor(bool checkDisabled = false)
481 if (!ctor)
482 return false;
484 bool result;
485 overloadApply(ctor, (Dsymbol s)
487 if (auto td = s.isTemplateDeclaration())
489 if (checkDisabled && td.onemember)
491 if (auto ctorDecl = td.onemember.isCtorDeclaration())
493 if (ctorDecl.storage_class & STC.disable)
494 return 0;
497 result = true;
498 return 1;
500 if (auto ctorDecl = s.isCtorDeclaration())
502 if (!ctorDecl.isCpCtor && (!checkDisabled || !(ctorDecl.storage_class & STC.disable)))
504 result = true;
505 return 1;
508 return 0;
510 return result;
514 /**********************************
515 * Determine if exp is all binary zeros.
516 * Params:
517 * exp = expression to check
518 * Returns:
519 * true if it's all binary 0
521 private bool _isZeroInit(Expression exp)
523 switch (exp.op)
525 case TOK.int64:
526 return exp.toInteger() == 0;
528 case TOK.null_:
529 case TOK.false_:
530 return true;
532 case TOK.structLiteral:
534 auto sle = cast(StructLiteralExp) exp;
535 foreach (i; 0 .. sle.sd.fields.dim)
537 auto field = sle.sd.fields[i];
538 if (field.type.size(field.loc))
540 auto e = (*sle.elements)[i];
541 if (e ? !_isZeroInit(e)
542 : !field.type.isZeroInit(field.loc))
543 return false;
546 return true;
549 case TOK.arrayLiteral:
551 auto ale = cast(ArrayLiteralExp)exp;
553 const dim = ale.elements ? ale.elements.dim : 0;
555 if (ale.type.toBasetype().ty == Tarray) // if initializing a dynamic array
556 return dim == 0;
558 foreach (i; 0 .. dim)
560 if (!_isZeroInit(ale[i]))
561 return false;
564 /* Note that true is returned for all T[0]
566 return true;
569 case TOK.string_:
571 StringExp se = cast(StringExp)exp;
573 if (se.type.toBasetype().ty == Tarray) // if initializing a dynamic array
574 return se.len == 0;
576 foreach (i; 0 .. se.len)
578 if (se.getCodeUnit(i))
579 return false;
581 return true;
584 case TOK.vector:
586 auto ve = cast(VectorExp) exp;
587 return _isZeroInit(ve.e1);
590 case TOK.float64:
591 case TOK.complex80:
593 import dmd.root.ctfloat : CTFloat;
594 return (exp.toReal() is CTFloat.zero) &&
595 (exp.toImaginary() is CTFloat.zero);
598 default:
599 return false;
603 /***********************************************************
604 * Unions are a variation on structs.
606 extern (C++) final class UnionDeclaration : StructDeclaration
608 extern (D) this(const ref Loc loc, Identifier id)
610 super(loc, id, false);
613 override UnionDeclaration syntaxCopy(Dsymbol s)
615 assert(!s);
616 auto ud = new UnionDeclaration(loc, ident);
617 StructDeclaration.syntaxCopy(ud);
618 return ud;
621 override const(char)* kind() const
623 return "union";
626 override inout(UnionDeclaration) isUnionDeclaration() inout
628 return this;
631 override void accept(Visitor v)
633 v.visit(this);