| 524 | } |
| 525 | |
| 526 | FunctionPtr generateStructureFinalizer ( const StructurePtr & ls ) { |
| 527 | auto pFunc = new Function(); |
| 528 | pFunc->privateFunction = true; |
| 529 | pFunc->generated = true; |
| 530 | pFunc->at = pFunc->atDecl = ls->at; |
| 531 | pFunc->name = "finalize"; |
| 532 | if ( ls->isClass ) { |
| 533 | pFunc->isClassMethod = true; |
| 534 | pFunc->classParent = ls; |
| 535 | DAS_ASSERT(pFunc->classParent); |
| 536 | } |
| 537 | if ( ls->macroInterface ) pFunc->macroFunction = true; |
| 538 | auto fb = new ExprBlock(); |
| 539 | fb->at = ls->at; |
| 540 | // For a class whose ancestry has a user finalizer, chain to the immediate |
| 541 | // parent: this finalizer owns only its own slice of the fields (everything |
| 542 | // past the parent prefix), then `delete cast<Parent>(__this)` runs the |
| 543 | // parent's finalize — the user one, or a generated chain finalizer that |
| 544 | // recurses the same way. Derived slice first, parent second (dtor order). |
| 545 | Structure * chainParent = ( ls->isClass && findChainFinalizerAncestor(ls) ) ? ls->parent : nullptr; |
| 546 | size_t firstOwnField = chainParent ? chainParent->fields.size() : 0; |
| 547 | // now finalize |
| 548 | bool needUnsafe = false; |
| 549 | for ( int stage=0; stage!=2; ++stage ) { |
| 550 | // stage 0 is iterators, stage 1 is everything else |
| 551 | for ( size_t fi=firstOwnField, fis=ls->fields.size(); fi!=fis; ++fi ) { |
| 552 | const auto & fl = ls->fields[fi]; |
| 553 | if ( !fl.type->constant && !fl.capturedConstant && fl.type->needDelete() ) { |
| 554 | if ( !fl.doNotDelete && !fl.capturedRef ) { |
| 555 | if ( stage==0 && !fl.type->isIterator() ) continue; |
| 556 | if ( stage==1 && fl.type->isIterator() ) continue; |
| 557 | if ( fl.type->isPointer() && fl.type->firstType && fl.type->firstType->constant ) continue; |
| 558 | if ( ls->isLambda && !fl.type->isSafeToDelete() ) continue; // we don't do unsafe delete for lambda |
| 559 | auto fva = new ExprVar(fl.at, "__this"); |
| 560 | auto fld = new ExprField(fl.at, fva, fl.name); |
| 561 | fld->ignoreCaptureConst = true; |
| 562 | auto delf = new ExprDelete(fl.at, fld); |
| 563 | delf->alwaysSafe = true; |
| 564 | fb->list.emplace_back(delf); |
| 565 | if ( fl.type->isPointer() ) { |
| 566 | needUnsafe = true; |
| 567 | } |
| 568 | } |
| 569 | } |
| 570 | } |
| 571 | } |
| 572 | if ( chainParent ) { |
| 573 | auto chthis = new ExprVar(ls->at, "__this"); |
| 574 | auto chcast = new ExprCast(ls->at, chthis, new TypeDecl(chainParent)); |
| 575 | auto chdel = new ExprDelete(ls->at, chcast); |
| 576 | chdel->alwaysSafe = true; |
| 577 | fb->list.push_back(chdel); |
| 578 | } |
| 579 | auto mz = new ExprMemZero(ls->at, "memzero"); |
| 580 | auto lvar = new ExprVar(ls->at, "__this"); |
| 581 | mz->arguments.push_back(lvar); |
| 582 | fb->list.push_back(mz); |
| 583 | pFunc->body = fb; |
no test coverage detected