1//===--- ItaniumCXXABIUtils.cpp - Shared Itanium C++ ABI 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/ItaniumCXXABIUtils.h"
10#include "clang/AST/CXXInheritance.h"
11#include "clang/AST/RecordLayout.h"
12
13namespace clang::CodeGenUtils {
14
15CharUnits computeOffsetHint(ASTContext &Ctx, const CXXRecordDecl *Src,
16 const CXXRecordDecl *Dst) {
17 CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
18 /*DetectVirtual=*/false);
19
20 // If Dst is not derived from Src we can skip the whole computation below and
21 // return that Src is not a public base of Dst. Record all inheritance paths.
22 if (!Dst->isDerivedFrom(Base: Src, Paths))
23 return CharUnits::fromQuantity(Quantity: -2ULL);
24
25 unsigned NumPublicPaths = 0;
26 CharUnits Offset;
27
28 // Now walk all possible inheritance paths.
29 for (const CXXBasePath &Path : Paths) {
30 if (Path.Access != AS_public) // Ignore non-public inheritance.
31 continue;
32
33 ++NumPublicPaths;
34
35 for (const CXXBasePathElement &PathElement : Path) {
36 // If the path contains a virtual base class we can't give any hint.
37 // -1: no hint.
38 if (PathElement.Base->isVirtual())
39 return CharUnits::fromQuantity(Quantity: -1ULL);
40
41 if (NumPublicPaths > 1) // Won't use offsets, skip computation.
42 continue;
43
44 // Accumulate the base class offsets.
45 const ASTRecordLayout &L = Ctx.getASTRecordLayout(D: PathElement.Class);
46 Offset += L.getBaseClassOffset(
47 Base: PathElement.Base->getType()->getAsCXXRecordDecl());
48 }
49 }
50
51 // -2: Src is not a public base of Dst.
52 if (NumPublicPaths == 0)
53 return CharUnits::fromQuantity(Quantity: -2ULL);
54
55 // -3: Src is a multiple public base type but never a virtual base type.
56 if (NumPublicPaths > 1)
57 return CharUnits::fromQuantity(Quantity: -3ULL);
58
59 // Otherwise, the Src type is a unique public nonvirtual base type of Dst.
60 // Return the offset of Src from the origin of Dst.
61 return Offset;
62}
63
64bool canUseSingleInheritance(const CXXRecordDecl *RD) {
65 // Check the number of bases.
66 if (RD->getNumBases() != 1)
67 return false;
68
69 // Get the base.
70 CXXRecordDecl::base_class_const_iterator Base = RD->bases_begin();
71
72 // Check that the base is not virtual.
73 if (Base->isVirtual())
74 return false;
75
76 // Check that the base is public.
77 if (Base->getAccessSpecifier() != AS_public)
78 return false;
79
80 // Check that the class is dynamic iff the base is.
81 auto *BaseDecl = Base->getType()->castAsCXXRecordDecl();
82 return BaseDecl->isEmpty() ||
83 BaseDecl->isDynamicClass() == RD->isDynamicClass();
84}
85
86namespace {
87/// Contains virtual and non-virtual bases seen when traversing a class
88/// hierarchy.
89struct SeenBases {
90 llvm::SmallPtrSet<const CXXRecordDecl *, 16> NonVirtualBases;
91 llvm::SmallPtrSet<const CXXRecordDecl *, 16> VirtualBases;
92};
93} // namespace
94
95static unsigned computeVMIClassTypeInfoFlags(const CXXBaseSpecifier *Base,
96 SeenBases &Bases) {
97 unsigned Flags = 0;
98
99 auto *BaseDecl = Base->getType()->castAsCXXRecordDecl();
100 if (Base->isVirtual()) {
101 // Mark the virtual base as seen.
102 if (!Bases.VirtualBases.insert(Ptr: BaseDecl).second) {
103 // If this virtual base has been seen before, then the class is diamond
104 // shaped.
105 Flags |= VMI_DiamondShaped;
106 } else {
107 if (Bases.NonVirtualBases.count(Ptr: BaseDecl))
108 Flags |= VMI_NonDiamondRepeat;
109 }
110 } else {
111 // Mark the non-virtual base as seen.
112 if (!Bases.NonVirtualBases.insert(Ptr: BaseDecl).second) {
113 // If this non-virtual base has been seen before, then the class has non-
114 // diamond shaped repeated inheritance.
115 Flags |= VMI_NonDiamondRepeat;
116 } else {
117 if (Bases.VirtualBases.count(Ptr: BaseDecl))
118 Flags |= VMI_NonDiamondRepeat;
119 }
120 }
121
122 // Walk all bases.
123 for (const auto &I : BaseDecl->bases())
124 Flags |= computeVMIClassTypeInfoFlags(Base: &I, Bases);
125
126 return Flags;
127}
128
129unsigned computeVMIClassTypeInfoFlags(const CXXRecordDecl *RD) {
130 unsigned Flags = 0;
131 SeenBases Bases;
132
133 // Walk all bases.
134 for (const auto &I : RD->bases())
135 Flags |= computeVMIClassTypeInfoFlags(Base: &I, Bases);
136
137 return Flags;
138}
139
140/// Returns whether the given record type is incomplete.
141static bool isIncompleteClassType(const RecordType *RecordTy) {
142 return !RecordTy->getDecl()->getDefinitionOrSelf()->isCompleteDefinition();
143}
144
145bool containsIncompleteClassType(QualType Ty) {
146 if (const auto *RecordTy = dyn_cast<RecordType>(Val&: Ty)) {
147 if (isIncompleteClassType(RecordTy))
148 return true;
149 }
150
151 if (const auto *PointerTy = dyn_cast<PointerType>(Val&: Ty))
152 return containsIncompleteClassType(Ty: PointerTy->getPointeeType());
153
154 if (const auto *MemberPointerTy = dyn_cast<MemberPointerType>(Val&: Ty)) {
155 // Check if the class type is incomplete.
156 if (!MemberPointerTy->getMostRecentCXXRecordDecl()->hasDefinition())
157 return true;
158
159 return containsIncompleteClassType(Ty: MemberPointerTy->getPointeeType());
160 }
161
162 return false;
163}
164
165unsigned extractPBaseFlags(const ASTContext &Ctx, QualType &Type) {
166 unsigned Flags = 0;
167
168 if (Type.isConstQualified())
169 Flags |= PTI_Const;
170 if (Type.isVolatileQualified())
171 Flags |= PTI_Volatile;
172 if (Type.isRestrictQualified())
173 Flags |= PTI_Restrict;
174 Type = Type.getUnqualifiedType();
175
176 // Itanium C++ ABI 2.9.5p7:
177 // When the abi::__pbase_type_info is for a direct or indirect pointer to an
178 // incomplete class type, the incomplete target type flag is set.
179 if (containsIncompleteClassType(Ty: Type))
180 Flags |= PTI_Incomplete;
181
182 if (auto *Proto = Type->getAs<FunctionProtoType>()) {
183 if (Proto->isNothrow()) {
184 Flags |= PTI_Noexcept;
185 Type = Ctx.getFunctionTypeWithExceptionSpec(Orig: Type, ESI: EST_None);
186 }
187 }
188
189 return Flags;
190}
191
192/// Given a builtin type, returns whether the type info for that type is
193/// defined in the standard library.
194static bool typeInfoIsInStandardLibrary(const BuiltinType *Ty) {
195 // Itanium C++ ABI 2.9.2:
196 // Basic type information (e.g. for "int", "bool", etc.) will be kept in
197 // the run-time support library. Specifically, the run-time support
198 // library should contain type_info objects for the types X, X* and
199 // X const*, for every X in: void, std::nullptr_t, bool, wchar_t, char,
200 // unsigned char, signed char, short, unsigned short, int, unsigned int,
201 // long, unsigned long, long long, unsigned long long, float, double,
202 // long double, char16_t, char32_t, and the IEEE 754r decimal and
203 // half-precision floating point types.
204 //
205 // GCC also emits RTTI for __int128.
206 // FIXME: We do not emit RTTI information for decimal types here.
207
208 // Types added here must also be added to EmitFundamentalRTTIDescriptors in
209 // clang/lib/CodeGen/ItaniumCXXABI.cpp.
210 switch (Ty->getKind()) {
211 case BuiltinType::Void:
212 case BuiltinType::NullPtr:
213 case BuiltinType::Bool:
214 case BuiltinType::WChar_S:
215 case BuiltinType::WChar_U:
216 case BuiltinType::Char_U:
217 case BuiltinType::Char_S:
218 case BuiltinType::UChar:
219 case BuiltinType::SChar:
220 case BuiltinType::Short:
221 case BuiltinType::UShort:
222 case BuiltinType::Int:
223 case BuiltinType::UInt:
224 case BuiltinType::Long:
225 case BuiltinType::ULong:
226 case BuiltinType::LongLong:
227 case BuiltinType::ULongLong:
228 case BuiltinType::Half:
229 case BuiltinType::Float:
230 case BuiltinType::Double:
231 case BuiltinType::LongDouble:
232 case BuiltinType::Float16:
233 case BuiltinType::Float128:
234 case BuiltinType::Ibm128:
235 case BuiltinType::Char8:
236 case BuiltinType::Char16:
237 case BuiltinType::Char32:
238 case BuiltinType::Int128:
239 case BuiltinType::UInt128:
240 return true;
241
242#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
243 case BuiltinType::Id:
244#include "clang/Basic/OpenCLImageTypes.def"
245#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) case BuiltinType::Id:
246#include "clang/Basic/OpenCLExtensionTypes.def"
247 case BuiltinType::OCLSampler:
248 case BuiltinType::OCLEvent:
249 case BuiltinType::OCLClkEvent:
250 case BuiltinType::OCLQueue:
251 case BuiltinType::OCLReserveID:
252#define SVE_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
253#include "clang/Basic/AArch64ACLETypes.def"
254#define PPC_VECTOR_TYPE(Name, Id, Size) case BuiltinType::Id:
255#include "clang/Basic/PPCTypes.def"
256#define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
257#include "clang/Basic/RISCVVTypes.def"
258#define WASM_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
259#include "clang/Basic/WebAssemblyReferenceTypes.def"
260#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) case BuiltinType::Id:
261#include "clang/Basic/AMDGPUTypes.def"
262#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
263#include "clang/Basic/HLSLIntangibleTypes.def"
264#define HLSL_PACKED_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
265#include "clang/Basic/HLSLPackedTypes.def"
266#define SPIRV_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
267#include "clang/Basic/SPIRVTypes.def"
268 case BuiltinType::ShortAccum:
269 case BuiltinType::Accum:
270 case BuiltinType::LongAccum:
271 case BuiltinType::UShortAccum:
272 case BuiltinType::UAccum:
273 case BuiltinType::ULongAccum:
274 case BuiltinType::ShortFract:
275 case BuiltinType::Fract:
276 case BuiltinType::LongFract:
277 case BuiltinType::UShortFract:
278 case BuiltinType::UFract:
279 case BuiltinType::ULongFract:
280 case BuiltinType::SatShortAccum:
281 case BuiltinType::SatAccum:
282 case BuiltinType::SatLongAccum:
283 case BuiltinType::SatUShortAccum:
284 case BuiltinType::SatUAccum:
285 case BuiltinType::SatULongAccum:
286 case BuiltinType::SatShortFract:
287 case BuiltinType::SatFract:
288 case BuiltinType::SatLongFract:
289 case BuiltinType::SatUShortFract:
290 case BuiltinType::SatUFract:
291 case BuiltinType::SatULongFract:
292 case BuiltinType::BFloat16:
293 case BuiltinType::MetaInfo:
294 return false;
295
296 case BuiltinType::Dependent:
297#define BUILTIN_TYPE(Id, SingletonId)
298#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id:
299#include "clang/AST/BuiltinTypes.def"
300 llvm_unreachable("asking for RRTI for a placeholder type!");
301
302 case BuiltinType::ObjCId:
303 case BuiltinType::ObjCClass:
304 case BuiltinType::ObjCSel:
305 llvm_unreachable("FIXME: Objective-C types are unsupported!");
306 }
307
308 llvm_unreachable("Invalid BuiltinType Kind!");
309}
310
311static bool typeInfoIsInStandardLibrary(const PointerType *PointerTy) {
312 QualType PointeeTy = PointerTy->getPointeeType();
313 const BuiltinType *BuiltinTy = dyn_cast<BuiltinType>(Val&: PointeeTy);
314 if (!BuiltinTy)
315 return false;
316
317 // Check the qualifiers.
318 Qualifiers Quals = PointeeTy.getQualifiers();
319 Quals.removeConst();
320
321 if (!Quals.empty())
322 return false;
323
324 return typeInfoIsInStandardLibrary(Ty: BuiltinTy);
325}
326
327bool isStandardLibraryRTTIDescriptor(QualType Ty) {
328 // Type info for builtin types is defined in the standard library.
329 if (const BuiltinType *BuiltinTy = dyn_cast<BuiltinType>(Val&: Ty))
330 return typeInfoIsInStandardLibrary(Ty: BuiltinTy);
331
332 // Type info for some pointer types to builtin types is defined in the
333 // standard library.
334 if (const PointerType *PointerTy = dyn_cast<PointerType>(Val&: Ty))
335 return typeInfoIsInStandardLibrary(PointerTy);
336
337 return false;
338}
339
340} // namespace clang::CodeGenUtils
341