1//===--- ClassUtils.cpp - Shared C++ class emission queries ---------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "clang/CodeGenUtils/ClassUtils.h"
10#include "clang/AST/EvaluatedExprVisitor.h"
11
12namespace clang::CodeGenUtils {
13namespace {
14/// A visitor which checks whether an initializer uses 'this' in a
15/// way which requires the vtable to be properly set.
16struct DynamicThisUseChecker
17 : ConstEvaluatedExprVisitor<DynamicThisUseChecker> {
18 using super = ConstEvaluatedExprVisitor<DynamicThisUseChecker>;
19
20 bool UsesThis = false;
21
22 DynamicThisUseChecker(const ASTContext &C) : super(C) {}
23
24 // Black-list all explicit and implicit references to 'this'.
25 //
26 // Do we need to worry about external references to 'this' derived
27 // from arbitrary code? If so, then anything which runs arbitrary
28 // external code might potentially access the vtable.
29 void VisitCXXThisExpr(const CXXThisExpr *E) { UsesThis = true; }
30};
31} // namespace
32
33bool baseInitializerUsesThis(ASTContext &Ctx, const Expr *Init) {
34 DynamicThisUseChecker Checker(Ctx);
35 Checker.Visit(S: Init);
36 return Checker.UsesThis;
37}
38
39static bool
40hasTrivialDestructorBody(ASTContext &Ctx, const CXXRecordDecl *BaseClassDecl,
41 const CXXRecordDecl *MostDerivedClassDecl) {
42 // If the destructor is trivial we don't have to check anything else.
43 if (BaseClassDecl->hasTrivialDestructor())
44 return true;
45
46 if (!BaseClassDecl->getDestructor()->hasTrivialBody())
47 return false;
48
49 // Check fields.
50 for (const auto *Field : BaseClassDecl->fields())
51 if (!fieldHasTrivialDestructorBody(Ctx, Field))
52 return false;
53
54 // Check non-virtual bases.
55 for (const auto &I : BaseClassDecl->bases()) {
56 if (I.isVirtual())
57 continue;
58
59 const auto *NonVirtualBase = I.getType()->castAsCXXRecordDecl();
60 if (!hasTrivialDestructorBody(Ctx, BaseClassDecl: NonVirtualBase, MostDerivedClassDecl))
61 return false;
62 }
63
64 if (BaseClassDecl == MostDerivedClassDecl) {
65 // Check virtual bases.
66 for (const auto &I : BaseClassDecl->vbases()) {
67 const auto *VirtualBase = I.getType()->castAsCXXRecordDecl();
68 if (!hasTrivialDestructorBody(Ctx, BaseClassDecl: VirtualBase, MostDerivedClassDecl))
69 return false;
70 }
71 }
72
73 return true;
74}
75
76bool fieldHasTrivialDestructorBody(ASTContext &Ctx, const FieldDecl *Field) {
77 QualType FieldBaseElementType = Ctx.getBaseElementType(QT: Field->getType());
78
79 auto *FieldClassDecl = FieldBaseElementType->getAsCXXRecordDecl();
80 if (!FieldClassDecl)
81 return true;
82
83 // The destructor for an implicit anonymous union member is never invoked.
84 if (FieldClassDecl->isUnion() && FieldClassDecl->isAnonymousStructOrUnion())
85 return true;
86
87 return hasTrivialDestructorBody(Ctx, BaseClassDecl: FieldClassDecl, MostDerivedClassDecl: FieldClassDecl);
88}
89
90bool canSkipVTablePointerInitialization(ASTContext &Ctx,
91 const CXXDestructorDecl *Dtor) {
92 const CXXRecordDecl *ClassDecl = Dtor->getParent();
93 if (!ClassDecl->isDynamicClass())
94 return true;
95
96 // For a final class, the vtable pointer is known to already point to the
97 // class's vtable.
98 if (ClassDecl->isEffectivelyFinal())
99 return true;
100
101 if (!Dtor->hasTrivialBody())
102 return false;
103
104 // Check the fields.
105 for (const auto *Field : ClassDecl->fields())
106 if (!fieldHasTrivialDestructorBody(Ctx, Field))
107 return false;
108
109 return true;
110}
111
112bool isInitializerOfDynamicClass(const CXXCtorInitializer *BaseInit) {
113 const Type *BaseType = BaseInit->getBaseClass();
114 return BaseType->castAsCXXRecordDecl()->isDynamicClass();
115}
116
117} // namespace clang::CodeGenUtils
118