clang 24.0.0git
ClassUtils.cpp
Go to the documentation of this file.
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
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
34 DynamicThisUseChecker Checker(Ctx);
35 Checker.Visit(Init);
36 return Checker.UsesThis;
37}
38
39static bool
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, 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, VirtualBase, MostDerivedClassDecl))
69 return false;
70 }
71 }
72
73 return true;
74}
75
77 QualType FieldBaseElementType = Ctx.getBaseElementType(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, FieldClassDecl, FieldClassDecl);
88}
89
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
113 const Type *BaseType = BaseInit->getBaseClass();
114 return BaseType->castAsCXXRecordDecl()->isDynamicClass();
115}
116
117} // namespace clang::CodeGenUtils
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:245
QualType getBaseElementType(const ArrayType *VAT) const
Return the innermost element type of an array type.
Represents a C++ base or member initializer.
Definition DeclCXX.h:2407
const Type * getBaseClass() const
If this is a base class initializer, returns the type of the base class.
Definition DeclCXX.cpp:2946
Represents a C++ destructor within a class.
Definition DeclCXX.h:2907
Represents a C++ struct/union/class.
Definition DeclCXX.h:258
bool isEffectivelyFinal() const
Determine whether it's impossible for a class to be derived from this class.
Definition DeclCXX.cpp:2341
bool hasTrivialDestructor() const
Determine whether this class has a trivial destructor (C++ [class.dtor]p3)
Definition DeclCXX.h:1382
base_class_range bases()
Definition DeclCXX.h:609
base_class_range vbases()
Definition DeclCXX.h:626
bool isDynamicClass() const
Definition DeclCXX.h:575
CXXDestructorDecl * getDestructor() const
Returns the destructor decl for this class.
Definition DeclCXX.cpp:2129
This represents one expression.
Definition Expr.h:113
Represents a member of a struct/union/class.
Definition Decl.h:3299
bool hasTrivialBody() const
Returns whether the function has a trivial body that does not require any specific codegen.
Definition Decl.cpp:3202
A (possibly-)qualified type.
Definition TypeBase.h:938
field_range fields() const
Definition Decl.h:4667
The base class of the type hierarchy.
Definition TypeBase.h:1879
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition Type.h:26
CXXRecordDecl * castAsCXXRecordDecl() const
Definition Type.h:36
bool isInitializerOfDynamicClass(const CXXCtorInitializer *BaseInit)
Return whether BaseInit initializes a base class that is dynamic, that is, one whose vtable pointer m...
static bool hasTrivialDestructorBody(ASTContext &Ctx, const CXXRecordDecl *BaseClassDecl, const CXXRecordDecl *MostDerivedClassDecl)
bool canSkipVTablePointerInitialization(ASTContext &Ctx, const CXXDestructorDecl *Dtor)
Check whether we need to initialize any vtable pointers before calling this destructor.
bool fieldHasTrivialDestructorBody(ASTContext &Ctx, const FieldDecl *Field)
Check whether destructing Field has no observable behaviors, and thus can be skipped when creating a ...
bool baseInitializerUsesThis(ASTContext &Ctx, const Expr *Init)
Check whether Init uses 'this' in a way which requires the vtable to be properly set.