1 1.1 mrg /** 2 1.1 mrg * Defines a `class` declaration. 3 1.1 mrg * 4 1.1 mrg * Specification: $(LINK2 https://dlang.org/spec/class.html, Classes) 5 1.1 mrg * 6 1.1 mrg * Copyright: Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved 7 1.1 mrg * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 8 1.1 mrg * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 9 1.1 mrg * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dclass.d, _dclass.d) 10 1.1 mrg * Documentation: https://dlang.org/phobos/dmd_dclass.html 11 1.1 mrg * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dclass.d 12 1.1 mrg */ 13 1.1 mrg 14 1.1 mrg module dmd.dclass; 15 1.1 mrg 16 1.1 mrg import core.stdc.stdio; 17 1.1 mrg import core.stdc.string; 18 1.1 mrg 19 1.1 mrg import dmd.aggregate; 20 1.1 mrg import dmd.apply; 21 1.1 mrg import dmd.arraytypes; 22 1.1 mrg import dmd.astenums; 23 1.1 mrg import dmd.attrib; 24 1.1 mrg import dmd.gluelayer; 25 1.1 mrg import dmd.declaration; 26 1.1 mrg import dmd.dscope; 27 1.1 mrg import dmd.dsymbol; 28 1.1 mrg import dmd.dsymbolsem; 29 1.1 mrg import dmd.func; 30 1.1 mrg import dmd.globals; 31 1.1 mrg import dmd.id; 32 1.1 mrg import dmd.identifier; 33 1.1 mrg import dmd.mtype; 34 1.1 mrg import dmd.objc; 35 1.1 mrg import dmd.root.rmem; 36 1.1 mrg import dmd.target; 37 1.1 mrg import dmd.visitor; 38 1.1 mrg 39 1.1 mrg /*********************************************************** 40 1.1 mrg */ 41 1.1 mrg extern (C++) struct BaseClass 42 1.1 mrg { 43 1.1 mrg Type type; // (before semantic processing) 44 1.1 mrg 45 1.1 mrg ClassDeclaration sym; 46 1.1 mrg uint offset; // 'this' pointer offset 47 1.1 mrg 48 1.1 mrg // for interfaces: Array of FuncDeclaration's making up the vtbl[] 49 1.1 mrg FuncDeclarations vtbl; 50 1.1 mrg 51 1.1 mrg // if BaseClass is an interface, these 52 1.1 mrg // are a copy of the InterfaceDeclaration.interfaces 53 1.1 mrg BaseClass[] baseInterfaces; 54 1.1 mrg 55 1.1 mrg extern (D) this(Type type) 56 1.1 mrg { 57 1.1 mrg //printf("BaseClass(this = %p, '%s')\n", this, type.toChars()); 58 1.1 mrg this.type = type; 59 1.1 mrg } 60 1.1 mrg 61 1.1 mrg /**************************************** 62 1.1 mrg * Fill in vtbl[] for base class based on member functions of class cd. 63 1.1 mrg * Input: 64 1.1 mrg * vtbl if !=NULL, fill it in 65 1.1 mrg * newinstance !=0 means all entries must be filled in by members 66 1.1 mrg * of cd, not members of any base classes of cd. 67 1.1 mrg * Returns: 68 1.1 mrg * true if any entries were filled in by members of cd (not exclusively 69 1.1 mrg * by base classes) 70 1.1 mrg */ 71 1.1 mrg extern (C++) bool fillVtbl(ClassDeclaration cd, FuncDeclarations* vtbl, int newinstance) 72 1.1 mrg { 73 1.1 mrg bool result = false; 74 1.1 mrg 75 1.1 mrg //printf("BaseClass.fillVtbl(this='%s', cd='%s')\n", sym.toChars(), cd.toChars()); 76 1.1 mrg if (vtbl) 77 1.1 mrg vtbl.setDim(sym.vtbl.dim); 78 1.1 mrg 79 1.1 mrg // first entry is ClassInfo reference 80 1.1 mrg for (size_t j = sym.vtblOffset(); j < sym.vtbl.dim; j++) 81 1.1 mrg { 82 1.1 mrg FuncDeclaration ifd = sym.vtbl[j].isFuncDeclaration(); 83 1.1 mrg 84 1.1 mrg //printf(" vtbl[%d] is '%s'\n", j, ifd ? ifd.toChars() : "null"); 85 1.1 mrg assert(ifd); 86 1.1 mrg 87 1.1 mrg // Find corresponding function in this class 88 1.1 mrg auto tf = ifd.type.toTypeFunction(); 89 1.1 mrg auto fd = cd.findFunc(ifd.ident, tf); 90 1.1 mrg if (fd && !fd.isAbstract()) 91 1.1 mrg { 92 1.1 mrg if (fd.toParent() == cd) 93 1.1 mrg result = true; 94 1.1 mrg } 95 1.1 mrg else 96 1.1 mrg fd = null; 97 1.1 mrg if (vtbl) 98 1.1 mrg (*vtbl)[j] = fd; 99 1.1 mrg } 100 1.1 mrg return result; 101 1.1 mrg } 102 1.1 mrg 103 1.1 mrg extern (D) void copyBaseInterfaces(BaseClasses* vtblInterfaces) 104 1.1 mrg { 105 1.1 mrg //printf("+copyBaseInterfaces(), %s\n", sym.toChars()); 106 1.1 mrg // if (baseInterfaces.length) 107 1.1 mrg // return; 108 1.1 mrg auto bc = cast(BaseClass*)mem.xcalloc(sym.interfaces.length, BaseClass.sizeof); 109 1.1 mrg baseInterfaces = bc[0 .. sym.interfaces.length]; 110 1.1 mrg //printf("%s.copyBaseInterfaces()\n", sym.toChars()); 111 1.1 mrg for (size_t i = 0; i < baseInterfaces.length; i++) 112 1.1 mrg { 113 1.1 mrg BaseClass* b = &baseInterfaces[i]; 114 1.1 mrg BaseClass* b2 = sym.interfaces[i]; 115 1.1 mrg 116 1.1 mrg assert(b2.vtbl.dim == 0); // should not be filled yet 117 1.1 mrg memcpy(b, b2, BaseClass.sizeof); 118 1.1 mrg 119 1.1 mrg if (i) // single inheritance is i==0 120 1.1 mrg vtblInterfaces.push(b); // only need for M.I. 121 1.1 mrg b.copyBaseInterfaces(vtblInterfaces); 122 1.1 mrg } 123 1.1 mrg //printf("-copyBaseInterfaces\n"); 124 1.1 mrg } 125 1.1 mrg } 126 1.1 mrg 127 1.1 mrg enum ClassFlags : uint 128 1.1 mrg { 129 1.1 mrg none = 0x0, 130 1.1 mrg isCOMclass = 0x1, 131 1.1 mrg noPointers = 0x2, 132 1.1 mrg hasOffTi = 0x4, 133 1.1 mrg hasCtor = 0x8, 134 1.1 mrg hasGetMembers = 0x10, 135 1.1 mrg hasTypeInfo = 0x20, 136 1.1 mrg isAbstract = 0x40, 137 1.1 mrg isCPPclass = 0x80, 138 1.1 mrg hasDtor = 0x100, 139 1.1 mrg } 140 1.1 mrg 141 1.1 mrg /*********************************************************** 142 1.1 mrg */ 143 1.1 mrg extern (C++) class ClassDeclaration : AggregateDeclaration 144 1.1 mrg { 145 1.1 mrg extern (C++) __gshared 146 1.1 mrg { 147 1.1 mrg // Names found by reading object.d in druntime 148 1.1 mrg ClassDeclaration object; 149 1.1 mrg ClassDeclaration throwable; 150 1.1 mrg ClassDeclaration exception; 151 1.1 mrg ClassDeclaration errorException; 152 1.1 mrg ClassDeclaration cpp_type_info_ptr; // Object.__cpp_type_info_ptr 153 1.1 mrg } 154 1.1 mrg 155 1.1 mrg ClassDeclaration baseClass; // NULL only if this is Object 156 1.1 mrg FuncDeclaration staticCtor; 157 1.1 mrg FuncDeclaration staticDtor; 158 1.1 mrg Dsymbols vtbl; // Array of FuncDeclaration's making up the vtbl[] 159 1.1 mrg Dsymbols vtblFinal; // More FuncDeclaration's that aren't in vtbl[] 160 1.1 mrg 161 1.1 mrg // Array of BaseClass's; first is super, rest are Interface's 162 1.1 mrg BaseClasses* baseclasses; 163 1.1 mrg 164 1.1 mrg /* Slice of baseclasses[] that does not include baseClass 165 1.1 mrg */ 166 1.1 mrg BaseClass*[] interfaces; 167 1.1 mrg 168 1.1 mrg // array of base interfaces that have their own vtbl[] 169 1.1 mrg BaseClasses* vtblInterfaces; 170 1.1 mrg 171 1.1 mrg // the ClassInfo object for this ClassDeclaration 172 1.1 mrg TypeInfoClassDeclaration vclassinfo; 173 1.1 mrg 174 1.1 mrg // true if this is a COM class 175 1.1 mrg bool com; 176 1.1 mrg 177 1.1 mrg /// true if this is a scope class 178 1.1 mrg bool stack; 179 1.1 mrg 180 1.1 mrg /// if this is a C++ class, this is the slot reserved for the virtual destructor 181 1.1 mrg int cppDtorVtblIndex = -1; 182 1.1 mrg 183 1.1 mrg /// to prevent recursive attempts 184 1.1 mrg private bool inuse; 185 1.1 mrg 186 1.1 mrg ThreeState isabstract; 187 1.1 mrg 188 1.1 mrg /// set the progress of base classes resolving 189 1.1 mrg Baseok baseok; 190 1.1 mrg 191 1.1 mrg /** 192 1.1 mrg * Data for a class declaration that is needed for the Objective-C 193 1.1 mrg * integration. 194 1.1 mrg */ 195 1.1 mrg ObjcClassDeclaration objc; 196 1.1 mrg 197 1.1 mrg Symbol* cpp_type_info_ptr_sym; // cached instance of class Id.cpp_type_info_ptr 198 1.1 mrg 199 1.1 mrg final extern (D) this(const ref Loc loc, Identifier id, BaseClasses* baseclasses, Dsymbols* members, bool inObject) 200 1.1 mrg { 201 1.1 mrg objc = ObjcClassDeclaration(this); 202 1.1 mrg 203 1.1 mrg if (!id) 204 1.1 mrg id = Identifier.generateAnonymousId("class"); 205 1.1 mrg 206 1.1 mrg super(loc, id); 207 1.1 mrg 208 1.1 mrg static immutable msg = "only object.d can define this reserved class name"; 209 1.1 mrg 210 1.1 mrg if (baseclasses) 211 1.1 mrg { 212 1.1 mrg // Actually, this is a transfer 213 1.1 mrg this.baseclasses = baseclasses; 214 1.1 mrg } 215 1.1 mrg else 216 1.1 mrg this.baseclasses = new BaseClasses(); 217 1.1 mrg 218 1.1 mrg this.members = members; 219 1.1 mrg 220 1.1 mrg //printf("ClassDeclaration(%s), dim = %d\n", ident.toChars(), this.baseclasses.dim); 221 1.1 mrg 222 1.1 mrg // For forward references 223 1.1 mrg type = new TypeClass(this); 224 1.1 mrg 225 1.1 mrg // Look for special class names 226 1.1 mrg if (id == Id.__sizeof || id == Id.__xalignof || id == Id._mangleof) 227 1.1 mrg error("illegal class name"); 228 1.1 mrg 229 1.1 mrg // BUG: What if this is the wrong TypeInfo, i.e. it is nested? 230 1.1 mrg if (id.toChars()[0] == 'T') 231 1.1 mrg { 232 1.1 mrg if (id == Id.TypeInfo) 233 1.1 mrg { 234 1.1 mrg if (!inObject) 235 1.1 mrg error("%s", msg.ptr); 236 1.1 mrg Type.dtypeinfo = this; 237 1.1 mrg } 238 1.1 mrg if (id == Id.TypeInfo_Class) 239 1.1 mrg { 240 1.1 mrg if (!inObject) 241 1.1 mrg error("%s", msg.ptr); 242 1.1 mrg Type.typeinfoclass = this; 243 1.1 mrg } 244 1.1 mrg if (id == Id.TypeInfo_Interface) 245 1.1 mrg { 246 1.1 mrg if (!inObject) 247 1.1 mrg error("%s", msg.ptr); 248 1.1 mrg Type.typeinfointerface = this; 249 1.1 mrg } 250 1.1 mrg if (id == Id.TypeInfo_Struct) 251 1.1 mrg { 252 1.1 mrg if (!inObject) 253 1.1 mrg error("%s", msg.ptr); 254 1.1 mrg Type.typeinfostruct = this; 255 1.1 mrg } 256 1.1 mrg if (id == Id.TypeInfo_Pointer) 257 1.1 mrg { 258 1.1 mrg if (!inObject) 259 1.1 mrg error("%s", msg.ptr); 260 1.1 mrg Type.typeinfopointer = this; 261 1.1 mrg } 262 1.1 mrg if (id == Id.TypeInfo_Array) 263 1.1 mrg { 264 1.1 mrg if (!inObject) 265 1.1 mrg error("%s", msg.ptr); 266 1.1 mrg Type.typeinfoarray = this; 267 1.1 mrg } 268 1.1 mrg if (id == Id.TypeInfo_StaticArray) 269 1.1 mrg { 270 1.1 mrg //if (!inObject) 271 1.1 mrg // Type.typeinfostaticarray.error("%s", msg); 272 1.1 mrg Type.typeinfostaticarray = this; 273 1.1 mrg } 274 1.1 mrg if (id == Id.TypeInfo_AssociativeArray) 275 1.1 mrg { 276 1.1 mrg if (!inObject) 277 1.1 mrg error("%s", msg.ptr); 278 1.1 mrg Type.typeinfoassociativearray = this; 279 1.1 mrg } 280 1.1 mrg if (id == Id.TypeInfo_Enum) 281 1.1 mrg { 282 1.1 mrg if (!inObject) 283 1.1 mrg error("%s", msg.ptr); 284 1.1 mrg Type.typeinfoenum = this; 285 1.1 mrg } 286 1.1 mrg if (id == Id.TypeInfo_Function) 287 1.1 mrg { 288 1.1 mrg if (!inObject) 289 1.1 mrg error("%s", msg.ptr); 290 1.1 mrg Type.typeinfofunction = this; 291 1.1 mrg } 292 1.1 mrg if (id == Id.TypeInfo_Delegate) 293 1.1 mrg { 294 1.1 mrg if (!inObject) 295 1.1 mrg error("%s", msg.ptr); 296 1.1 mrg Type.typeinfodelegate = this; 297 1.1 mrg } 298 1.1 mrg if (id == Id.TypeInfo_Tuple) 299 1.1 mrg { 300 1.1 mrg if (!inObject) 301 1.1 mrg error("%s", msg.ptr); 302 1.1 mrg Type.typeinfotypelist = this; 303 1.1 mrg } 304 1.1 mrg if (id == Id.TypeInfo_Const) 305 1.1 mrg { 306 1.1 mrg if (!inObject) 307 1.1 mrg error("%s", msg.ptr); 308 1.1 mrg Type.typeinfoconst = this; 309 1.1 mrg } 310 1.1 mrg if (id == Id.TypeInfo_Invariant) 311 1.1 mrg { 312 1.1 mrg if (!inObject) 313 1.1 mrg error("%s", msg.ptr); 314 1.1 mrg Type.typeinfoinvariant = this; 315 1.1 mrg } 316 1.1 mrg if (id == Id.TypeInfo_Shared) 317 1.1 mrg { 318 1.1 mrg if (!inObject) 319 1.1 mrg error("%s", msg.ptr); 320 1.1 mrg Type.typeinfoshared = this; 321 1.1 mrg } 322 1.1 mrg if (id == Id.TypeInfo_Wild) 323 1.1 mrg { 324 1.1 mrg if (!inObject) 325 1.1 mrg error("%s", msg.ptr); 326 1.1 mrg Type.typeinfowild = this; 327 1.1 mrg } 328 1.1 mrg if (id == Id.TypeInfo_Vector) 329 1.1 mrg { 330 1.1 mrg if (!inObject) 331 1.1 mrg error("%s", msg.ptr); 332 1.1 mrg Type.typeinfovector = this; 333 1.1 mrg } 334 1.1 mrg } 335 1.1 mrg 336 1.1 mrg if (id == Id.Object) 337 1.1 mrg { 338 1.1 mrg if (!inObject) 339 1.1 mrg error("%s", msg.ptr); 340 1.1 mrg object = this; 341 1.1 mrg } 342 1.1 mrg 343 1.1 mrg if (id == Id.Throwable) 344 1.1 mrg { 345 1.1 mrg if (!inObject) 346 1.1 mrg error("%s", msg.ptr); 347 1.1 mrg throwable = this; 348 1.1 mrg } 349 1.1 mrg if (id == Id.Exception) 350 1.1 mrg { 351 1.1 mrg if (!inObject) 352 1.1 mrg error("%s", msg.ptr); 353 1.1 mrg exception = this; 354 1.1 mrg } 355 1.1 mrg if (id == Id.Error) 356 1.1 mrg { 357 1.1 mrg if (!inObject) 358 1.1 mrg error("%s", msg.ptr); 359 1.1 mrg errorException = this; 360 1.1 mrg } 361 1.1 mrg if (id == Id.cpp_type_info_ptr) 362 1.1 mrg { 363 1.1 mrg if (!inObject) 364 1.1 mrg error("%s", msg.ptr); 365 1.1 mrg cpp_type_info_ptr = this; 366 1.1 mrg } 367 1.1 mrg 368 1.1 mrg baseok = Baseok.none; 369 1.1 mrg } 370 1.1 mrg 371 1.1 mrg static ClassDeclaration create(const ref Loc loc, Identifier id, BaseClasses* baseclasses, Dsymbols* members, bool inObject) 372 1.1 mrg { 373 1.1 mrg return new ClassDeclaration(loc, id, baseclasses, members, inObject); 374 1.1 mrg } 375 1.1 mrg 376 1.1 mrg override const(char)* toPrettyChars(bool qualifyTypes = false) 377 1.1 mrg { 378 1.1 mrg if (objc.isMeta) 379 1.1 mrg return .objc.toPrettyChars(this, qualifyTypes); 380 1.1 mrg 381 1.1 mrg return super.toPrettyChars(qualifyTypes); 382 1.1 mrg } 383 1.1 mrg 384 1.1 mrg override ClassDeclaration syntaxCopy(Dsymbol s) 385 1.1 mrg { 386 1.1 mrg //printf("ClassDeclaration.syntaxCopy('%s')\n", toChars()); 387 1.1 mrg ClassDeclaration cd = 388 1.1 mrg s ? cast(ClassDeclaration)s 389 1.1 mrg : new ClassDeclaration(loc, ident, null, null, false); 390 1.1 mrg 391 1.1 mrg cd.storage_class |= storage_class; 392 1.1 mrg 393 1.1 mrg cd.baseclasses.setDim(this.baseclasses.dim); 394 1.1 mrg for (size_t i = 0; i < cd.baseclasses.dim; i++) 395 1.1 mrg { 396 1.1 mrg BaseClass* b = (*this.baseclasses)[i]; 397 1.1 mrg auto b2 = new BaseClass(b.type.syntaxCopy()); 398 1.1 mrg (*cd.baseclasses)[i] = b2; 399 1.1 mrg } 400 1.1 mrg 401 1.1 mrg ScopeDsymbol.syntaxCopy(cd); 402 1.1 mrg return cd; 403 1.1 mrg } 404 1.1 mrg 405 1.1 mrg override Scope* newScope(Scope* sc) 406 1.1 mrg { 407 1.1 mrg auto sc2 = super.newScope(sc); 408 1.1 mrg if (isCOMclass()) 409 1.1 mrg { 410 1.1 mrg /* This enables us to use COM objects under Linux and 411 1.1 mrg * work with things like XPCOM 412 1.1 mrg */ 413 1.1 mrg sc2.linkage = target.systemLinkage(); 414 1.1 mrg } 415 1.1 mrg return sc2; 416 1.1 mrg } 417 1.1 mrg 418 1.1 mrg /********************************************* 419 1.1 mrg * Determine if 'this' is a base class of cd. 420 1.1 mrg * This is used to detect circular inheritance only. 421 1.1 mrg */ 422 1.1 mrg final bool isBaseOf2(ClassDeclaration cd) pure nothrow @nogc 423 1.1 mrg { 424 1.1 mrg if (!cd) 425 1.1 mrg return false; 426 1.1 mrg //printf("ClassDeclaration.isBaseOf2(this = '%s', cd = '%s')\n", toChars(), cd.toChars()); 427 1.1 mrg for (size_t i = 0; i < cd.baseclasses.dim; i++) 428 1.1 mrg { 429 1.1 mrg BaseClass* b = (*cd.baseclasses)[i]; 430 1.1 mrg if (b.sym == this || isBaseOf2(b.sym)) 431 1.1 mrg return true; 432 1.1 mrg } 433 1.1 mrg return false; 434 1.1 mrg } 435 1.1 mrg 436 1.1 mrg enum OFFSET_RUNTIME = 0x76543210; 437 1.1 mrg enum OFFSET_FWDREF = 0x76543211; 438 1.1 mrg 439 1.1 mrg /******************************************* 440 1.1 mrg * Determine if 'this' is a base class of cd. 441 1.1 mrg */ 442 1.1 mrg bool isBaseOf(ClassDeclaration cd, int* poffset) pure nothrow @nogc 443 1.1 mrg { 444 1.1 mrg //printf("ClassDeclaration.isBaseOf(this = '%s', cd = '%s')\n", toChars(), cd.toChars()); 445 1.1 mrg if (poffset) 446 1.1 mrg *poffset = 0; 447 1.1 mrg while (cd) 448 1.1 mrg { 449 1.1 mrg assert(cd.baseClass || cd.semanticRun >= PASS.semanticdone || cd.isInterfaceDeclaration()); 450 1.1 mrg if (this == cd.baseClass) 451 1.1 mrg return true; 452 1.1 mrg 453 1.1 mrg cd = cd.baseClass; 454 1.1 mrg } 455 1.1 mrg return false; 456 1.1 mrg } 457 1.1 mrg 458 1.1 mrg /********************************************* 459 1.1 mrg * Determine if 'this' has complete base class information. 460 1.1 mrg * This is used to detect forward references in covariant overloads. 461 1.1 mrg */ 462 1.1 mrg final bool isBaseInfoComplete() const 463 1.1 mrg { 464 1.1 mrg return baseok >= Baseok.done; 465 1.1 mrg } 466 1.1 mrg 467 1.1 mrg override final Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) 468 1.1 mrg { 469 1.1 mrg //printf("%s.ClassDeclaration.search('%s', flags=x%x)\n", toChars(), ident.toChars(), flags); 470 1.1 mrg //if (_scope) printf("%s baseok = %d\n", toChars(), baseok); 471 1.1 mrg if (_scope && baseok < Baseok.done) 472 1.1 mrg { 473 1.1 mrg if (!inuse) 474 1.1 mrg { 475 1.1 mrg // must semantic on base class/interfaces 476 1.1 mrg inuse = true; 477 1.1 mrg dsymbolSemantic(this, null); 478 1.1 mrg inuse = false; 479 1.1 mrg } 480 1.1 mrg } 481 1.1 mrg 482 1.1 mrg if (!members || !symtab) // opaque or addMember is not yet done 483 1.1 mrg { 484 1.1 mrg // .stringof is always defined (but may be hidden by some other symbol) 485 1.1 mrg if (ident != Id.stringof && !(flags & IgnoreErrors) && semanticRun < PASS.semanticdone) 486 1.1 mrg error("is forward referenced when looking for `%s`", ident.toChars()); 487 1.1 mrg //*(char*)0=0; 488 1.1 mrg return null; 489 1.1 mrg } 490 1.1 mrg 491 1.1 mrg auto s = ScopeDsymbol.search(loc, ident, flags); 492 1.1 mrg 493 1.1 mrg // don't search imports of base classes 494 1.1 mrg if (flags & SearchImportsOnly) 495 1.1 mrg return s; 496 1.1 mrg 497 1.1 mrg if (s) 498 1.1 mrg return s; 499 1.1 mrg 500 1.1 mrg // Search bases classes in depth-first, left to right order 501 1.1 mrg foreach (b; (*baseclasses)[]) 502 1.1 mrg { 503 1.1 mrg if (!b.sym) 504 1.1 mrg continue; 505 1.1 mrg 506 1.1 mrg if (!b.sym.symtab) 507 1.1 mrg { 508 1.1 mrg error("base `%s` is forward referenced", b.sym.ident.toChars()); 509 1.1 mrg continue; 510 1.1 mrg } 511 1.1 mrg 512 1.1 mrg import dmd.access : symbolIsVisible; 513 1.1 mrg 514 1.1 mrg s = b.sym.search(loc, ident, flags); 515 1.1 mrg if (!s) 516 1.1 mrg continue; 517 1.1 mrg else if (s == this) // happens if s is nested in this and derives from this 518 1.1 mrg s = null; 519 1.1 mrg else if (!(flags & IgnoreSymbolVisibility) && !(s.visible().kind == Visibility.Kind.protected_) && !symbolIsVisible(this, s)) 520 1.1 mrg s = null; 521 1.1 mrg else 522 1.1 mrg break; 523 1.1 mrg } 524 1.1 mrg 525 1.1 mrg return s; 526 1.1 mrg } 527 1.1 mrg 528 1.1 mrg /************************************ 529 1.1 mrg * Search base classes in depth-first, left-to-right order for 530 1.1 mrg * a class or interface named 'ident'. 531 1.1 mrg * Stops at first found. Does not look for additional matches. 532 1.1 mrg * Params: 533 1.1 mrg * ident = identifier to search for 534 1.1 mrg * Returns: 535 1.1 mrg * ClassDeclaration if found, null if not 536 1.1 mrg */ 537 1.1 mrg final ClassDeclaration searchBase(Identifier ident) 538 1.1 mrg { 539 1.1 mrg foreach (b; *baseclasses) 540 1.1 mrg { 541 1.1 mrg auto cdb = b.type.isClassHandle(); 542 1.1 mrg if (!cdb) // https://issues.dlang.org/show_bug.cgi?id=10616 543 1.1 mrg return null; 544 1.1 mrg if (cdb.ident.equals(ident)) 545 1.1 mrg return cdb; 546 1.1 mrg auto result = cdb.searchBase(ident); 547 1.1 mrg if (result) 548 1.1 mrg return result; 549 1.1 mrg } 550 1.1 mrg return null; 551 1.1 mrg } 552 1.1 mrg 553 1.1 mrg final override void finalizeSize() 554 1.1 mrg { 555 1.1 mrg assert(sizeok != Sizeok.done); 556 1.1 mrg 557 1.1 mrg // Set the offsets of the fields and determine the size of the class 558 1.1 mrg if (baseClass) 559 1.1 mrg { 560 1.1 mrg assert(baseClass.sizeok == Sizeok.done); 561 1.1 mrg 562 1.1 mrg alignsize = baseClass.alignsize; 563 1.1 mrg if (classKind == ClassKind.cpp) 564 1.1 mrg structsize = target.cpp.derivedClassOffset(baseClass); 565 1.1 mrg else 566 1.1 mrg structsize = baseClass.structsize; 567 1.1 mrg } 568 1.1 mrg else if (classKind == ClassKind.objc) 569 1.1 mrg structsize = 0; // no hidden member for an Objective-C class 570 1.1 mrg else if (isInterfaceDeclaration()) 571 1.1 mrg { 572 1.1 mrg if (interfaces.length == 0) 573 1.1 mrg { 574 1.1 mrg alignsize = target.ptrsize; 575 1.1 mrg structsize = target.ptrsize; // allow room for __vptr 576 1.1 mrg } 577 1.1 mrg } 578 1.1 mrg else 579 1.1 mrg { 580 1.1 mrg alignsize = target.ptrsize; 581 1.1 mrg structsize = target.ptrsize; // allow room for __vptr 582 1.1 mrg if (hasMonitor()) 583 1.1 mrg structsize += target.ptrsize; // allow room for __monitor 584 1.1 mrg } 585 1.1 mrg 586 1.1 mrg //printf("finalizeSize() %s, sizeok = %d\n", toChars(), sizeok); 587 1.1 mrg size_t bi = 0; // index into vtblInterfaces[] 588 1.1 mrg 589 1.1 mrg /**** 590 1.1 mrg * Runs through the inheritance graph to set the BaseClass.offset fields. 591 1.1 mrg * Recursive in order to account for the size of the interface classes, if they are 592 1.1 mrg * more than just interfaces. 593 1.1 mrg * Params: 594 1.1 mrg * cd = interface to look at 595 1.1 mrg * baseOffset = offset of where cd will be placed 596 1.1 mrg * Returns: 597 1.1 mrg * subset of instantiated size used by cd for interfaces 598 1.1 mrg */ 599 1.1 mrg uint membersPlace(ClassDeclaration cd, uint baseOffset) 600 1.1 mrg { 601 1.1 mrg //printf(" membersPlace(%s, %d)\n", cd.toChars(), baseOffset); 602 1.1 mrg uint offset = baseOffset; 603 1.1 mrg 604 1.1 mrg foreach (BaseClass* b; cd.interfaces) 605 1.1 mrg { 606 1.1 mrg if (b.sym.sizeok != Sizeok.done) 607 1.1 mrg b.sym.finalizeSize(); 608 1.1 mrg assert(b.sym.sizeok == Sizeok.done); 609 1.1 mrg 610 1.1 mrg if (!b.sym.alignsize) 611 1.1 mrg b.sym.alignsize = target.ptrsize; 612 1.1 mrg alignmember(structalign_t(cast(ushort)b.sym.alignsize), b.sym.alignsize, &offset); 613 1.1 mrg assert(bi < vtblInterfaces.dim); 614 1.1 mrg 615 1.1 mrg BaseClass* bv = (*vtblInterfaces)[bi]; 616 1.1 mrg if (b.sym.interfaces.length == 0) 617 1.1 mrg { 618 1.1 mrg //printf("\tvtblInterfaces[%d] b=%p b.sym = %s, offset = %d\n", bi, bv, bv.sym.toChars(), offset); 619 1.1 mrg bv.offset = offset; 620 1.1 mrg ++bi; 621 1.1 mrg // All the base interfaces down the left side share the same offset 622 1.1 mrg for (BaseClass* b2 = bv; b2.baseInterfaces.length; ) 623 1.1 mrg { 624 1.1 mrg b2 = &b2.baseInterfaces[0]; 625 1.1 mrg b2.offset = offset; 626 1.1 mrg //printf("\tvtblInterfaces[%d] b=%p sym = %s, offset = %d\n", bi, b2, b2.sym.toChars(), b2.offset); 627 1.1 mrg } 628 1.1 mrg } 629 1.1 mrg membersPlace(b.sym, offset); 630 1.1 mrg //printf(" %s size = %d\n", b.sym.toChars(), b.sym.structsize); 631 1.1 mrg offset += b.sym.structsize; 632 1.1 mrg if (alignsize < b.sym.alignsize) 633 1.1 mrg alignsize = b.sym.alignsize; 634 1.1 mrg } 635 1.1 mrg return offset - baseOffset; 636 1.1 mrg } 637 1.1 mrg 638 1.1 mrg structsize += membersPlace(this, structsize); 639 1.1 mrg 640 1.1 mrg if (isInterfaceDeclaration()) 641 1.1 mrg { 642 1.1 mrg sizeok = Sizeok.done; 643 1.1 mrg return; 644 1.1 mrg } 645 1.1 mrg 646 1.1 mrg // FIXME: Currently setFieldOffset functions need to increase fields 647 1.1 mrg // to calculate each variable offsets. It can be improved later. 648 1.1 mrg fields.setDim(0); 649 1.1 mrg 650 1.1 mrg FieldState fieldState; 651 1.1 mrg fieldState.offset = structsize; 652 1.1 mrg foreach (s; *members) 653 1.1 mrg { 654 1.1 mrg s.setFieldOffset(this, fieldState, false); 655 1.1 mrg } 656 1.1 mrg 657 1.1 mrg sizeok = Sizeok.done; 658 1.1 mrg 659 1.1 mrg // Calculate fields[i].overlapped 660 1.1 mrg checkOverlappedFields(); 661 1.1 mrg } 662 1.1 mrg 663 1.1 mrg /************** 664 1.1 mrg * Returns: true if there's a __monitor field 665 1.1 mrg */ 666 1.1 mrg final bool hasMonitor() 667 1.1 mrg { 668 1.1 mrg return classKind == ClassKind.d; 669 1.1 mrg } 670 1.1 mrg 671 1.1 mrg final bool isFuncHidden(FuncDeclaration fd) 672 1.1 mrg { 673 1.1 mrg //printf("ClassDeclaration.isFuncHidden(class = %s, fd = %s)\n", toChars(), fd.toPrettyChars()); 674 1.1 mrg Dsymbol s = search(Loc.initial, fd.ident, IgnoreAmbiguous | IgnoreErrors); 675 1.1 mrg if (!s) 676 1.1 mrg { 677 1.1 mrg //printf("not found\n"); 678 1.1 mrg /* Because, due to a hack, if there are multiple definitions 679 1.1 mrg * of fd.ident, NULL is returned. 680 1.1 mrg */ 681 1.1 mrg return false; 682 1.1 mrg } 683 1.1 mrg s = s.toAlias(); 684 1.1 mrg if (auto os = s.isOverloadSet()) 685 1.1 mrg { 686 1.1 mrg foreach (sm; os.a) 687 1.1 mrg { 688 1.1 mrg auto fm = sm.isFuncDeclaration(); 689 1.1 mrg if (overloadApply(fm, s => fd == s.isFuncDeclaration())) 690 1.1 mrg return false; 691 1.1 mrg } 692 1.1 mrg return true; 693 1.1 mrg } 694 1.1 mrg else 695 1.1 mrg { 696 1.1 mrg auto f = s.isFuncDeclaration(); 697 1.1 mrg //printf("%s fdstart = %p\n", s.kind(), fdstart); 698 1.1 mrg if (overloadApply(f, s => fd == s.isFuncDeclaration())) 699 1.1 mrg return false; 700 1.1 mrg return !fd.parent.isTemplateMixin(); 701 1.1 mrg } 702 1.1 mrg } 703 1.1 mrg 704 1.1 mrg /**************** 705 1.1 mrg * Find virtual function matching identifier and type. 706 1.1 mrg * Used to build virtual function tables for interface implementations. 707 1.1 mrg * Params: 708 1.1 mrg * ident = function's identifier 709 1.1 mrg * tf = function's type 710 1.1 mrg * Returns: 711 1.1 mrg * function symbol if found, null if not 712 1.1 mrg * Errors: 713 1.1 mrg * prints error message if more than one match 714 1.1 mrg */ 715 1.1 mrg final FuncDeclaration findFunc(Identifier ident, TypeFunction tf) 716 1.1 mrg { 717 1.1 mrg //printf("ClassDeclaration.findFunc(%s, %s) %s\n", ident.toChars(), tf.toChars(), toChars()); 718 1.1 mrg FuncDeclaration fdmatch = null; 719 1.1 mrg FuncDeclaration fdambig = null; 720 1.1 mrg 721 1.1 mrg void updateBestMatch(FuncDeclaration fd) 722 1.1 mrg { 723 1.1 mrg fdmatch = fd; 724 1.1 mrg fdambig = null; 725 1.1 mrg //printf("Lfd fdmatch = %s %s [%s]\n", fdmatch.toChars(), fdmatch.type.toChars(), fdmatch.loc.toChars()); 726 1.1 mrg } 727 1.1 mrg 728 1.1 mrg void searchVtbl(ref Dsymbols vtbl) 729 1.1 mrg { 730 1.1 mrg bool seenInterfaceVirtual; 731 1.1 mrg foreach (s; vtbl) 732 1.1 mrg { 733 1.1 mrg auto fd = s.isFuncDeclaration(); 734 1.1 mrg if (!fd) 735 1.1 mrg continue; 736 1.1 mrg 737 1.1 mrg // the first entry might be a ClassInfo 738 1.1 mrg //printf("\t[%d] = %s\n", i, fd.toChars()); 739 1.1 mrg if (ident != fd.ident || fd.type.covariant(tf) != Covariant.yes) 740 1.1 mrg { 741 1.1 mrg //printf("\t\t%d\n", fd.type.covariant(tf)); 742 1.1 mrg continue; 743 1.1 mrg } 744 1.1 mrg 745 1.1 mrg //printf("fd.parent.isClassDeclaration() = %p\n", fd.parent.isClassDeclaration()); 746 1.1 mrg if (!fdmatch) 747 1.1 mrg { 748 1.1 mrg updateBestMatch(fd); 749 1.1 mrg continue; 750 1.1 mrg } 751 1.1 mrg if (fd == fdmatch) 752 1.1 mrg continue; 753 1.1 mrg 754 1.1 mrg /* Functions overriding interface functions for extern(C++) with VC++ 755 1.1 mrg * are not in the normal vtbl, but in vtblFinal. If the implementation 756 1.1 mrg * is again overridden in a child class, both would be found here. 757 1.1 mrg * The function in the child class should override the function 758 1.1 mrg * in the base class, which is done here, because searchVtbl is first 759 1.1 mrg * called for the child class. Checking seenInterfaceVirtual makes 760 1.1 mrg * sure, that the compared functions are not in the same vtbl. 761 1.1 mrg */ 762 1.1 mrg if (fd.interfaceVirtual && 763 1.1 mrg fd.interfaceVirtual is fdmatch.interfaceVirtual && 764 1.1 mrg !seenInterfaceVirtual && 765 1.1 mrg fdmatch.type.covariant(fd.type) == Covariant.yes) 766 1.1 mrg { 767 1.1 mrg seenInterfaceVirtual = true; 768 1.1 mrg continue; 769 1.1 mrg } 770 1.1 mrg 771 1.1 mrg { 772 1.1 mrg // Function type matching: exact > covariant 773 1.1 mrg MATCH m1 = tf.equals(fd.type) ? MATCH.exact : MATCH.nomatch; 774 1.1 mrg MATCH m2 = tf.equals(fdmatch.type) ? MATCH.exact : MATCH.nomatch; 775 1.1 mrg if (m1 > m2) 776 1.1 mrg { 777 1.1 mrg updateBestMatch(fd); 778 1.1 mrg continue; 779 1.1 mrg } 780 1.1 mrg else if (m1 < m2) 781 1.1 mrg continue; 782 1.1 mrg } 783 1.1 mrg { 784 1.1 mrg MATCH m1 = (tf.mod == fd.type.mod) ? MATCH.exact : MATCH.nomatch; 785 1.1 mrg MATCH m2 = (tf.mod == fdmatch.type.mod) ? MATCH.exact : MATCH.nomatch; 786 1.1 mrg if (m1 > m2) 787 1.1 mrg { 788 1.1 mrg updateBestMatch(fd); 789 1.1 mrg continue; 790 1.1 mrg } 791 1.1 mrg else if (m1 < m2) 792 1.1 mrg continue; 793 1.1 mrg } 794 1.1 mrg { 795 1.1 mrg // The way of definition: non-mixin > mixin 796 1.1 mrg MATCH m1 = fd.parent.isClassDeclaration() ? MATCH.exact : MATCH.nomatch; 797 1.1 mrg MATCH m2 = fdmatch.parent.isClassDeclaration() ? MATCH.exact : MATCH.nomatch; 798 1.1 mrg if (m1 > m2) 799 1.1 mrg { 800 1.1 mrg updateBestMatch(fd); 801 1.1 mrg continue; 802 1.1 mrg } 803 1.1 mrg else if (m1 < m2) 804 1.1 mrg continue; 805 1.1 mrg } 806 1.1 mrg 807 1.1 mrg fdambig = fd; 808 1.1 mrg //printf("Lambig fdambig = %s %s [%s]\n", fdambig.toChars(), fdambig.type.toChars(), fdambig.loc.toChars()); 809 1.1 mrg } 810 1.1 mrg } 811 1.1 mrg 812 1.1 mrg searchVtbl(vtbl); 813 1.1 mrg for (auto cd = this; cd; cd = cd.baseClass) 814 1.1 mrg { 815 1.1 mrg searchVtbl(cd.vtblFinal); 816 1.1 mrg } 817 1.1 mrg 818 1.1 mrg if (fdambig) 819 1.1 mrg error("ambiguous virtual function `%s`", fdambig.toChars()); 820 1.1 mrg 821 1.1 mrg return fdmatch; 822 1.1 mrg } 823 1.1 mrg 824 1.1 mrg /**************************************** 825 1.1 mrg */ 826 1.1 mrg final bool isCOMclass() const 827 1.1 mrg { 828 1.1 mrg return com; 829 1.1 mrg } 830 1.1 mrg 831 1.1 mrg bool isCOMinterface() const 832 1.1 mrg { 833 1.1 mrg return false; 834 1.1 mrg } 835 1.1 mrg 836 1.1 mrg final bool isCPPclass() const 837 1.1 mrg { 838 1.1 mrg return classKind == ClassKind.cpp; 839 1.1 mrg } 840 1.1 mrg 841 1.1 mrg bool isCPPinterface() const 842 1.1 mrg { 843 1.1 mrg return false; 844 1.1 mrg } 845 1.1 mrg 846 1.1 mrg /**************************************** 847 1.1 mrg */ 848 1.1 mrg final bool isAbstract() 849 1.1 mrg { 850 1.1 mrg enum log = false; 851 1.1 mrg if (isabstract != ThreeState.none) 852 1.1 mrg return isabstract == ThreeState.yes; 853 1.1 mrg 854 1.1 mrg if (log) printf("isAbstract(%s)\n", toChars()); 855 1.1 mrg 856 1.1 mrg bool no() { if (log) printf("no\n"); isabstract = ThreeState.no; return false; } 857 1.1 mrg bool yes() { if (log) printf("yes\n"); isabstract = ThreeState.yes; return true; } 858 1.1 mrg 859 1.1 mrg if (storage_class & STC.abstract_ || _scope && _scope.stc & STC.abstract_) 860 1.1 mrg return yes(); 861 1.1 mrg 862 1.1 mrg if (errors) 863 1.1 mrg return no(); 864 1.1 mrg 865 1.1 mrg /* https://issues.dlang.org/show_bug.cgi?id=11169 866 1.1 mrg * Resolve forward references to all class member functions, 867 1.1 mrg * and determine whether this class is abstract. 868 1.1 mrg */ 869 1.1 mrg static int func(Dsymbol s) 870 1.1 mrg { 871 1.1 mrg auto fd = s.isFuncDeclaration(); 872 1.1 mrg if (!fd) 873 1.1 mrg return 0; 874 1.1 mrg if (fd.storage_class & STC.static_) 875 1.1 mrg return 0; 876 1.1 mrg 877 1.1 mrg if (fd.isAbstract()) 878 1.1 mrg return 1; 879 1.1 mrg return 0; 880 1.1 mrg } 881 1.1 mrg 882 1.1 mrg for (size_t i = 0; i < members.dim; i++) 883 1.1 mrg { 884 1.1 mrg auto s = (*members)[i]; 885 1.1 mrg if (s.apply(&func)) 886 1.1 mrg { 887 1.1 mrg return yes(); 888 1.1 mrg } 889 1.1 mrg } 890 1.1 mrg 891 1.1 mrg /* If the base class is not abstract, then this class cannot 892 1.1 mrg * be abstract. 893 1.1 mrg */ 894 1.1 mrg if (!isInterfaceDeclaration() && (!baseClass || !baseClass.isAbstract())) 895 1.1 mrg return no(); 896 1.1 mrg 897 1.1 mrg /* If any abstract functions are inherited, but not overridden, 898 1.1 mrg * then the class is abstract. Do this by checking the vtbl[]. 899 1.1 mrg * Need to do semantic() on class to fill the vtbl[]. 900 1.1 mrg */ 901 1.1 mrg this.dsymbolSemantic(null); 902 1.1 mrg 903 1.1 mrg /* The next line should work, but does not because when ClassDeclaration.dsymbolSemantic() 904 1.1 mrg * is called recursively it can set PASS.semanticdone without finishing it. 905 1.1 mrg */ 906 1.1 mrg //if (semanticRun < PASS.semanticdone) 907 1.1 mrg { 908 1.1 mrg /* Could not complete semantic(). Try running semantic() on 909 1.1 mrg * each of the virtual functions, 910 1.1 mrg * which will fill in the vtbl[] overrides. 911 1.1 mrg */ 912 1.1 mrg static int virtualSemantic(Dsymbol s) 913 1.1 mrg { 914 1.1 mrg auto fd = s.isFuncDeclaration(); 915 1.1 mrg if (fd && !(fd.storage_class & STC.static_) && !fd.isUnitTestDeclaration()) 916 1.1 mrg fd.dsymbolSemantic(null); 917 1.1 mrg return 0; 918 1.1 mrg } 919 1.1 mrg 920 1.1 mrg for (size_t i = 0; i < members.dim; i++) 921 1.1 mrg { 922 1.1 mrg auto s = (*members)[i]; 923 1.1 mrg s.apply(&virtualSemantic); 924 1.1 mrg } 925 1.1 mrg } 926 1.1 mrg 927 1.1 mrg /* Finally, check the vtbl[] 928 1.1 mrg */ 929 1.1 mrg foreach (i; 1 .. vtbl.dim) 930 1.1 mrg { 931 1.1 mrg auto fd = vtbl[i].isFuncDeclaration(); 932 1.1 mrg //if (fd) printf("\tvtbl[%d] = [%s] %s\n", i, fd.loc.toChars(), fd.toPrettyChars()); 933 1.1 mrg if (!fd || fd.isAbstract()) 934 1.1 mrg { 935 1.1 mrg return yes(); 936 1.1 mrg } 937 1.1 mrg } 938 1.1 mrg 939 1.1 mrg return no(); 940 1.1 mrg } 941 1.1 mrg 942 1.1 mrg /**************************************** 943 1.1 mrg * Determine if slot 0 of the vtbl[] is reserved for something else. 944 1.1 mrg * For class objects, yes, this is where the classinfo ptr goes. 945 1.1 mrg * For COM interfaces, no. 946 1.1 mrg * For non-COM interfaces, yes, this is where the Interface ptr goes. 947 1.1 mrg * Returns: 948 1.1 mrg * 0 vtbl[0] is first virtual function pointer 949 1.1 mrg * 1 vtbl[0] is classinfo/interfaceinfo pointer 950 1.1 mrg */ 951 1.1 mrg int vtblOffset() const 952 1.1 mrg { 953 1.1 mrg return classKind == ClassKind.cpp ? 0 : 1; 954 1.1 mrg } 955 1.1 mrg 956 1.1 mrg /**************************************** 957 1.1 mrg */ 958 1.1 mrg override const(char)* kind() const 959 1.1 mrg { 960 1.1 mrg return "class"; 961 1.1 mrg } 962 1.1 mrg 963 1.1 mrg /**************************************** 964 1.1 mrg */ 965 1.1 mrg override final void addLocalClass(ClassDeclarations* aclasses) 966 1.1 mrg { 967 1.1 mrg if (classKind != ClassKind.objc) 968 1.1 mrg aclasses.push(this); 969 1.1 mrg } 970 1.1 mrg 971 1.1 mrg override final void addObjcSymbols(ClassDeclarations* classes, ClassDeclarations* categories) 972 1.1 mrg { 973 1.1 mrg .objc.addSymbols(this, classes, categories); 974 1.1 mrg } 975 1.1 mrg 976 1.1 mrg // Back end 977 1.1 mrg Dsymbol vtblsym; 978 1.1 mrg 979 1.1 mrg final Dsymbol vtblSymbol() 980 1.1 mrg { 981 1.1 mrg if (!vtblsym) 982 1.1 mrg { 983 1.1 mrg auto vtype = Type.tvoidptr.immutableOf().sarrayOf(vtbl.dim); 984 1.1 mrg auto var = new VarDeclaration(loc, vtype, Identifier.idPool("__vtbl"), null, STC.immutable_ | STC.static_); 985 1.1 mrg var.addMember(null, this); 986 1.1 mrg var.isdataseg = 1; 987 1.1 mrg var._linkage = LINK.d; 988 1.1 mrg var.semanticRun = PASS.semanticdone; // no more semantic wanted 989 1.1 mrg vtblsym = var; 990 1.1 mrg } 991 1.1 mrg return vtblsym; 992 1.1 mrg } 993 1.1 mrg 994 1.1 mrg override final inout(ClassDeclaration) isClassDeclaration() inout @nogc nothrow pure @safe 995 1.1 mrg { 996 1.1 mrg return this; 997 1.1 mrg } 998 1.1 mrg 999 1.1 mrg override void accept(Visitor v) 1000 1.1 mrg { 1001 1.1 mrg v.visit(this); 1002 1.1 mrg } 1003 1.1 mrg } 1004 1.1 mrg 1005 1.1 mrg /*********************************************************** 1006 1.1 mrg */ 1007 1.1 mrg extern (C++) final class InterfaceDeclaration : ClassDeclaration 1008 1.1 mrg { 1009 1.1 mrg extern (D) this(const ref Loc loc, Identifier id, BaseClasses* baseclasses) 1010 1.1 mrg { 1011 1.1 mrg super(loc, id, baseclasses, null, false); 1012 1.1 mrg if (id == Id.IUnknown) // IUnknown is the root of all COM interfaces 1013 1.1 mrg { 1014 1.1 mrg com = true; 1015 1.1 mrg classKind = ClassKind.cpp; // IUnknown is also a C++ interface 1016 1.1 mrg } 1017 1.1 mrg } 1018 1.1 mrg 1019 1.1 mrg override InterfaceDeclaration syntaxCopy(Dsymbol s) 1020 1.1 mrg { 1021 1.1 mrg InterfaceDeclaration id = 1022 1.1 mrg s ? cast(InterfaceDeclaration)s 1023 1.1 mrg : new InterfaceDeclaration(loc, ident, null); 1024 1.1 mrg ClassDeclaration.syntaxCopy(id); 1025 1.1 mrg return id; 1026 1.1 mrg } 1027 1.1 mrg 1028 1.1 mrg 1029 1.1 mrg override Scope* newScope(Scope* sc) 1030 1.1 mrg { 1031 1.1 mrg auto sc2 = super.newScope(sc); 1032 1.1 mrg if (com) 1033 1.1 mrg sc2.linkage = LINK.windows; 1034 1.1 mrg else if (classKind == ClassKind.cpp) 1035 1.1 mrg sc2.linkage = LINK.cpp; 1036 1.1 mrg else if (classKind == ClassKind.objc) 1037 1.1 mrg sc2.linkage = LINK.objc; 1038 1.1 mrg return sc2; 1039 1.1 mrg } 1040 1.1 mrg 1041 1.1 mrg /******************************************* 1042 1.1 mrg * Determine if 'this' is a base class of cd. 1043 1.1 mrg * (Actually, if it is an interface supported by cd) 1044 1.1 mrg * Output: 1045 1.1 mrg * *poffset offset to start of class 1046 1.1 mrg * OFFSET_RUNTIME must determine offset at runtime 1047 1.1 mrg * Returns: 1048 1.1 mrg * false not a base 1049 1.1 mrg * true is a base 1050 1.1 mrg */ 1051 1.1 mrg override bool isBaseOf(ClassDeclaration cd, int* poffset) pure nothrow @nogc 1052 1.1 mrg { 1053 1.1 mrg //printf("%s.InterfaceDeclaration.isBaseOf(cd = '%s')\n", toChars(), cd.toChars()); 1054 1.1 mrg assert(!baseClass); 1055 1.1 mrg foreach (b; cd.interfaces) 1056 1.1 mrg { 1057 1.1 mrg //printf("\tX base %s\n", b.sym.toChars()); 1058 1.1 mrg if (this == b.sym) 1059 1.1 mrg { 1060 1.1 mrg //printf("\tfound at offset %d\n", b.offset); 1061 1.1 mrg if (poffset) 1062 1.1 mrg { 1063 1.1 mrg // don't return incorrect offsets 1064 1.1 mrg // https://issues.dlang.org/show_bug.cgi?id=16980 1065 1.1 mrg *poffset = cd.sizeok == Sizeok.done ? b.offset : OFFSET_FWDREF; 1066 1.1 mrg } 1067 1.1 mrg // printf("\tfound at offset %d\n", b.offset); 1068 1.1 mrg return true; 1069 1.1 mrg } 1070 1.1 mrg if (baseClassImplementsInterface(this, b, poffset)) 1071 1.1 mrg return true; 1072 1.1 mrg } 1073 1.1 mrg if (cd.baseClass && isBaseOf(cd.baseClass, poffset)) 1074 1.1 mrg return true; 1075 1.1 mrg 1076 1.1 mrg if (poffset) 1077 1.1 mrg *poffset = 0; 1078 1.1 mrg return false; 1079 1.1 mrg } 1080 1.1 mrg 1081 1.1 mrg /******************************************* 1082 1.1 mrg */ 1083 1.1 mrg override const(char)* kind() const 1084 1.1 mrg { 1085 1.1 mrg return "interface"; 1086 1.1 mrg } 1087 1.1 mrg 1088 1.1 mrg /**************************************** 1089 1.1 mrg * Determine if slot 0 of the vtbl[] is reserved for something else. 1090 1.1 mrg * For class objects, yes, this is where the ClassInfo ptr goes. 1091 1.1 mrg * For COM interfaces, no. 1092 1.1 mrg * For non-COM interfaces, yes, this is where the Interface ptr goes. 1093 1.1 mrg */ 1094 1.1 mrg override int vtblOffset() const 1095 1.1 mrg { 1096 1.1 mrg if (isCOMinterface() || isCPPinterface()) 1097 1.1 mrg return 0; 1098 1.1 mrg return 1; 1099 1.1 mrg } 1100 1.1 mrg 1101 1.1 mrg override bool isCPPinterface() const 1102 1.1 mrg { 1103 1.1 mrg return classKind == ClassKind.cpp; 1104 1.1 mrg } 1105 1.1 mrg 1106 1.1 mrg override bool isCOMinterface() const 1107 1.1 mrg { 1108 1.1 mrg return com; 1109 1.1 mrg } 1110 1.1 mrg 1111 1.1 mrg override inout(InterfaceDeclaration) isInterfaceDeclaration() inout 1112 1.1 mrg { 1113 1.1 mrg return this; 1114 1.1 mrg } 1115 1.1 mrg 1116 1.1 mrg override void accept(Visitor v) 1117 1.1 mrg { 1118 1.1 mrg v.visit(this); 1119 1.1 mrg } 1120 1.1 mrg } 1121 1.1 mrg 1122 1.1 mrg /** 1123 1.1 mrg * Returns whether `bc` implements `id`, including indirectly (`bc` implements an interfaces 1124 1.1 mrg * that inherits from `id`) 1125 1.1 mrg * 1126 1.1 mrg * Params: 1127 1.1 mrg * id = the interface 1128 1.1 mrg * bc = the base class 1129 1.1 mrg * poffset = out parameter, offset of the interface in an object 1130 1.1 mrg * 1131 1.1 mrg * Returns: 1132 1.1 mrg * true if the `bc` implements `id`, false otherwise 1133 1.1 mrg **/ 1134 1.1 mrg private bool baseClassImplementsInterface(InterfaceDeclaration id, BaseClass* bc, int* poffset) pure nothrow @nogc 1135 1.1 mrg { 1136 1.1 mrg //printf("%s.InterfaceDeclaration.isBaseOf(bc = '%s')\n", id.toChars(), bc.sym.toChars()); 1137 1.1 mrg for (size_t j = 0; j < bc.baseInterfaces.length; j++) 1138 1.1 mrg { 1139 1.1 mrg BaseClass* b = &bc.baseInterfaces[j]; 1140 1.1 mrg //printf("\tY base %s\n", b.sym.toChars()); 1141 1.1 mrg if (id == b.sym) 1142 1.1 mrg { 1143 1.1 mrg //printf("\tfound at offset %d\n", b.offset); 1144 1.1 mrg if (poffset) 1145 1.1 mrg { 1146 1.1 mrg *poffset = b.offset; 1147 1.1 mrg } 1148 1.1 mrg return true; 1149 1.1 mrg } 1150 1.1 mrg if (baseClassImplementsInterface(id, b, poffset)) 1151 1.1 mrg { 1152 1.1 mrg return true; 1153 1.1 mrg } 1154 1.1 mrg } 1155 1.1 mrg 1156 1.1 mrg if (poffset) 1157 1.1 mrg *poffset = 0; 1158 1.1 mrg return false; 1159 1.1 mrg } 1160