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 
24 namespace clang::insights {
25 
26 using namespace asthelpers;
27 //-----------------------------------------------------------------------------
28 
29 //! Store the `this` pointer offset from derived to base class.
30 static llvm::DenseMap<std::pair<const CXXRecordDecl*, const CXXRecordDecl*>, int> mThisPointerOffset{};
31 //-----------------------------------------------------------------------------
32 
33 static 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 
67 FieldDecl* CfrontCodeGenerator::CfrontVtableData::VtblPtrField(const CXXRecordDecl* parent)
68 {
69  return mkFieldDecl(const_cast<CXXRecordDecl*>(parent), StrCat("__vptr"sv, GetName(*parent)), Ptr(vtableRecordType));
70 }
71 //-----------------------------------------------------------------------------
72 
74 {
75  static CfrontVtableData data{};
76 
77  return data;
78 }
79 //-----------------------------------------------------------------------------
80 
81 CodeGeneratorVariant::CodeGenerators::CodeGenerators(OutputFormatHelper& _outputFormatHelper,
82  CodeGenerator::LambdaStackType& lambdaStack,
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 
95 CodeGeneratorVariant::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 
106 CodeGeneratorVariant::CodeGenerators::~CodeGenerators()
107 {
108  if(GetInsightsOptions().UseShow2C) {
109  cfcg.~CfrontCodeGenerator();
110  } else {
111  cg.~CodeGenerator();
112  }
113 }
114 //-----------------------------------------------------------------------------
115 
116 void CodeGeneratorVariant::Set()
117 {
118  if(GetInsightsOptions().UseShow2C) {
119  cg = &cgs.cfcg;
120  } else {
121  cg = &cgs.cg;
122  }
123 }
124 //-----------------------------------------------------------------------------
125 
126 static bool IsCopyOrMoveCtor(const CXXConstructorDecl* ctor)
127 {
128  return ctor and (ctor->isCopyConstructor() or ctor->isMoveConstructor());
129 }
130 //-----------------------------------------------------------------------------
131 
132 static bool IsCopyOrMoveAssign(const CXXMethodDecl* stmt)
133 {
134  return stmt and (stmt->isCopyAssignmentOperator() or stmt->isMoveAssignmentOperator());
135 }
136 //-----------------------------------------------------------------------------
137 
138 static 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 
166 std::string GetSpecialMemberName(const ValueDecl* vd)
167 {
168  if(const auto* md = dyn_cast_or_null<CXXMethodDecl>(vd)) {
169  return GetSpecialMemberName(vd, GetRecordDeclType(md));
170  }
171 
172  return {};
173 }
174 //-----------------------------------------------------------------------------
175 
176 void CfrontCodeGenerator::InsertArg(const CXXThisExpr*)
177 {
179 }
180 //-----------------------------------------------------------------------------
181 
182 static 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 
192 static 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 
202 static 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 
215 static auto* CallVecDelete(Expr* objectParam, QualType allocatedType)
216 {
218 
219  return CallVecDeleteOrDtor(objectParam, allocatedType, "__cxa_vec_delete"sv, 0);
220 }
221 //-----------------------------------------------------------------------------
222 
223 static auto* CallVecDtor(Expr* objectParam, const ConstantArrayType* ar)
224 {
226 
227  return CallVecDeleteOrDtor(objectParam, ar->getElementType(), "__cxa_vec_dtor"sv, GetSize(ar));
228 }
229 //-----------------------------------------------------------------------------
230 
231 void 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 
253 static 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 
281 static 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 
289 static auto*
290 CallVecCtor(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 
298 void 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 
422 void 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 
441 static 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_[]
448  auto* vtablAr = CfrontCodeGenerator::VtableData().VtblArrayVar(1);
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 
462 void CfrontCodeGenerator::InsertCXXMethodDecl(const CXXMethodDecl* stmt, SkipBody)
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(),
551  Ptr(GetRecordDeclType(rd)),
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 
631  if(body) {
632  bodyStmts.AddBodyStmts(body);
633  }
634 
635  bodyStmts.AddBodyStmts(Return(mkVarDeclRefExpr(kwInternalThis, Ptr(ctorDecl->getType()))));
636 
637  body = mkCompoundStmt({bodyStmts});
638  retType = parentType;
639 
640  // copy and move assignment op
641  } else if(IsCopyOrMoveAssign(stmt)) {
642  if(not stmt->doesThisDeclarationHaveABody() or stmt->isDefaulted()) {
643 
644  // we don't want the default generated body
645  bodyStmts.clear();
646 
647  processBaseClassesAndFields(stmt->getParent());
648  } else if(body) {
649  bodyStmts.AddBodyStmts(body);
650  }
651 
652  bodyStmts.AddBodyStmts(Return(mkVarDeclRefExpr(kwInternalThis, Ptr(stmt->getType()))));
653 
654  body = mkCompoundStmt({bodyStmts});
655  retType = parentType;
656 
657  } else if(const auto* dtor = dyn_cast_or_null<CXXDestructorDecl>(stmt)) {
658  // Based on: https://www.dre.vanderbilt.edu/~schmidt/PDF/C++-translation.pdf
659 
660  if(body) {
661  bodyStmts.AddBodyStmts(body);
662  }
663 
664  if(not HasDtor(GetRecordDeclType(dtor->getParent()))) {
665  return;
666  }
667 
668  for(const auto& base : llvm::reverse(dtor->getParent()->bases())) {
669  if(not dtor->isVirtual()) {
670  continue;
671  }
672 
673  auto* lhsDeclRef = mkVarDeclRefExpr(kwInternalThis, Ptr(base.getType()));
674  auto* cast = Cast(lhsDeclRef, lhsDeclRef->getType());
675 
676  bodyStmts.Add(
677  Call(GetSpecialMemberName(stmt, GetRecordDeclType(base.getType()->getAsRecordDecl())), {cast}));
678 
679  body = mkCompoundStmt({bodyStmts});
680  }
681  }
682 
683  params_store params{};
684  params.reserve(stmt->getNumParams() + 1);
685 
686  if(not IsStaticStorageClass(stmt) and not stmt->isStatic()) {
687  params.emplace_back(kwInternalThis, parentType);
688  }
689 
690  for(const auto& param : stmt->parameters()) {
691  std::string name{GetName(*param)};
692  auto type = param->getType();
693 
694  // at least in case of a copy constructor modify the parameters
695  if((0 == name.length()) and
696  (IsCopyOrMoveCtor(dyn_cast_or_null<CXXConstructorDecl>(stmt)) or IsCopyOrMoveAssign(stmt))) {
697  name = "__rhs"sv;
698  type = Ptr(type.getNonReferenceType());
699  }
700 
701  params.emplace_back(name, type);
702  }
703 
704  auto* callSpecialMemberFn = Function(GetSpecialMemberName(stmt), retType, to_params_view(params));
705  callSpecialMemberFn->setInlineSpecified(stmt->isInlined());
706  callSpecialMemberFn->setStorageClass((stmt->isStatic() or IsStaticStorageClass(stmt)) ? SC_Static : SC_None);
707  callSpecialMemberFn->setBody(body);
708 
709  InsertArg(callSpecialMemberFn);
710 
712 }
713 //-----------------------------------------------------------------------------
714 
715 void CfrontCodeGenerator::FormatCast(const std::string_view,
716  const QualType& castDestType,
717  const Expr* subExpr,
718  const CastKind& kind)
719 {
720  // C does not have a rvalue notation and we already transformed the temporary into an object. Skip the cast to &&.
721  // Ignore CK_UncheckedDerivedToBase which would lead to (A)c where neither A nor c is a pointer.
722  if(not castDestType->isRValueReferenceType() and not(CastKind::CK_UncheckedDerivedToBase == kind)) {
723  mOutputFormatHelper.Append("(", GetName(castDestType), ")");
724 
725  // ARM p 221:
726  // C* pc = new C;
727  // B* pb = pc -> pc = (B*) ((char*)pc+delta(B))
728  if(is{kind}.any_of(CastKind::CK_DerivedToBase, CastKind::CK_BaseToDerived)) {
729  // We have to switch in case of a base to derived cast
730  auto [key,
731  sign] = [&]() -> std::pair<std::pair<const CXXRecordDecl*, const CXXRecordDecl*>, std::string_view> {
732  auto plainType = [](QualType t) {
733  if(const auto* pt = dyn_cast_or_null<PointerType>(t.getTypePtrOrNull())) {
734  return pt->getPointeeType()->getAsCXXRecordDecl();
735  }
736 
737  return t->getAsCXXRecordDecl();
738  };
739 
740  auto base = plainType(castDestType);
741  auto derived = plainType(subExpr->getType());
742 
743  if((CastKind::CK_BaseToDerived == kind)) {
744  return {{base, derived}, "-"sv};
745  }
746 
747  return {{derived, base}, "+"sv};
748  }();
749 
750  if(auto off = mThisPointerOffset[key]) {
751  mOutputFormatHelper.Append("((char*)"sv);
752  InsertArg(subExpr);
753  mOutputFormatHelper.Append(sign, off, ")"sv);
754 
755  return;
756  }
757  }
758  }
759 
760  InsertArg(subExpr);
761 }
762 //-----------------------------------------------------------------------------
763 
764 void CfrontCodeGenerator::InsertArg(const CXXNullPtrLiteralExpr*)
765 {
767 
769 }
770 //-----------------------------------------------------------------------------
771 
772 void CfrontCodeGenerator::InsertArg(const StaticAssertDecl* stmt)
773 {
775 
776  mOutputFormatHelper.Append("_Static_assert"sv);
777 
778  WrapInParens([&] {
779  InsertArg(stmt->getAssertExpr());
780 
781  if(stmt->getMessage()) {
782  mOutputFormatHelper.Append(", "sv);
783  InsertArg(stmt->getMessage());
784  }
785  });
786 
788 }
789 //-----------------------------------------------------------------------------
790 
791 void CfrontCodeGenerator::InsertArg(const TypedefDecl* stmt)
792 {
793  mOutputFormatHelper.AppendSemiNewLine(kwTypedefSpace, GetName(stmt->getUnderlyingType()), " "sv, GetName(*stmt));
795 }
796 //-----------------------------------------------------------------------------
797 
798 static void ProcessFields(CXXRecordDecl* recordDecl, const CXXRecordDecl* rd)
799 {
800  RETURN_IF(not rd->hasDefinition())
801 
802  auto AddField = [&](const FieldDecl* field) {
803  recordDecl->addDecl(mkFieldDecl(recordDecl, GetName(*field), field->getType()));
804  };
805 
806  // Insert field from base classes
807  for(const auto& base : rd->bases()) {
808  // XXX: ignoring TemplateSpecializationType
809  if(const auto* rdBase = dyn_cast_or_null<CXXRecordDecl>(base.getType().getCanonicalType()->getAsRecordDecl())) {
810  ProcessFields(recordDecl, rdBase);
811  }
812  }
813 
814  // insert vtable pointer if required
815  if(rd->isPolymorphic() and (rd->getNumBases() == 0)) {
816  recordDecl->addDecl(CfrontCodeGenerator::VtableData().VtblPtrField(rd));
817  }
818 
819  // insert own fields
820  for(const auto* d : rd->fields()) {
821  AddField(d);
822  }
823 
824  if(recordDecl->field_empty()) {
825  AddField(mkFieldDecl(recordDecl, "__dummy"sv, GetGlobalAST().CharTy));
826  }
827 }
828 //-----------------------------------------------------------------------------
829 
830 static std::string GetFirstPolymorphicBaseName(const RecordDecl* decl, const RecordDecl* to)
831 {
832  std::string ret{GetName(*decl)};
833 
834  if(const auto* rdecl = dyn_cast_or_null<CXXRecordDecl>(decl); rdecl->getNumBases() > 1) {
835  for(const auto& base : rdecl->bases()) {
836  if(const auto* rd = base.getType()->getAsRecordDecl(); rd == to) {
837  ret += GetFirstPolymorphicBaseName(rd, to);
838  break;
839  }
840  }
841  }
842 
843  return ret;
844 }
845 //-----------------------------------------------------------------------------
846 
847 void CfrontCodeGenerator::InsertArg(const CXXRecordDecl* stmt)
848 {
849  auto* recordDecl = Struct(GetName(*stmt));
850 
851  if(stmt->hasDefinition() and stmt->isPolymorphic()) {
852  if(auto* itctx =
853  static_cast<ItaniumVTableContext*>(const_cast<ASTContext&>(GetGlobalAST()).getVTableContext())) {
854 #if 0
855  // Get mangled RTTI name
856  auto* mc = const_cast<ASTContext&>(GetGlobalAST()).createMangleContext(nullptr);
857  SmallString<256> rttiName{};
858  llvm::raw_svector_ostream out(rttiName);
859  mc->mangleCXXRTTI(QualType(stmt->getTypeForDecl(), 0), out);
860  DPrint("name: %s\n", rttiName.c_str());
861 #endif
862 
863  SmallVector<Expr*, 16> mInitExprs{};
864  SmallVector<QualType, 5> baseList{};
865 
866  if(stmt->getNumBases() == 0) {
867  baseList.push_back(GetRecordDeclType(stmt));
868  }
869 
870  for(const auto& base : stmt->bases()) {
871  baseList.push_back(base.getType());
872  }
873 
874  llvm::DenseMap<uint64_t, ThunkInfo> thunkMap{};
875  const VTableLayout& layout{itctx->getVTableLayout(stmt)};
876 
877  for(const auto& [idx, thunk] : layout.vtable_thunks()) {
878  thunkMap[idx] = thunk;
879  }
880 
881  unsigned clsIdx{};
882  unsigned funIdx{};
883  auto& vtblData = VtableData();
884 
885  auto pushVtable = [&] {
886  if(funIdx) {
888 
889  // struct __mptr __vtbl__A[] = {0, 0, 0, 0, 0, (__vptp)FunA, 0, 0, 0};
890  auto* thisRd = baseList[clsIdx - 1]->getAsCXXRecordDecl();
891  auto vtableName{StrCat("__vtbl_"sv, GetFirstPolymorphicBaseName(stmt, thisRd))};
892  auto* vtabl = Variable(vtableName, ContantArrayTy(vtblData.vtableRecordType, funIdx));
893  vtabl->setInit(InitList(mInitExprs, vtblData.vtableRecordType));
894 
895  PushVtableEntry(stmt, thisRd, vtabl);
896 
897  funIdx = 0;
898  }
899 
900  mInitExprs.clear();
901  };
902 
903  for(unsigned i = 0; const auto& vc : layout.vtable_components()) {
904  switch(vc.getKind()) {
905  case VTableComponent::CK_OffsetToTop: {
906  auto off = layout.getVTableOffset(clsIdx);
907  if(auto rem = (off % 4)) {
908  off += 4 - rem; // sometimes the value is misaligned. Align to 4 bytes
909  }
910 
911  mThisPointerOffset[{stmt, baseList[clsIdx]->getAsCXXRecordDecl()}] = off * 4; // we need bytes
912 
913  if(clsIdx >= 1) {
914  pushVtable();
915  }
916  ++clsIdx;
917  } break;
918 
919  case VTableComponent::CK_RTTI:
920  break;
921 
922  // Source: https://itanium-cxx-abi.github.io/cxx-abi/abi.html#vtable-components
923  // The entries for virtual destructors are actually pairs of entries. The first destructor,
924  // called the complete object destructor, performs the destruction without calling delete() on
925  // the object. The second destructor, called the deleting destructor, calls delete() after
926  // destroying the object.
927  case VTableComponent::CK_CompleteDtorPointer:
928  break; // vc.getKind() == VTableComponent::CK_CompleteDtorPointer
929  case VTableComponent::CK_DeletingDtorPointer:
930  case VTableComponent::CK_FunctionPointer: {
931  auto* thunkOffset = [&] {
932  if(ThunkInfo thunk = thunkMap.lookup(i); not thunk.isEmpty() and not thunk.This.isEmpty()) {
933  return Int32(thunk.This.NonVirtual);
934  }
935 
936  return Int32(0);
937  }();
938 
939  const auto* md = dyn_cast_or_null<FunctionDecl>(vc.getFunctionDecl());
940 
941  std::string name{};
942  if(md->isPureVirtual()) {
945 
946  md = Function("__cxa_pure_virtual"sv, VoidTy(), params_vector{{kwInternalThis, VoidTy()}});
947 
948  name = GetName(*md);
949  } else {
950  name = GetSpecialMemberName(md);
951  }
952 
953  auto* reicast = ReinterpretCast(vtblData.vptpTypedef, mkVarDeclRefExpr(name, md->getType()));
954 
955  mInitExprs.push_back(InitList({thunkOffset, Int32(0), reicast}, vtblData.vtableRecordType));
956 
957  ++funIdx;
958  break;
959  }
960  default: break;
961  }
962 
963  ++i;
964  }
965 
966  pushVtable();
967  }
968  }
969 
970  if(stmt->hasDefinition()) {
971  ProcessFields(recordDecl, stmt);
972  recordDecl->completeDefinition();
973 
975  }
976 
977  // use our freshly created recordDecl
978  CodeGenerator::InsertArg(recordDecl);
979 
980 #if 0
981  // TypedefDecl above is not called
982  auto& ctx = GetGlobalAST();
983  auto et = ctx.getElaboratedType(ElaboratedTypeKeyword::ETK_Struct, nullptr, GetRecordDeclType(recordDecl), nullptr);
984  auto* typedefDecl = Typedef(GetName(*stmt),et);
985  CodeGenerator::InsertArg(typedefDecl);
986 #endif
987 
988  // insert member functions except for the special member functions and classes defined inside this class
989  for(OnceTrue firstRecordDecl{}; const auto* d : stmt->decls()) {
990  if((isa<CXXRecordDecl>(d) and firstRecordDecl) // skip the first record decl which are ourselves
991  or (stmt->isLambda() and isa<CXXDestructorDecl>(d)) // skip dtor for lambdas
992  or isa<FieldDecl>(d) // skip fields
993  or isa<AccessSpecDecl>(d) // skip access specifiers
994  ) {
995  continue;
996  }
997 
998  // According to "Inside the C++ Object Model" a trivial and literal type has no ctor/dtor.
999  if((stmt->isTrivial() and isa<CXXConstructorDecl>(d)) or
1000  (stmt->hasTrivialDestructor() and isa<CXXDestructorDecl>(d))) {
1001  continue;
1002  }
1003 
1004  InsertArg(d);
1005  }
1006 }
1007 //-----------------------------------------------------------------------------
1008 
1009 ///! Find the first polymorphic base class.
1010 static const CXXRecordDecl* GetFirstPolymorphicBase(const RecordDecl* decl)
1011 {
1012  if(const auto* rdecl = dyn_cast_or_null<CXXRecordDecl>(decl); rdecl->getNumBases() >= 1) {
1013  for(const auto& base : rdecl->bases()) {
1014  const auto* rd = base.getType()->getAsRecordDecl();
1015 
1016  if(const auto* cxxRd = dyn_cast_or_null<CXXRecordDecl>(rd); not cxxRd or not cxxRd->isPolymorphic()) {
1017  continue;
1018  } else if(const CXXRecordDecl* ret = GetFirstPolymorphicBase(rd)) {
1019  return ret;
1020  }
1021 
1022  break;
1023  }
1024  }
1025 
1026  return dyn_cast_or_null<CXXRecordDecl>(decl);
1027 }
1028 //-----------------------------------------------------------------------------
1029 
1030 void CfrontCodeGenerator::InsertArg(const CXXMemberCallExpr* stmt)
1031 {
1032  if(const auto* me = dyn_cast_or_null<MemberExpr>(stmt->getCallee())) {
1033  auto* obj = me->getBase();
1034  const bool isPointer{obj->getType()->isPointerType()};
1035 
1036  if(const bool isReference = IsReferenceType(dyn_cast_or_null<VarDecl>(obj->getReferencedDeclOfCallee()));
1037  not isPointer and not isReference) {
1038  obj = Ref(obj);
1039  }
1040 
1041  if(const auto* matExpr = dyn_cast_or_null<MaterializeTemporaryExpr>(me->getBase())) {
1042  if(const auto* tmpExpr = dyn_cast_or_null<CXXBindTemporaryExpr>(matExpr->getSubExpr())) {
1043  if(const auto* tmpObjExpr = dyn_cast_or_null<CXXTemporaryObjectExpr>(tmpExpr->getSubExpr())) {
1044  obj = const_cast<CXXTemporaryObjectExpr*>(tmpObjExpr);
1045  }
1046  }
1047  }
1048 
1049  auto* memDecl = me->getMemberDecl();
1050 
1051  if(const auto* ar = dyn_cast_or_null<ConstantArrayType>(obj->getType())) {
1052  if(const auto* dtor = dyn_cast_or_null<CXXDestructorDecl>(memDecl)) {
1053  // ignore the reference
1054  InsertArg(CallVecDtor(dyn_cast_or_null<UnaryOperator>(obj)->getSubExpr(), ar));
1055  return;
1056  }
1057  }
1058 
1059  SmallVector<Expr*, 16> params{obj};
1060  auto* ncStmt = const_cast<CXXMemberCallExpr*>(stmt);
1061  params.append(ncStmt->arg_begin(), ncStmt->arg_end());
1062 
1063  if(auto* md = dyn_cast_or_null<CXXMethodDecl>(memDecl); md and md->isVirtual()) {
1064  auto& vtblData = VtableData();
1065  auto* cls = md->getParent();
1066  auto vRecordDecl = GetFirstPolymorphicBase(cls);
1067  auto* vtblField = VtableData().VtblPtrField(vRecordDecl);
1068 
1069  // -- cast to function signature: void Fun(struct X*)
1070 
1071  auto destType = not isPointer ? Ptr(obj->getType()) : obj->getType();
1072  auto atype = isPointer ? obj->getType()->getPointeeType() : obj->getType();
1073  auto idx = mVirtualFunctions[{md, {atype->getAsCXXRecordDecl(), vRecordDecl}}];
1074 
1075  // a->__vptr[1]; #1
1076  auto* accessVptr = AccessMember(Paren(obj), vtblField, true);
1077  auto* vtblArrayPos = ArraySubscript(accessVptr, idx, vtblField->getType());
1078 
1079  auto* p = Paren(vtblArrayPos); // ( #1 ) #2
1080  auto* accessMemberF = AccessMember(p, vtblData.f, false); // #2.f #3
1081 
1082  // (void (*)(struct X*) (#3)
1083  params_vector ps{{kwInternalThis, destType}};
1084  auto* funcPtrFuncDecl = Function("__dummy"sv, VoidTy(), ps);
1085  auto* reicast = ReinterpretCast(funcPtrFuncDecl->getType(), accessMemberF, true);
1086 
1087  auto* p4 = Paren(reicast); // (#4)
1088  auto p5 = Dref(p4); // *#5
1089  auto* p6 = Paren(p5); // (#5) #6
1090 
1091  // -- call with possible this pointer adjustment
1092 
1093  auto* p7 = AccessMember(p, vtblData.d, false); // a->__vptr[1]; #7
1094  auto* p8 = ReinterpretCast(GetGlobalAST().CharTy, Paren(obj), true); // (#7) #8
1095 
1096  auto* p9 = ReinterpretCast(destType, p8);
1097 
1098  auto* p10 = Paren(p9);
1099  auto* p11 = Plus(p10, p7); // #7 + #8 #9
1100  auto* p12 = Paren(p11);
1101 
1102  // Use the modified object parameter
1103  params[0] = p12;
1104  InsertArg(CallExpr::Create(GetGlobalAST(), p6, params, p6->getType(), VK_LValue, {}, {}));
1105 
1106  } else {
1107  InsertArg(Call(GetSpecialMemberName(memDecl), params));
1108  }
1109 
1110  } else {
1112  }
1113 }
1114 //-----------------------------------------------------------------------------
1115 
1116 void CfrontCodeGenerator::InsertArg(const FunctionDecl* stmt)
1117 {
1118  if(not stmt->isMain()) {
1120  return;
1121  }
1122 
1123  params_store params{};
1124  SmallVector<Expr*, 16> args{};
1125 
1126  for(auto* param : stmt->parameters()) {
1127  params.emplace_back(GetName(*param), param->getType());
1128  args.push_back(mkDeclRefExpr(param));
1129  }
1130 
1131  auto mainName{"main"sv};
1132  auto trampolinMainName{BuildInternalVarName(mainName)};
1133 
1134  auto* intMain = Function(trampolinMainName, stmt->getReturnType(), to_params_view(params));
1135  intMain->setBody(stmt->getBody());
1136  intMain->setHasImplicitReturnZero(true);
1137 
1138  InsertArg(intMain);
1140 
1141  auto* mainRetVar = Variable("ret"sv, stmt->getReturnType());
1142  mainRetVar->setInit(Call(trampolinMainName, args));
1143 
1144  auto* mainRetVarDeclStmt = mkDeclStmt(mainRetVar);
1145 
1146  StmtsContainer bodyStmts{Call(cxaStart, {}), mainRetVarDeclStmt, Call(cxaAtExit, {}), Return(mainRetVar)};
1147 
1148  auto* body = mkCompoundStmt({bodyStmts});
1149  auto* modMain = Function(mainName, stmt->getReturnType(), to_params_view(params));
1150  modMain->setBody(body);
1151 
1152  CodeGenerator::InsertArg(modMain);
1153 }
1154 //-----------------------------------------------------------------------------
1155 
1156 void CfrontCodeGenerator::InsertArg(const CXXConstructExpr* stmt)
1157 {
1158  if(P0315Visitor dt{*this}; not dt.TraverseType(stmt->getType())) {
1159  if(not mLambdaStack.empty()) {
1160  for(const auto& e : mLambdaStack) {
1161  RETURN_IF(LambdaCallerType::VarDecl == e.callerType());
1162  }
1163  }
1164  }
1165 
1166  auto ctor = stmt->getConstructor();
1167  auto ctorName = GetSpecialMemberName(ctor);
1168  auto* vd = dyn_cast_or_null<VarDecl>(mLastDecl);
1169 
1170 #if 0
1171  // XXX: An expression like C c[4]{4,5,6} with C having a ctor does show up wrong at the moment.
1172  if(not ar) {
1173  ar = dyn_cast_or_null<ConstantArrayType>(vd->getType());
1174 
1175  if(ar) {
1176  mLastStmt->dump();
1177  openScope = true;
1178  // mOutputFormatHelper.CloseScopeWithSemi();
1180  }
1181  }
1182 #endif
1183 
1184  auto InsertCallCtor = [&](Expr* varNameRef) {
1185  SmallVector<Expr*, 16> args{Cast(varNameRef, Ptr(stmt->getType()))};
1186 
1187  for(int i = 0; auto* arg : stmt->arguments()) {
1188  if(IsCopyOrMoveCtor(ctor) or ctor->getParamDecl(i)->getType()->isReferenceType()) {
1189  args.push_back(Ref(arg));
1190 
1191  } else {
1192  args.push_back(const_cast<Expr*>(arg));
1193  }
1194 
1195  ++i;
1196  }
1197 
1198  InsertArg(Call(ctorName, args));
1199  };
1200 
1201  // For an array we need to call __vec_new
1202  if(const auto* ar = dyn_cast_or_null<ConstantArrayType>(stmt->getType())) {
1203  if(not HasCtor(ar->getElementType())) {
1204  mInsertSemi = false;
1205  return;
1206  }
1207 
1208  InsertArg(CallVecCtor(ctorName, vd, ar->getElementType(), Int32(GetSize(ar))));
1209 
1210  } else if(const auto* tmpObjectExpr = dyn_cast_or_null<CXXTemporaryObjectExpr>(stmt); vd and not tmpObjectExpr) {
1211  if(not HasCtor(vd->getType())) {
1212  mInsertSemi = false;
1213  } else {
1214  auto* varNameRef = Ref(mkDeclRefExpr(vd));
1215 
1216  InsertCallCtor(varNameRef);
1217  }
1218 
1219  } else if(tmpObjectExpr) {
1220  auto* varNameRef = Ref(mkVarDeclRefExpr(GetName(*tmpObjectExpr), stmt->getType()));
1221 
1222  if(not HasCtor(stmt->getType())) {
1223  InsertArg(varNameRef);
1224  return;
1225  }
1226 
1227  InsertCallCtor(varNameRef);
1228 
1229  } else {
1231  stmt->getType(), Ptr(GetRecordDeclType(ctor)), nullptr, ArgsToExprVector(stmt), DoCast::Yes));
1232  }
1233 }
1234 //-----------------------------------------------------------------------------
1235 
1236 } // namespace clang::insights
const ASTContext & GetGlobalAST()
Get access to the ASTContext.
Definition: Insights.cpp:81
const InsightsOptions & GetInsightsOptions()
Get the global C++ Insights options.
Definition: Insights.cpp:37
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...
virtual void InsertArg(const Decl *stmt)
void InsertCXXMethodDecl(const CXXMethodDecl *, CodeGenerator::SkipBody) override
constexpr CodeGenerator(OutputFormatHelper &_outputFormatHelper, LambdaStackType &lambdaStack, LambdaInInitCapture lambdaInitCapture, ProcessingPrimaryTemplate processingPrimaryTemplate)
! We do not want to transform a primary template which contains a Coroutine.
static CfrontVtableData & VtableData()
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)
LambdaStackType & mLambdaStack
OutputFormatHelper & mOutputFormatHelper
The C++ Insights formatter.
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
BinaryOperator * Plus(Expr *var, Expr *assignExpr)
Definition: ASTHelpers.cpp:336
CXXReinterpretCastExpr * ReinterpretCast(QualType toType, const Expr *toExpr, bool makePointer)
Definition: ASTHelpers.cpp:234
CXXRecordDecl * Struct(std::string_view name)
Definition: ASTHelpers.cpp:512
FieldDecl * mkFieldDecl(DeclContext *dc, std::string_view name, QualType type)
Definition: ASTHelpers.cpp:533
params_vector to_params_view(params_store &params)
Definition: ASTHelpers.cpp:560
DeclStmt * mkDeclStmt(Dcls... dcls)
Definition: ASTHelpers.h:91
DeclRefExpr * mkDeclRefExpr(const ValueDecl *vd)
Definition: ASTHelpers.cpp:425
QualType Typedef(std::string_view name, QualType underlayingType)
Definition: ASTHelpers.cpp:663
std::vector< std::pair< std::string_view, QualType > > params_vector
Definition: ASTHelpers.h:27
CallExpr * Call(const FunctionDecl *fd, ArrayRef< Expr * > params)
Definition: ASTHelpers.cpp:117
UnaryOperator * Ref(const Expr *e)
Definition: ASTHelpers.cpp:93
VarDecl * Variable(std::string_view name, QualType type, DeclContext *dc)
Definition: ASTHelpers.cpp:487
MemberExpr * AccessMember(const Expr *expr, const ValueDecl *vd, bool isArrow)
Definition: ASTHelpers.cpp:318
DeclRefExpr * mkVarDeclRefExpr(std::string_view name, QualType type)
Definition: ASTHelpers.cpp:573
SmallVector< Expr *, 5 > ArgsToExprVector(const Expr *expr)
Definition: ASTHelpers.cpp:740
ArraySubscriptExpr * ArraySubscript(const Expr *lhs, uint64_t index, QualType type)
Definition: ASTHelpers.cpp:553
ReturnStmt * Return(Expr *stmt)
Definition: ASTHelpers.cpp:454
CXXStaticCastExpr * Cast(const Expr *toExpr, QualType toType)
Definition: ASTHelpers.cpp:178
CXXStaticCastExpr * CastToVoidFunPtr(std::string_view name)
Definition: ASTHelpers.cpp:228
Stmt * Comment(std::string_view comment)
Definition: ASTHelpers.cpp:506
ParenExpr * Paren(Expr *expr)
Definition: ASTHelpers.cpp:196
IfStmt * If(const Expr *condition, ArrayRef< Stmt * > bodyStmts)
Definition: ASTHelpers.cpp:293
BinaryOperator * Mul(Expr *lhs, Expr *rhs)
Definition: ASTHelpers.cpp:711
InitListExpr * InitList(ArrayRef< Expr * > initExprs, QualType t)
Definition: ASTHelpers.cpp:544
UnaryExprOrTypeTraitExpr * Sizeof(QualType toType)
Definition: ASTHelpers.cpp:171
QualType GetRecordDeclType(const CXXMethodDecl *md)
Definition: ASTHelpers.cpp:677
static CallExpr * CallConstructor(QualType ctorType, DeclRefExpr *lhsDeclRef, Expr *lhsMemberExpr, ArrayRef< Expr * > callParams, DoCast doCast, AsReference asReference)
Definition: ASTHelpers.cpp:582
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)
Definition: ASTHelpers.cpp:403
CompoundStmt * mkCompoundStmt(ArrayRef< Stmt * > bodyStmts, SourceLocation beginLoc, SourceLocation endLoc)
Definition: ASTHelpers.cpp:287
IntegerLiteral * Int32(uint64_t value)
Definition: ASTHelpers.cpp:309
QualType ContantArrayTy(QualType t, int size)
Definition: ASTHelpers.cpp:202
UnaryOperator * Dref(const Expr *stmt)
Definition: ASTHelpers.cpp:105
QualType Ptr(QualType srcType)
Definition: ASTHelpers.cpp:184
CXXStaticCastExpr * StaticCast(QualType toType, const Expr *toExpr, bool makePointer)
Definition: ASTHelpers.cpp:253
BinaryOperator * Assign(const VarDecl *var, Expr *assignExpr)
Definition: ASTHelpers.cpp:31
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 DPrint([[maybe_unused]] const char *fmt, [[maybe_unused]] const auto &... args)
Debug print which is disabled in release-mode.
Definition: DPrint.h:71
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.
static auto * CallVecCtor(std::string_view ctorName, const VarDecl *objectParam, QualType allocatedType, Expr *arraySizeExpr)
std::string GetName(const NamedDecl &nd, const QualifiedName qualifiedName)
static void ProcessFields(CXXRecordDecl *recordDecl, const CXXRecordDecl *rd)
std::string BuildInternalVarName(const std::string_view &varName)
static bool IsCopyOrMoveAssign(const CXXMethodDecl *stmt)
static FieldDecl * AddField(CoroutineASTData &astData, std::string_view name, QualType type)
static bool HasDtor(QualType t)
static MemberExpr * AccessMember(std::string_view name, const ValueDecl *vd, QualType type)
static bool HasCtor(QualType t)
static void InsertVtblPtr(const CXXMethodDecl *stmt, const CXXRecordDecl *cur, StmtsContainer &bodyStmts)
static const CXXRecordDecl * GetFirstPolymorphicBase(const RecordDecl *decl)
! Find the first polymorphic base class.
bool IsReferenceType(const ValueDecl *decl)
static auto * CallVecDelete(Expr *objectParam, QualType allocatedType)
static std::string GetSpecialMemberName(const ValueDecl *vd, QualType type)
static bool IsCopyOrMoveCtor(const CXXConstructorDecl *ctor)
bool IsStaticStorageClass(const CXXMethodDecl *md)
static std::string GetFirstPolymorphicBaseName(const RecordDecl *decl, const RecordDecl *to)
void EnableGlobalInsert(GlobalInserts idx)
Definition: Insights.cpp:106
static auto * CallVecDtor(Expr *objectParam, const ConstantArrayType *ar)
static auto * CallVecNewOrCtor(std::string_view ctorName, Expr *objectParam, QualType allocatedType, Expr *arraySizeExpr, std::string_view funName)
static auto * CallVecDeleteOrDtor(Expr *objectParam, QualType allocatedType, std::string_view name, uint64_t size)
std::string StrCat(const auto &... args)
static auto * CallVecNew(std::string_view ctorName, Expr *objectParam, QualType allocatedType, Expr *arraySizeExpr)
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