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