CfrontCodeGenerator.cpp
Go to the documentation of this file.
1/******************************************************************************
2 *
3 * C++ Insights, copyright (C) by Andreas Fertig
4 * Distributed under an MIT license. See LICENSE for details
5 *
6 ****************************************************************************/
7
8#include <clang/AST/VTableBuilder.h>
9
10#include <algorithm>
11#include <vector>
12
13#include "CodeGenerator.h"
14#include "DPrint.h"
15#include "Insights.h"
16#include "InsightsHelpers.h"
17#include "InsightsOnce.h"
18#include "InsightsStrCat.h"
19#include "NumberIterator.h"
20
21#include "ASTHelpers.h"
22//-----------------------------------------------------------------------------
23
24namespace clang::insights {
25
26using namespace asthelpers;
27//-----------------------------------------------------------------------------
28
29//! Store the `this` pointer offset from derived to base class.
30static llvm::DenseMap<std::pair<const CXXRecordDecl*, const CXXRecordDecl*>, int> mThisPointerOffset{};
31//-----------------------------------------------------------------------------
32
33static MemberExpr* AccessMember(std::string_view name, const ValueDecl* vd, QualType type)
34{
35 auto* rhsDeclRef = mkVarDeclRefExpr(name, type);
36 auto* rhsMemberExpr = AccessMember(rhsDeclRef, vd);
37
38 return rhsMemberExpr;
39}
40//-----------------------------------------------------------------------------
41
43: vptpTypedef{Typedef("__vptp"sv, Function("vptp"sv, GetGlobalAST().IntTy, {})->getType())}
44, vtableRecorDecl{}
45{
46 vtableRecorDecl = Struct("__mptr"sv);
47 auto AddField = [&](FieldDecl* field) { vtableRecorDecl->addDecl(field); };
48
49 d = mkFieldDecl(vtableRecorDecl, "d"sv, GetGlobalAST().ShortTy);
50 AddField(d);
51 AddField(mkFieldDecl(vtableRecorDecl, "i"sv, GetGlobalAST().ShortTy));
52 f = mkFieldDecl(vtableRecorDecl, "f"sv, vptpTypedef);
53 AddField(f);
54
55 vtableRecorDecl->completeDefinition();
56
57 vtableRecordType =
58#if IS_CLANG_NEWER_THAN(22)
59 vtableRecorDecl->getASTContext().getCanonicalTagType(vtableRecorDecl);
60#else
61 QualType{vtableRecorDecl->getTypeForDecl(), 0u};
62#endif
63}
64//-----------------------------------------------------------------------------
65
67{
68 return Variable("__vtbl_array"sv, ContantArrayTy(Ptr(vtableRecordType), size));
69}
70//-----------------------------------------------------------------------------
71
72FieldDecl* CfrontCodeGenerator::CfrontVtableData::VtblPtrField(const CXXRecordDecl* parent)
73{
74 return mkFieldDecl(const_cast<CXXRecordDecl*>(parent), StrCat("__vptr"sv, GetName(*parent)), Ptr(vtableRecordType));
75}
76//-----------------------------------------------------------------------------
77
84//-----------------------------------------------------------------------------
85
86CodeGeneratorVariant::CodeGenerators::CodeGenerators(OutputFormatHelper& _outputFormatHelper,
88 CodeGenerator::ProcessingPrimaryTemplate processingPrimaryTemplate)
89{
90 if(GetInsightsOptions().UseShow2C) {
91 new(&cfcg) CfrontCodeGenerator{_outputFormatHelper, lambdaStack, processingPrimaryTemplate};
92 } else {
93 new(&cg) CodeGenerator{_outputFormatHelper, lambdaStack, processingPrimaryTemplate};
94 }
95}
96//-----------------------------------------------------------------------------
97
98CodeGeneratorVariant::CodeGenerators::CodeGenerators(OutputFormatHelper& _outputFormatHelper)
99{
100 if(GetInsightsOptions().UseShow2C) {
101 new(&cfcg) CfrontCodeGenerator{_outputFormatHelper};
102 } else {
103 new(&cg) CodeGenerator{_outputFormatHelper};
104 }
105}
106//-----------------------------------------------------------------------------
107
108CodeGeneratorVariant::CodeGenerators::~CodeGenerators()
109{
110 if(GetInsightsOptions().UseShow2C) {
111 cfcg.~CfrontCodeGenerator();
112 } else {
113 cg.~CodeGenerator();
114 }
115}
116//-----------------------------------------------------------------------------
117
118void CodeGeneratorVariant::Set()
119{
120 if(GetInsightsOptions().UseShow2C) {
121 cg = &cgs.cfcg;
122 } else {
123 cg = &cgs.cg;
124 }
125}
126//-----------------------------------------------------------------------------
127
128static bool IsCopyOrMoveCtor(const CXXConstructorDecl* ctor)
129{
130 return ctor and (ctor->isCopyConstructor() or ctor->isMoveConstructor());
131}
132//-----------------------------------------------------------------------------
133
134static bool IsCopyOrMoveAssign(const CXXMethodDecl* stmt)
135{
136 return stmt and (stmt->isCopyAssignmentOperator() or stmt->isMoveAssignmentOperator());
137}
138//-----------------------------------------------------------------------------
139
140static std::string GetSpecialMemberName(const ValueDecl* vd, QualType type)
141{
142 if(const auto* md = dyn_cast_or_null<CXXMethodDecl>(vd)) {
143 // GetName below would return a[4] for example. To avoid the array part we go for the underlying type.
144 if(const auto* ar = dyn_cast_or_null<ArrayType>(type)) {
145 type = ar->getElementType();
146 }
147
148 auto rdName = GetName(type);
149
150 if(const auto* ctor = dyn_cast_or_null<CXXConstructorDecl>(md)) {
151 if(ctor->isCopyConstructor()) {
152 return StrCat("CopyConstructor_"sv, rdName);
153 } else if(ctor->isMoveConstructor()) {
154 return StrCat("MoveConstructor_"sv, rdName);
155 }
156
157 return StrCat("Constructor_"sv, rdName);
158
159 } else if(isa<CXXDestructorDecl>(md)) {
160 return StrCat("Destructor_"sv, rdName);
161 }
162 }
163
164 return GetName(*vd);
165}
166//-----------------------------------------------------------------------------
167
168std::string GetSpecialMemberName(const ValueDecl* vd)
169{
170 if(const auto* md = dyn_cast_or_null<CXXMethodDecl>(vd)) {
172 }
173
174 return {};
175}
176//-----------------------------------------------------------------------------
177
182//-----------------------------------------------------------------------------
183
184static bool HasCtor(QualType t)
185{
186 if(auto* cxxRecordDecl = t->getAsCXXRecordDecl(); cxxRecordDecl and not cxxRecordDecl->isTrivial()) {
187 return true;
188 }
189
190 return false;
191}
192//-----------------------------------------------------------------------------
193
194static bool HasDtor(QualType t)
195{
196 if(auto* cxxRecordDecl = t->getAsCXXRecordDecl(); cxxRecordDecl and not cxxRecordDecl->hasTrivialDestructor()) {
197 return true;
198 }
199
200 return false;
201}
202//-----------------------------------------------------------------------------
203
204static auto* CallVecDeleteOrDtor(Expr* objectParam, QualType allocatedType, std::string_view name, uint64_t size)
205{
206 auto dtorName = GetSpecialMemberName(allocatedType->getAsCXXRecordDecl()->getDestructor());
207
208 SmallVector<Expr*, 4> args{objectParam,
209 Sizeof(allocatedType),
210 Int32(size), // XXX what is the correct value?
211 CastToVoidFunPtr(dtorName)};
212
213 return Call(name, args);
214}
215//-----------------------------------------------------------------------------
216
217static auto* CallVecDelete(Expr* objectParam, QualType allocatedType)
218{
220
221 return CallVecDeleteOrDtor(objectParam, allocatedType, "__cxa_vec_delete"sv, 0);
222}
223//-----------------------------------------------------------------------------
224
225static auto* CallVecDtor(Expr* objectParam, const ConstantArrayType* ar)
226{
228
229 return CallVecDeleteOrDtor(objectParam, ar->getElementType(), "__cxa_vec_dtor"sv, GetSize(ar));
230}
231//-----------------------------------------------------------------------------
232
233void CfrontCodeGenerator::InsertArg(const CXXDeleteExpr* stmt)
234{
235 auto destroyedType = stmt->getDestroyedType();
236 auto* arg = const_cast<Expr*>(stmt->getArgument());
237
238 StmtsContainer bodyStmts{};
239
240 if(const auto hasDtor{HasDtor(destroyedType)}; stmt->isArrayForm() and hasDtor) {
241 bodyStmts.Add(CallVecDelete(arg, destroyedType));
242 } else if(hasDtor) {
243 bodyStmts.Add(Call(StrCat("Destructor_"sv, GetName(destroyedType)), {arg}));
244 }
245
247
248 bodyStmts.Add(Call("free"sv, {arg}));
249
250 InsertArg(If(arg, {bodyStmts}));
251 mInsertSemi = false; // Since we tamper with a CompoundStmt we signal _not_ to insert the usual semi
252}
253//-----------------------------------------------------------------------------
254
255static auto* CallVecNewOrCtor(std::string_view ctorName,
256 Expr* objectParam,
257 QualType allocatedType,
258 Expr* arraySizeExpr,
259 std::string_view funName)
260{
261 // According to "Inside the C++ Object Model" the dtor is required in case one of the array element ctors fails the
262 // already constructed one must be destroyed.
263 // See also: https://itanium-cxx-abi.github.io/cxx-abi/abi.html#array-ctor
264 auto dtorName = [&]() {
265 if(HasDtor(allocatedType)) {
266 return GetSpecialMemberName(allocatedType->getAsCXXRecordDecl()->getDestructor());
267 }
268
269 return std::string{kwNull};
270 }();
271
272 SmallVector<Expr*, 6> args{objectParam,
273 Sizeof(allocatedType),
274 arraySizeExpr,
275 Int32(0), // XXX what is the correct value?
276 CastToVoidFunPtr(ctorName),
277 CastToVoidFunPtr(dtorName)};
278
279 return Call(funName, args);
280}
281//-----------------------------------------------------------------------------
282
283static auto* CallVecNew(std::string_view ctorName, Expr* objectParam, QualType allocatedType, Expr* arraySizeExpr)
284{
286
287 return CallVecNewOrCtor(ctorName, objectParam, allocatedType, arraySizeExpr, "__cxa_vec_new"sv);
288}
289//-----------------------------------------------------------------------------
290
291static auto*
292CallVecCtor(std::string_view ctorName, const VarDecl* objectParam, QualType allocatedType, Expr* arraySizeExpr)
293{
295
296 return CallVecNewOrCtor(ctorName, mkDeclRefExpr(objectParam), allocatedType, arraySizeExpr, "__cxa_vec_ctor"sv);
297}
298//-----------------------------------------------------------------------------
299
300void CfrontCodeGenerator::InsertArg(const CXXNewExpr* cstmt)
301{
302 auto* stmt = const_cast<CXXNewExpr*>(cstmt);
303
304 auto allocatedType = stmt->getAllocatedType();
305 auto ctorName = StrCat("Constructor_"sv, GetName(allocatedType));
306
307 if(stmt->isArray()) {
309
310 auto* arraySizeExpr = stmt->getArraySize().value();
311 auto* callMalloc = Call("malloc"sv, {Mul(Sizeof(allocatedType), arraySizeExpr)});
312
313 Expr* assign{};
314
315 // According to "Inside the C++ Object Model" a trivial and literal type does use plain malloc as it does not
316 // require a ctor/dtor.
317 if(not HasCtor(allocatedType) and not HasDtor(allocatedType)) {
318 assign = Cast(callMalloc, Ptr(allocatedType));
319
320 } else {
321 if(allocatedType->getAsCXXRecordDecl()->ctors().empty()) {
323
324 ctorName = kwNull;
325 }
326
327 assign = Cast(CallVecNew(ctorName, callMalloc, allocatedType, arraySizeExpr), Ptr(allocatedType));
328 }
329
330 InsertArg(assign);
331
332 if(stmt->hasInitializer() and allocatedType->isBuiltinType()) { // Ignore CXXConstructExpr
333 // The resulting code here is slightly different from the cfront code. For
334 //
335 // int* p = new int(2);
336 //
337 // C++ Insights generates:
338 //
339 // int* p = (int*)malloc(sizeof(int));
340 // if(p) { *p = 2; }
341 //
342 // However, due to Cs requirement to only declare variables and delay initialization the cfront code is
343 //
344 // int* p;
345 // if(p = (int*)malloc(sizeof(int))) { *p = 2; }
347
348 if(auto* inits = dyn_cast_or_null<InitListExpr>(stmt->getInitializer())) {
349 auto* expr = [&]() -> const Expr* {
350 if(auto* vd = dyn_cast_or_null<VarDecl>(mLastDecl)) {
351 return mkDeclRefExpr(vd);
352 }
353
354 return mLastExpr;
355 }();
356
357 StmtsContainer bodyStmts{};
358
359 for(auto idx : NumberIterator(inits->getNumInits())) {
360 bodyStmts.Add(Assign(ArraySubscript(expr, idx, allocatedType), inits->getInit(idx)));
361 }
362
363 InsertArg(If(expr, {bodyStmts}));
364
365 mInsertSemi = false; // Since we tamper with a CompoundStmt we signal _not_ to insert the usual semi
366 }
367 }
368
369 return;
370 }
371
372 auto* mallocCall = [&]() -> Expr* {
373 if(stmt->getNumPlacementArgs()) {
374 return stmt->getPlacementArg(0);
375 }
376
378
379 return Call("malloc"sv, {Sizeof(allocatedType)});
380 }();
381
382 mallocCall = Cast(mallocCall, Ptr(allocatedType));
383
384 if(allocatedType->isBuiltinType()) {
385 InsertArg(mallocCall);
386
387 if(stmt->hasInitializer()) {
388 // The resulting code here is slightly different from the cfront code. For
389 //
390 // int* p = new int(2);
391 //
392 // C++ Insights generates:
393 //
394 // int* p = (int*)malloc(sizeof(int));
395 // if(p) { *p = 2; }
396 //
397 // However, due to Cs requirement to only declare variables and delay initialization the cfront code is
398 //
399 // int* p;
400 // if(p = (int*)malloc(sizeof(int))) { *p = 2; }
402
403 auto* varDeclRefExpr = mkDeclRefExpr(dyn_cast_or_null<VarDecl>(mLastDecl));
404
405 StmtsContainer bodyStmts{Assign(Dref(varDeclRefExpr), stmt->getInitializer())};
406
407 InsertArg(If(varDeclRefExpr, {bodyStmts}));
408
409 mInsertSemi = false; // Since we tamper with a CompoundStmt we signal _not_ to insert the usual semi
410 }
411
412 return;
413 }
414
415 SmallVector<Expr*, 16> args{mallocCall};
416 if(auto* ncCtorExpr = const_cast<CXXConstructExpr*>(stmt->getConstructExpr())) {
417 args.append(ncCtorExpr->arg_begin(), ncCtorExpr->arg_end());
418 }
419
420 InsertArg(Call(ctorName, args));
421}
422//-----------------------------------------------------------------------------
423
424void CfrontCodeGenerator::InsertArg(const CXXOperatorCallExpr* stmt)
425{
426 const auto* callee = stmt->getDirectCallee();
427
428 if(const auto* cxxCallee = dyn_cast_or_null<CXXMethodDecl>(callee); IsCopyOrMoveAssign(cxxCallee)) {
429 SmallVector<Expr*, 16> args{};
430
431 for(const auto& arg : stmt->arguments()) {
432 args.push_back(Ref(arg));
433 }
434
435 InsertArg(Call(callee, args));
436
437 } else {
438 InsertArg(dyn_cast_or_null<CallExpr>(stmt));
439 }
440}
441//-----------------------------------------------------------------------------
442
443static void InsertVtblPtr(const CXXMethodDecl* stmt, const CXXRecordDecl* cur, StmtsContainer& bodyStmts)
444{
445 if(cur->isPolymorphic() and (0 == cur->getNumBases())) {
446 auto* fieldDecl = CfrontCodeGenerator::VtableData().VtblPtrField(cur);
447 auto* lhsMemberExpr = AccessMember(kwInternalThis, fieldDecl, Ptr(GetRecordDeclType(cur)));
448
449 // struct __mptr *__ptbl_vec__c___src_C_[]
451 auto* vtblArrayPos =
452 ArraySubscript(mkDeclRefExpr(vtablAr), GetGlobalVtablePos(stmt->getParent(), cur), fieldDecl->getType());
453
454 bodyStmts.AddBodyStmts(Assign(lhsMemberExpr, fieldDecl, vtblArrayPos));
455
456 } else if(cur->isPolymorphic() and (0 < cur->getNumBases()) and (cur != stmt->getParent())) {
457 for(const auto& base : cur->bases()) {
458 InsertVtblPtr(stmt, base.getType()->getAsCXXRecordDecl(), bodyStmts);
459 }
460 }
461}
462//-----------------------------------------------------------------------------
463
465{
466 // Skip if he method is unused like assignment operators by default.
467 RETURN_IF(not stmt->isUsed() and
468 (IsCopyOrMoveAssign(stmt) or (not stmt->hasBody() and not isa<CXXConstructorDecl>(stmt))));
469
470 OutputFormatHelper initOutputFormatHelper{};
471 initOutputFormatHelper.SetIndent(mOutputFormatHelper, OutputFormatHelper::SkipIndenting::Yes);
472
473 auto recordDeclType = GetRecordDeclType(stmt);
474 if(stmt->isConst()) {
475 recordDeclType.addConst();
476 }
477
478 auto parentType = Ptr(recordDeclType);
479 auto* body = stmt->getBody();
480 StmtsContainer bodyStmts{};
481
482 auto retType = stmt->getReturnType();
483
484 auto processBaseClassesAndFields = [&](const CXXRecordDecl* parent) {
485 auto* thisOfParent = mkVarDeclRefExpr(kwInternalThis, parentType);
486
487 auto insertFields = [&](const RecordDecl* rd) {
488 for(auto* fieldDecl : rd->fields()) {
489 if(const auto* cxxRecordDecl = fieldDecl->getType()->getAsCXXRecordDecl()) {
490 // We don't need any checks like isDefaultConstructible. We would not reach this
491 // point in any other case.
492
493 auto lvalueRefType = GetGlobalAST().getLValueReferenceType(parentType);
494 auto* lhsMemberExpr = AccessMember(kwInternalThis, fieldDecl, lvalueRefType);
495 auto* rhsMemberExpr = AccessMember("__rhs"sv, fieldDecl, lvalueRefType);
496
497 // Add call to ctor
498 bodyStmts.AddBodyStmts(Call(GetSpecialMemberName(stmt, GetRecordDeclType(cxxRecordDecl)),
499 {Ref(lhsMemberExpr), Ref(rhsMemberExpr)}));
500
501 } else {
502 auto* rhsMemberExpr = AccessMember("__rhs"sv, fieldDecl, parentType);
503
504 bodyStmts.AddBodyStmts(Assign(thisOfParent, fieldDecl, rhsMemberExpr));
505 }
506 }
507 };
508
509 for(const auto& base : parent->bases()) {
510 const auto rd = base.getType()->getAsRecordDecl();
511
512 auto* lhsCast = StaticCast(GetRecordDeclType(rd), thisOfParent, true);
513 auto* rhsDeclRef = mkVarDeclRefExpr("__rhs"sv, parentType);
514 auto* rhsCast = StaticCast(GetRecordDeclType(rd), rhsDeclRef, true);
515
516 auto* callAssignBase = Call(GetSpecialMemberName(stmt, GetRecordDeclType(rd)), {lhsCast, rhsCast});
517
518 bodyStmts.AddBodyStmts(callAssignBase);
519 }
520
521 // insert own fields
522 insertFields(parent);
523 };
524
525 // Skip ctor for trivial types
526 if(const auto* ctorDecl = dyn_cast_or_null<CXXConstructorDecl>(stmt)) {
527 const auto* parent = stmt->getParent();
528
529 if(not stmt->doesThisDeclarationHaveABody()) {
530 if(IsCopyOrMoveCtor(ctorDecl)) {
531 if(const bool showSpecialMemberFunc{stmt->isUserProvided() or stmt->isExplicitlyDefaulted()};
532 not showSpecialMemberFunc) {
533 return;
534 }
535
536 processBaseClassesAndFields(parent);
537 }
538 } else if(ctorDecl->isDefaultConstructor()) {
539 auto insertFields = [&](const RecordDecl* rd) {
540 for(auto* fieldDecl : rd->fields()) {
541 if(auto* initializer = fieldDecl->getInClassInitializer();
542 initializer and fieldDecl->hasInClassInitializer()) {
543 const bool isConstructorExpr{isa<CXXConstructExpr>(initializer) or
544 isa<ExprWithCleanups>(initializer)};
545
546 if(not isConstructorExpr) {
547 auto* lhsMemberExpr = AccessMember(kwInternalThis, fieldDecl, Ptr(GetRecordDeclType(rd)));
548
549 bodyStmts.AddBodyStmts(Assign(lhsMemberExpr, fieldDecl, initializer));
550
551 } else {
552 bodyStmts.AddBodyStmts(CallConstructor(fieldDecl->getType(),
554 fieldDecl,
555 ArgsToExprVector(initializer),
556 DoCast::No,
557 AsReference::Yes));
558 }
559
560 } else if(const auto* cxxRecordDecl = fieldDecl->getType()->getAsCXXRecordDecl()) {
561 // We don't need any checks like isDefaultConstructible. We would not reach this
562 // point in any other cause.
563
564 if(auto lhsType = fieldDecl->getType(); HasCtor(lhsType)) {
565 bodyStmts.AddBodyStmts(CallConstructor(GetRecordDeclType(cxxRecordDecl),
566 Ptr(GetRecordDeclType(cxxRecordDecl)),
567 fieldDecl,
568 {},
569 DoCast::No,
570 AsReference::Yes));
571
572 } else {
573 bodyStmts.Add(
574 Comment(StrCat(GetName(*fieldDecl), " // trivial type, maybe uninitialized"sv)));
575 // Nothing to do here, we are looking at an uninitialized variable
576 }
577 }
578 }
579 };
580
581 for(const auto& base : parent->bases()) {
582 auto baseType = base.getType();
583
584 if(const auto* baseRd = baseType->getAsCXXRecordDecl();
585 baseRd and baseRd->hasNonTrivialDefaultConstructor()) {
586 bodyStmts.AddBodyStmts(CallConstructor(baseType, Ptr(baseType), nullptr, {}, DoCast::Yes));
587 }
588 }
589
590 // insert our vtable pointer
591 InsertVtblPtr(stmt, stmt->getParent(), bodyStmts);
592
593 // in case of multi inheritance insert additional vtable pointers
594 for(const auto& base : parent->bases()) {
595 InsertVtblPtr(stmt, base.getType()->getAsCXXRecordDecl(), bodyStmts);
596 }
597
598 // insert own fields
599 insertFields(parent);
600
601 } else {
602 // user ctor
603 for(const auto* init : ctorDecl->inits()) {
604 auto* member = init->getMember();
605
606 if(not isa<CXXConstructExpr>(init->getInit())) {
607 if(not init->getAnyMember()) {
608 continue;
609 }
610
611 auto* lhsMemberExpr = AccessMember(kwInternalThis, member, Ptr(GetRecordDeclType(parent)));
612
613 bodyStmts.AddBodyStmts(Assign(lhsMemberExpr, member, init->getInit()));
614 continue;
615
616 } else if(init->isBaseInitializer()) {
617 bodyStmts.AddBodyStmts(init->getInit());
618 continue;
619 }
620
621 auto ctorType = member->getType();
622
623 auto* lhsMemberExpr = AccessMember(kwInternalThis, member, ctorType);
624
625 auto callParams{ArgsToExprVector(init->getInit())};
626 callParams.insert(callParams.begin(), Ref(lhsMemberExpr));
627
628 bodyStmts.AddBodyStmts(
629 Call(GetSpecialMemberName(stmt, GetRecordDeclType(ctorType->getAsRecordDecl())), callParams));
630 }
631
632 // insert our vtable pointer
633 InsertVtblPtr(stmt, stmt->getParent(), bodyStmts);
634 // in case of multi inheritance insert additional vtable pointers
635 for(const auto& base : parent->bases()) {
636 InsertVtblPtr(stmt, base.getType()->getAsCXXRecordDecl(), bodyStmts);
637 }
638 }
639
640 if(body) {
641 bodyStmts.AddBodyStmts(body);
642 }
643
644 bodyStmts.AddBodyStmts(Return(mkVarDeclRefExpr(kwInternalThis, Ptr(ctorDecl->getType()))));
645
646 body = mkCompoundStmt({bodyStmts});
647 retType = parentType;
648
649 // copy and move assignment op
650 } else if(IsCopyOrMoveAssign(stmt)) {
651 if(not stmt->doesThisDeclarationHaveABody() or stmt->isDefaulted()) {
652
653 // we don't want the default generated body
654 bodyStmts.clear();
655
656 processBaseClassesAndFields(stmt->getParent());
657 } else if(body) {
658 bodyStmts.AddBodyStmts(body);
659 }
660
661 bodyStmts.AddBodyStmts(Return(mkVarDeclRefExpr(kwInternalThis, Ptr(stmt->getType()))));
662
663 body = mkCompoundStmt({bodyStmts});
664 retType = parentType;
665
666 } else if(const auto* dtor = dyn_cast_or_null<CXXDestructorDecl>(stmt)) {
667 // Based on: https://www.dre.vanderbilt.edu/~schmidt/PDF/C++-translation.pdf
668
669 if(not HasDtor(GetRecordDeclType(dtor->getParent()))) {
670 return;
671 }
672
673 InsertVtblPtr(stmt, stmt->getParent(), bodyStmts);
674
675 for(const auto& base : llvm::reverse(dtor->getParent()->bases())) {
676 if(not dtor->isVirtual()) {
677 continue;
678 }
679
680 InsertVtblPtr(stmt, dyn_cast_or_null<CXXRecordDecl>(base.getType()->getAsRecordDecl()), bodyStmts);
681 }
682
683 if(body) {
684 bodyStmts.AddBodyStmts(body);
685 }
686
687 for(const auto& base : llvm::reverse(dtor->getParent()->bases())) {
688 if(not dtor->isVirtual()) {
689 continue;
690 }
691
692 auto* lhsDeclRef = mkVarDeclRefExpr(kwInternalThis, Ptr(base.getType()));
693 auto* cast = Cast(lhsDeclRef, lhsDeclRef->getType());
694
695 bodyStmts.Add(
696 Call(GetSpecialMemberName(stmt, GetRecordDeclType(base.getType()->getAsRecordDecl())), {cast}));
697 }
698
699 body = mkCompoundStmt({bodyStmts});
700 }
701
702 params_store params{};
703 params.reserve(stmt->getNumParams() + 1);
704
705 if(not IsStaticStorageClass(stmt) and not stmt->isStatic()) {
706 params.emplace_back(kwInternalThis, parentType);
707 }
708
709 for(const auto& param : stmt->parameters()) {
710 std::string name{GetName(*param)};
711 auto type = param->getType();
712
713 // at least in case of a copy constructor modify the parameters
714 if((0 == name.length()) and
715 (IsCopyOrMoveCtor(dyn_cast_or_null<CXXConstructorDecl>(stmt)) or IsCopyOrMoveAssign(stmt))) {
716 name = "__rhs"sv;
717 type = Ptr(type.getNonReferenceType());
718 }
719
720 params.emplace_back(name, type);
721 }
722
723 auto* callSpecialMemberFn = Function(GetSpecialMemberName(stmt), retType, to_params_view(params));
724 callSpecialMemberFn->setInlineSpecified(stmt->isInlined());
725 callSpecialMemberFn->setStorageClass((stmt->isStatic() or IsStaticStorageClass(stmt)) ? SC_Static : SC_None);
726 callSpecialMemberFn->setBody(body);
727
728 InsertArg(callSpecialMemberFn);
729
731}
732//-----------------------------------------------------------------------------
733
734void CfrontCodeGenerator::FormatCast(const std::string_view,
735 const QualType& castDestType,
736 const Expr* subExpr,
737 const CastKind& kind)
738{
739 // C does not have a rvalue notation and we already transformed the temporary into an object. Skip the cast to &&.
740 // Ignore CK_UncheckedDerivedToBase which would lead to (A)c where neither A nor c is a pointer.
741 if(not castDestType->isRValueReferenceType() and not(CastKind::CK_UncheckedDerivedToBase == kind)) {
742 mOutputFormatHelper.Append("(", GetName(castDestType), ")");
743
744 // ARM p 221:
745 // C* pc = new C;
746 // B* pb = pc -> pc = (B*) ((char*)pc+delta(B))
747 if(is{kind}.any_of(CastKind::CK_DerivedToBase, CastKind::CK_BaseToDerived)) {
748 // We have to switch in case of a base to derived cast
749 auto [key,
750 sign] = [&]() -> std::pair<std::pair<const CXXRecordDecl*, const CXXRecordDecl*>, std::string_view> {
751 auto plainType = [](QualType t) {
752 if(const auto* pt = dyn_cast_or_null<PointerType>(t.getTypePtrOrNull())) {
753 return pt->getPointeeType()->getAsCXXRecordDecl();
754 }
755
756 return t->getAsCXXRecordDecl();
757 };
758
759 auto base = plainType(castDestType);
760 auto derived = plainType(subExpr->getType());
761
762 if((CastKind::CK_BaseToDerived == kind)) {
763 return {{base, derived}, "-"sv};
764 }
765
766 return {{derived, base}, "+"sv};
767 }();
768
769 if(auto off = mThisPointerOffset[key]) {
770 mOutputFormatHelper.Append("((char*)"sv);
771 InsertArg(subExpr);
772 mOutputFormatHelper.Append(sign, off, ")"sv);
773
774 return;
775 }
776 }
777 }
778
779 InsertArg(subExpr);
780}
781//-----------------------------------------------------------------------------
782
789//-----------------------------------------------------------------------------
790
791void CfrontCodeGenerator::InsertArg(const StaticAssertDecl* stmt)
792{
794
795 mOutputFormatHelper.Append("_Static_assert"sv);
796
797 WrapInParens([&] {
798 InsertArg(stmt->getAssertExpr());
799
800 if(stmt->getMessage()) {
802 InsertArg(stmt->getMessage());
803 }
804 });
805
807}
808//-----------------------------------------------------------------------------
809
810void CfrontCodeGenerator::InsertArg(const TypedefDecl* stmt)
811{
812 mOutputFormatHelper.AppendSemiNewLine(kwTypedefSpace, GetName(stmt->getUnderlyingType()), " "sv, GetName(*stmt));
814}
815//-----------------------------------------------------------------------------
816
817static void ProcessFields(CXXRecordDecl* recordDecl, const CXXRecordDecl* rd)
818{
819 RETURN_IF(not rd->hasDefinition())
820
821 auto AddField = [&](const FieldDecl* field) {
822 recordDecl->addDecl(mkFieldDecl(recordDecl, GetName(*field), field->getType()));
823 };
824
825 // Insert field from base classes
826 for(const auto& base : rd->bases()) {
827 // XXX: ignoring TemplateSpecializationType
828 if(const auto* rdBase = dyn_cast_or_null<CXXRecordDecl>(base.getType().getCanonicalType()->getAsRecordDecl())) {
829 ProcessFields(recordDecl, rdBase);
830 }
831 }
832
833 // insert vtable pointer if required
834 if(rd->isPolymorphic() and (rd->getNumBases() == 0)) {
835 recordDecl->addDecl(CfrontCodeGenerator::VtableData().VtblPtrField(rd));
836 }
837
838 // insert own fields
839 for(const auto* d : rd->fields()) {
840 AddField(d);
841 }
842
843 if(recordDecl->field_empty()) {
844 AddField(mkFieldDecl(recordDecl, "__dummy"sv, GetGlobalAST().CharTy));
845 }
846}
847//-----------------------------------------------------------------------------
848
849static std::string GetFirstPolymorphicBaseName(const RecordDecl* decl, const RecordDecl* to)
850{
851 std::string ret{GetName(*decl)};
852
853 if(const auto* rdecl = dyn_cast_or_null<CXXRecordDecl>(decl); rdecl->getNumBases() > 1) {
854 for(const auto& base : rdecl->bases()) {
855 if(const auto* rd = base.getType()->getAsRecordDecl(); rd == to) {
856 ret += GetFirstPolymorphicBaseName(rd, to);
857 break;
858 }
859 }
860 }
861
862 return ret;
863}
864//-----------------------------------------------------------------------------
865
866///! Find the first polymorphic base class.
867static const CXXRecordDecl* GetFirstPolymorphicBase(const RecordDecl* decl)
868{
869 if(const auto* rdecl = dyn_cast_or_null<CXXRecordDecl>(decl); rdecl->getNumBases() >= 1) {
870 for(const auto& base : rdecl->bases()) {
871 const auto* rd = base.getType()->getAsRecordDecl();
872
873 if(const auto* cxxRd = dyn_cast_or_null<CXXRecordDecl>(rd); not cxxRd or not cxxRd->isPolymorphic()) {
874 continue;
875 } else if(const CXXRecordDecl* ret = GetFirstPolymorphicBase(rd)) {
876 return ret;
877 }
878
879 break;
880 }
881 }
882
883 return dyn_cast_or_null<CXXRecordDecl>(decl);
884}
885//-----------------------------------------------------------------------------
886
887void CfrontCodeGenerator::InsertArg(const CXXRecordDecl* stmt)
888{
889 auto* recordDecl = Struct(GetName(*stmt));
890
891 if(stmt->hasDefinition() and stmt->isPolymorphic()) {
892 if(auto* itctx =
893 static_cast<ItaniumVTableContext*>(const_cast<ASTContext&>(GetGlobalAST()).getVTableContext())) {
894#if 0
895 // Get mangled RTTI name
896 auto* mc = const_cast<ASTContext&>(GetGlobalAST()).createMangleContext(nullptr);
897 SmallString<256> rttiName{};
898 llvm::raw_svector_ostream out(rttiName);
899 mc->mangleCXXRTTI(QualType(stmt->getTypeForDecl(), 0), out);
900 DPrint("name: %s\n", rttiName.c_str());
901#endif
902
903 SmallVector<Expr*, 16> mInitExprs{};
904 SmallVector<QualType, 5> baseList{};
905
906 if(stmt->getNumBases() == 0) {
907 baseList.push_back(GetRecordDeclType(stmt));
908 }
909
910 for(const auto& base : stmt->bases()) {
911 baseList.push_back(base.getType());
912 }
913
914 llvm::DenseMap<uint64_t, ThunkInfo> thunkMap{};
915 const VTableLayout& layout{itctx->getVTableLayout(stmt)};
916
917 for(const auto& [idx, thunk] : layout.vtable_thunks()) {
918 thunkMap[idx] = thunk;
919 }
920
921 unsigned clsIdx{};
922 unsigned funIdx{};
923 auto& vtblData = VtableData();
924
925 auto pushVtable = [&] {
926 if(funIdx) {
928
929 // struct __mptr __vtbl__A[] = {0, 0, 0, 0, 0, (__vptp)FunA, 0, 0, 0};
930 auto* thisRd = baseList[clsIdx - 1]->getAsCXXRecordDecl();
931 auto vtableName{StrCat("__vtbl_"sv, GetFirstPolymorphicBaseName(stmt, thisRd))};
932 auto* vtabl = Variable(vtableName, ContantArrayTy(vtblData.vtableRecordType, funIdx));
933 vtabl->setInit(InitList(mInitExprs, vtblData.vtableRecordType));
934
935 PushVtableEntry(stmt, thisRd, vtabl);
936
937 funIdx = 0;
938 }
939
940 mInitExprs.clear();
941 };
942
943 for(unsigned i = 0; const auto& vc : layout.vtable_components()) {
944 switch(vc.getKind()) {
945 case VTableComponent::CK_OffsetToTop: {
946 auto off = layout.getVTableOffset(clsIdx);
947 if(auto rem = (off % 4)) {
948 off += 4 - rem; // sometimes the value is misaligned. Align to 4 bytes
949 }
950
951 mThisPointerOffset[{stmt, baseList[clsIdx]->getAsCXXRecordDecl()}] = off * 4; // we need bytes
952
953 if(clsIdx >= 1) {
954 pushVtable();
955 }
956 ++clsIdx;
957 } break;
958
959 case VTableComponent::CK_RTTI:
960 break;
961
962 // Source: https://itanium-cxx-abi.github.io/cxx-abi/abi.html#vtable-components
963 // The entries for virtual destructors are actually pairs of entries. The first destructor,
964 // called the complete object destructor, performs the destruction without calling delete() on
965 // the object. The second destructor, called the deleting destructor, calls delete() after
966 // destroying the object.
967 case VTableComponent::CK_CompleteDtorPointer:
968 break; // vc.getKind() == VTableComponent::CK_CompleteDtorPointer
969 case VTableComponent::CK_DeletingDtorPointer:
970 case VTableComponent::CK_FunctionPointer: {
971 auto* thunkOffset = [&] {
972 if(ThunkInfo thunk = thunkMap.lookup(i); not thunk.isEmpty() and not thunk.This.isEmpty()) {
973 return Int32(thunk.This.NonVirtual);
974 }
975
976 return Int32(0);
977 }();
978
979 const auto* md = dyn_cast_or_null<FunctionDecl>(vc.getFunctionDecl());
980
981 std::string name{};
982 if(md->isPureVirtual()) {
985
986 md = Function("__cxa_pure_virtual"sv, VoidTy(), params_vector{{kwInternalThis, VoidTy()}});
987
988 name = GetName(*md);
989 } else {
990 name = GetSpecialMemberName(md);
991 }
992
993 auto* reicast = ReinterpretCast(vtblData.vptpTypedef, mkVarDeclRefExpr(name, md->getType()));
994
995 mInitExprs.push_back(InitList({thunkOffset, Int32(0), reicast}, vtblData.vtableRecordType));
996
997 mVirtualFunctions[{md, {stmt, GetFirstPolymorphicBase(stmt)}}] = funIdx;
998
999 ++funIdx;
1000 break;
1001 }
1002 default: break;
1003 }
1004
1005 ++i;
1006 }
1007
1008 pushVtable();
1009 }
1010 }
1011
1012 if(stmt->hasDefinition()) {
1013 ProcessFields(recordDecl, stmt);
1014 recordDecl->completeDefinition();
1015
1017 }
1018
1019 // use our freshly created recordDecl
1020 CodeGenerator::InsertArg(recordDecl);
1021
1022#if 0
1023 // TypedefDecl above is not called
1024 auto& ctx = GetGlobalAST();
1025 auto et = ctx.getElaboratedType(ElaboratedTypeKeyword::ETK_Struct, nullptr, GetRecordDeclType(recordDecl), nullptr);
1026 auto* typedefDecl = Typedef(GetName(*stmt),et);
1027 CodeGenerator::InsertArg(typedefDecl);
1028#endif
1029
1030 // insert member functions except for the special member functions and classes defined inside this class
1031 for(OnceTrue firstRecordDecl{}; const auto* d : stmt->decls()) {
1032 if((isa<CXXRecordDecl>(d) and firstRecordDecl) // skip the first record decl which are ourselves
1033 or (stmt->isLambda() and isa<CXXDestructorDecl>(d)) // skip dtor for lambdas
1034 or isa<FieldDecl>(d) // skip fields
1035 or isa<AccessSpecDecl>(d) // skip access specifiers
1036 ) {
1037 continue;
1038 }
1039
1040 // According to "Inside the C++ Object Model" a trivial and literal type has no ctor/dtor.
1041 if((stmt->isTrivial() and isa<CXXConstructorDecl>(d)) or
1042 (stmt->hasTrivialDestructor() and isa<CXXDestructorDecl>(d))) {
1043 continue;
1044 }
1045
1046 InsertArg(d);
1047 }
1048}
1049//-----------------------------------------------------------------------------
1050
1051void CfrontCodeGenerator::InsertArg(const CXXMemberCallExpr* stmt)
1052{
1053 if(const auto* me = dyn_cast_or_null<MemberExpr>(stmt->getCallee())) {
1054 auto* obj = me->getBase();
1055 const bool isPointer{obj->getType()->isPointerType()};
1056
1057 if(const bool isReference = IsReferenceType(dyn_cast_or_null<VarDecl>(obj->getReferencedDeclOfCallee()));
1058 not isPointer and not isReference) {
1059 obj = Ref(obj);
1060 }
1061
1062 if(const auto* matExpr = dyn_cast_or_null<MaterializeTemporaryExpr>(me->getBase())) {
1063 if(const auto* tmpExpr = dyn_cast_or_null<CXXBindTemporaryExpr>(matExpr->getSubExpr())) {
1064 if(const auto* tmpObjExpr = dyn_cast_or_null<CXXTemporaryObjectExpr>(tmpExpr->getSubExpr())) {
1065 obj = const_cast<CXXTemporaryObjectExpr*>(tmpObjExpr);
1066 }
1067 }
1068 }
1069
1070 auto* memDecl = me->getMemberDecl();
1071
1072 if(const auto* ar = dyn_cast_or_null<ConstantArrayType>(obj->getType())) {
1073 if(const auto* dtor = dyn_cast_or_null<CXXDestructorDecl>(memDecl)) {
1074 // ignore the reference
1075 InsertArg(CallVecDtor(dyn_cast_or_null<UnaryOperator>(obj)->getSubExpr(), ar));
1076 return;
1077 }
1078 }
1079
1080 SmallVector<Expr*, 16> params{obj};
1081 auto* ncStmt = const_cast<CXXMemberCallExpr*>(stmt);
1082 params.append(ncStmt->arg_begin(), ncStmt->arg_end());
1083
1084 if(auto* md = dyn_cast_or_null<CXXMethodDecl>(memDecl); md and md->isVirtual()) {
1085 auto& vtblData = VtableData();
1086 auto* cls = md->getParent();
1087 auto vRecordDecl = GetFirstPolymorphicBase(cls);
1088 auto* vtblField = VtableData().VtblPtrField(vRecordDecl);
1089
1090 // -- cast to function signature: void Fun(struct X*)
1091
1092 auto destType = not isPointer ? Ptr(obj->getType()) : obj->getType();
1093 auto atype = isPointer ? obj->getType()->getPointeeType() : obj->getType();
1094 auto idx = mVirtualFunctions[{md, {atype->getAsCXXRecordDecl(), vRecordDecl}}];
1095
1096 // a->__vptr[1]; #1
1097 auto* accessVptr = AccessMember(Paren(obj), vtblField, true);
1098 auto* vtblArrayPos = ArraySubscript(accessVptr, idx, vtblField->getType());
1099
1100 auto* p = Paren(vtblArrayPos); // ( #1 ) #2
1101 auto* accessMemberF = AccessMember(p, vtblData.f, false); // #2.f #3
1102
1103 // (void (*)(struct X*) (#3)
1104 params_vector ps{{kwInternalThis, destType}};
1105 auto* funcPtrFuncDecl = Function("__dummy"sv, VoidTy(), ps);
1106 auto* reicast = ReinterpretCast(funcPtrFuncDecl->getType(), accessMemberF, true);
1107
1108 auto* p4 = Paren(reicast); // (#4)
1109 auto p5 = Dref(p4); // *#5
1110 auto* p6 = Paren(p5); // (#5) #6
1111
1112 // -- call with possible this pointer adjustment
1113
1114 auto* p7 = AccessMember(p, vtblData.d, false); // a->__vptr[1]; #7
1115 auto* p8 = ReinterpretCast(GetGlobalAST().CharTy, Paren(obj), true); // (#7) #8
1116
1117 auto* p9 = ReinterpretCast(destType, p8);
1118
1119 auto* p10 = Paren(p9);
1120 auto* p11 = Plus(p10, p7); // #7 + #8 #9
1121 auto* p12 = Paren(p11);
1122
1123 // Use the modified object parameter
1124 params[0] = p12;
1125 InsertArg(CallExpr::Create(GetGlobalAST(), p6, params, p6->getType(), VK_LValue, {}, {}));
1126
1127 } else {
1128 InsertArg(Call(GetSpecialMemberName(memDecl), params));
1129 }
1130
1131 } else {
1133 }
1134}
1135//-----------------------------------------------------------------------------
1136
1137void CfrontCodeGenerator::InsertArg(const FunctionDecl* stmt)
1138{
1139 if(not stmt->isMain()) {
1141 return;
1142 }
1143
1144 params_store params{};
1145 SmallVector<Expr*, 16> args{};
1146
1147 for(auto* param : stmt->parameters()) {
1148 params.emplace_back(GetName(*param), param->getType());
1149 args.push_back(mkDeclRefExpr(param));
1150 }
1151
1152 auto mainName{"main"sv};
1153 auto trampolinMainName{BuildInternalVarName(mainName)};
1154
1155 auto* intMain = Function(trampolinMainName, stmt->getReturnType(), to_params_view(params));
1156 intMain->setBody(stmt->getBody());
1157 intMain->setHasImplicitReturnZero(true);
1158
1159 InsertArg(intMain);
1161
1162 auto* mainRetVar = Variable("ret"sv, stmt->getReturnType());
1163 mainRetVar->setInit(Call(trampolinMainName, args));
1164
1165 auto* mainRetVarDeclStmt = mkDeclStmt(mainRetVar);
1166
1167 StmtsContainer bodyStmts{Call(cxaStart, {}), mainRetVarDeclStmt, Call(cxaAtExit, {}), Return(mainRetVar)};
1168
1169 auto* body = mkCompoundStmt({bodyStmts});
1170 auto* modMain = Function(mainName, stmt->getReturnType(), to_params_view(params));
1171 modMain->setBody(body);
1172
1173 CodeGenerator::InsertArg(modMain);
1174}
1175//-----------------------------------------------------------------------------
1176
1177void CfrontCodeGenerator::InsertArg(const CXXConstructExpr* stmt)
1178{
1179 if(P0315Visitor dt{*this}; not dt.TraverseType(stmt->getType())) {
1180 if(not mLambdaStack.empty()) {
1181 for(const auto& e : mLambdaStack) {
1182 RETURN_IF(LambdaCallerType::VarDecl == e.callerType());
1183 }
1184 }
1185 }
1186
1187 auto ctor = stmt->getConstructor();
1188 auto ctorName = GetSpecialMemberName(ctor);
1189 auto* vd = dyn_cast_or_null<VarDecl>(mLastDecl);
1190
1191#if 0
1192 // XXX: An expression like C c[4]{4,5,6} with C having a ctor does show up wrong at the moment.
1193 if(not ar) {
1194 ar = dyn_cast_or_null<ConstantArrayType>(vd->getType());
1195
1196 if(ar) {
1197 mLastStmt->dump();
1198 openScope = true;
1199 // mOutputFormatHelper.CloseScopeWithSemi();
1201 }
1202 }
1203#endif
1204
1205 auto InsertCallCtor = [&](Expr* varNameRef) {
1206 SmallVector<Expr*, 16> args{Cast(varNameRef, Ptr(stmt->getType()))};
1207
1208 for(int i = 0; auto* arg : stmt->arguments()) {
1209 if(IsCopyOrMoveCtor(ctor) or ctor->getParamDecl(i)->getType()->isReferenceType()) {
1210 args.push_back(Ref(arg));
1211
1212 } else {
1213 args.push_back(const_cast<Expr*>(arg));
1214 }
1215
1216 ++i;
1217 }
1218
1219 InsertArg(Call(ctorName, args));
1220 };
1221
1222 // For an array we need to call __vec_new
1223 if(const auto* ar = dyn_cast_or_null<ConstantArrayType>(stmt->getType())) {
1224 if(not HasCtor(ar->getElementType())) {
1225 mInsertSemi = false;
1226 return;
1227 }
1228
1229 InsertArg(CallVecCtor(ctorName, vd, ar->getElementType(), Int32(GetSize(ar))));
1230
1231 } else if(const auto* tmpObjectExpr = dyn_cast_or_null<CXXTemporaryObjectExpr>(stmt); vd and not tmpObjectExpr) {
1232 if(not HasCtor(vd->getType())) {
1233 mInsertSemi = false;
1234 } else {
1235 auto* varNameRef = Ref(mkDeclRefExpr(vd));
1236
1237 InsertCallCtor(varNameRef);
1238 }
1239
1240 } else if(tmpObjectExpr) {
1241 auto* varNameRef = Ref(mkVarDeclRefExpr(GetName(*tmpObjectExpr), stmt->getType()));
1242
1243 if(not HasCtor(stmt->getType())) {
1244 InsertArg(varNameRef);
1245 return;
1246 }
1247
1248 InsertCallCtor(varNameRef);
1249
1250 } else {
1252 stmt->getType(), Ptr(GetRecordDeclType(ctor)), nullptr, ArgsToExprVector(stmt), DoCast::Yes));
1253 }
1254}
1255//-----------------------------------------------------------------------------
1256
1257} // namespace clang::insights
const InsightsOptions & GetInsightsOptions()
Get the global C++ Insights options.
Definition Insights.cpp:37
const ASTContext & GetGlobalAST()
Get access to the ASTContext.
Definition Insights.cpp:71
constexpr std::string_view kwNull
constexpr std::string_view cxaStart
constexpr std::string_view kwInternalThis
constexpr std::string_view kwTypedefSpace
constexpr std::string_view cxaAtExit
#define RETURN_IF(cond)
! A helper inspired by https://github.com/Microsoft/wil/wiki/Error-handling-helpers
constexpr bool empty() const noexcept
Definition StackList.h:69
A special generator for coroutines. It is only activated, if -show-coroutines-transformation is given...
void InsertArg(const CXXThisExpr *) override
void InsertCXXMethodDecl(const CXXMethodDecl *, CodeGenerator::SkipBody) override
void FormatCast(const std::string_view, const QualType &, const Expr *, const CastKind &) override
void WrapInParens(void_func_ref lambda, const AddSpaceAtTheEnd addSpaceAtTheEnd=AddSpaceAtTheEnd::No)
virtual void InsertArg(const Decl *stmt)
OutputFormatHelper & mOutputFormatHelper
void AppendNewLine(const char c)
Same as Append but adds a newline after the last argument.
void Append(const char c)
Append a single character.
void SetIndent(const unsigned indent, const SkipIndenting skipIndenting=SkipIndenting::No)
Set the indent level of this class to indent.
void AppendSemiNewLine()
Append a semicolon and a newline.
! Find a LambdaExpr inside a Decltype
DeclStmt * mkDeclStmt(Dcls... dcls)
Definition ASTHelpers.h:91
BinaryOperator * Plus(Expr *var, Expr *assignExpr)
CXXReinterpretCastExpr * ReinterpretCast(QualType toType, const Expr *toExpr, bool makePointer)
CXXRecordDecl * Struct(std::string_view name)
FieldDecl * mkFieldDecl(DeclContext *dc, std::string_view name, QualType type)
params_vector to_params_view(params_store &params)
DeclRefExpr * mkDeclRefExpr(const ValueDecl *vd)
QualType Typedef(std::string_view name, QualType underlayingType)
std::vector< std::pair< std::string_view, QualType > > params_vector
Definition ASTHelpers.h:27
CallExpr * Call(const FunctionDecl *fd, ArrayRef< Expr * > params)
UnaryOperator * Ref(const Expr *e)
VarDecl * Variable(std::string_view name, QualType type, DeclContext *dc)
MemberExpr * AccessMember(const Expr *expr, const ValueDecl *vd, bool isArrow)
DeclRefExpr * mkVarDeclRefExpr(std::string_view name, QualType type)
static CallExpr * CallConstructor(QualType ctorType, DeclRefExpr *lhsDeclRef, Expr *lhsMemberExpr, ArrayRef< Expr * > callParams, DoCast doCast, AsReference asReference)
SmallVector< Expr *, 5 > ArgsToExprVector(const Expr *expr)
ArraySubscriptExpr * ArraySubscript(const Expr *lhs, uint64_t index, QualType type)
ReturnStmt * Return(Expr *stmt)
CXXStaticCastExpr * Cast(const Expr *toExpr, QualType toType)
CXXStaticCastExpr * CastToVoidFunPtr(std::string_view name)
Stmt * Comment(std::string_view comment)
ParenExpr * Paren(Expr *expr)
IfStmt * If(const Expr *condition, ArrayRef< Stmt * > bodyStmts)
BinaryOperator * Mul(Expr *lhs, Expr *rhs)
InitListExpr * InitList(ArrayRef< Expr * > initExprs, QualType t)
UnaryExprOrTypeTraitExpr * Sizeof(QualType toType)
QualType GetRecordDeclType(const CXXMethodDecl *md)
std::vector< std::pair< std::string, QualType > > params_store
Definition ASTHelpers.h:28
FunctionDecl * Function(std::string_view name, QualType returnType, const params_vector &parameters)
CompoundStmt * mkCompoundStmt(ArrayRef< Stmt * > bodyStmts, SourceLocation beginLoc, SourceLocation endLoc)
IntegerLiteral * Int32(uint64_t value)
QualType ContantArrayTy(QualType t, int size)
UnaryOperator * Dref(const Expr *stmt)
QualType Ptr(QualType srcType)
CXXStaticCastExpr * StaticCast(QualType toType, const Expr *toExpr, bool makePointer)
BinaryOperator * Assign(const VarDecl *var, Expr *assignExpr)
static auto * CallVecDelete(Expr *objectParam, QualType allocatedType)
uint64_t GetSize(const ConstantArrayType *arrayType)
@ HeaderStdlib
Track whether we need to insert <stdlib.h> in Cfront mode.
@ HeaderAssert
Track whether we need to insert <assert.h> in Cfront mode.
@ HeaderStddef
Track whether we need to insert <stddef.h> in Cfront mode.
void PushVtableEntry(const CXXRecordDecl *record, const CXXRecordDecl *recordB, VarDecl *decl)
int GetGlobalVtablePos(const CXXRecordDecl *record, const CXXRecordDecl *recordB)
static llvm::DenseMap< std::pair< const CXXRecordDecl *, const CXXRecordDecl * >, int > mThisPointerOffset
Store the this pointer offset from derived to base class.
std::string GetName(const NamedDecl &nd, const QualifiedName qualifiedName)
static void ProcessFields(CXXRecordDecl *recordDecl, const CXXRecordDecl *rd)
void DPrint(const char *fmt, const auto &... args)
Debug print which is disabled in release-mode.
Definition DPrint.h:71
std::string BuildInternalVarName(const std::string_view &varName)
static bool IsCopyOrMoveAssign(const CXXMethodDecl *stmt)
static bool HasDtor(QualType t)
static const CXXRecordDecl * GetFirstPolymorphicBase(const RecordDecl *decl)
! Find the first polymorphic base class.
static bool HasCtor(QualType t)
static void InsertVtblPtr(const CXXMethodDecl *stmt, const CXXRecordDecl *cur, StmtsContainer &bodyStmts)
static auto * CallVecDtor(Expr *objectParam, const ConstantArrayType *ar)
bool IsReferenceType(const ValueDecl *decl)
static auto * CallVecNewOrCtor(std::string_view ctorName, Expr *objectParam, QualType allocatedType, Expr *arraySizeExpr, std::string_view funName)
static std::string GetSpecialMemberName(const ValueDecl *vd, QualType type)
static auto * CallVecCtor(std::string_view ctorName, const VarDecl *objectParam, QualType allocatedType, Expr *arraySizeExpr)
static bool IsCopyOrMoveCtor(const CXXConstructorDecl *ctor)
bool IsStaticStorageClass(const CXXMethodDecl *md)
static std::string GetFirstPolymorphicBaseName(const RecordDecl *decl, const RecordDecl *to)
static auto * CallVecNew(std::string_view ctorName, Expr *objectParam, QualType allocatedType, Expr *arraySizeExpr)
static auto * CallVecDeleteOrDtor(Expr *objectParam, QualType allocatedType, std::string_view name, uint64_t size)
void EnableGlobalInsert(GlobalInserts idx)
Definition Insights.cpp:96
static FieldDecl * AddField(CoroutineASTData &astData, std::string_view name, QualType type)
std::string StrCat(const auto &... args)
FieldDecl * VtblPtrField(const CXXRecordDecl *parent)
! A helper type to have a container for ArrayRef
Definition ASTHelpers.h:64
Handy helper to avoid longish comparisons.
constexpr bool any_of(const auto &... ts) const