blob: 44b9804215d2face4725778bc41b5a47b81c60fa [file] [log] [blame]
John McCallbda0d6b2011-03-27 09:00:25 +00001//===--- CGVTables.h - Emit LLVM Code for C++ vtables -----------*- C++ -*-===//
Anders Carlssondbd920c2009-10-11 22:13:54 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This contains code dealing with C++ code generation of virtual tables.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef CLANG_CODEGEN_CGVTABLE_H
15#define CLANG_CODEGEN_CGVTABLE_H
16
17#include "llvm/ADT/DenseMap.h"
Anders Carlsson35272252009-12-06 00:23:49 +000018#include "llvm/GlobalVariable.h"
Peter Collingbourne14110472011-01-13 18:57:25 +000019#include "clang/Basic/ABI.h"
Peter Collingbourne33446f12011-09-26 01:56:16 +000020#include "clang/AST/BaseSubobject.h"
Ken Dyck4230d522011-03-24 01:21:01 +000021#include "clang/AST/CharUnits.h"
Peter Collingbournefd05ca02011-06-14 04:02:39 +000022#include "clang/AST/GlobalDecl.h"
Anders Carlssondbd920c2009-10-11 22:13:54 +000023
24namespace clang {
Anders Carlssondbd920c2009-10-11 22:13:54 +000025 class CXXRecordDecl;
Benjamin Kramer39411b92009-11-26 13:09:03 +000026
Anders Carlssondbd920c2009-10-11 22:13:54 +000027namespace CodeGen {
28 class CodeGenModule;
Anders Carlssona94822e2009-11-26 02:32:05 +000029
Peter Collingbourneba6ffeb2011-09-26 01:56:45 +000030/// VTableComponent - Represents a single component in a vtable.
31class VTableComponent {
32public:
33 enum Kind {
34 CK_VCallOffset,
35 CK_VBaseOffset,
36 CK_OffsetToTop,
37 CK_RTTI,
38 CK_FunctionPointer,
39
40 /// CK_CompleteDtorPointer - A pointer to the complete destructor.
41 CK_CompleteDtorPointer,
42
43 /// CK_DeletingDtorPointer - A pointer to the deleting destructor.
44 CK_DeletingDtorPointer,
45
46 /// CK_UnusedFunctionPointer - In some cases, a vtable function pointer
47 /// will end up never being called. Such vtable function pointers are
48 /// represented as a CK_UnusedFunctionPointer.
49 CK_UnusedFunctionPointer
50 };
51
Peter Collingbournee09cdf42011-09-26 01:56:50 +000052 VTableComponent() { }
53
Peter Collingbourneba6ffeb2011-09-26 01:56:45 +000054 static VTableComponent MakeVCallOffset(CharUnits Offset) {
55 return VTableComponent(CK_VCallOffset, Offset);
56 }
57
58 static VTableComponent MakeVBaseOffset(CharUnits Offset) {
59 return VTableComponent(CK_VBaseOffset, Offset);
60 }
61
62 static VTableComponent MakeOffsetToTop(CharUnits Offset) {
63 return VTableComponent(CK_OffsetToTop, Offset);
64 }
65
66 static VTableComponent MakeRTTI(const CXXRecordDecl *RD) {
67 return VTableComponent(CK_RTTI, reinterpret_cast<uintptr_t>(RD));
68 }
69
70 static VTableComponent MakeFunction(const CXXMethodDecl *MD) {
71 assert(!isa<CXXDestructorDecl>(MD) &&
72 "Don't use MakeFunction with destructors!");
73
74 return VTableComponent(CK_FunctionPointer,
75 reinterpret_cast<uintptr_t>(MD));
76 }
77
78 static VTableComponent MakeCompleteDtor(const CXXDestructorDecl *DD) {
79 return VTableComponent(CK_CompleteDtorPointer,
80 reinterpret_cast<uintptr_t>(DD));
81 }
82
83 static VTableComponent MakeDeletingDtor(const CXXDestructorDecl *DD) {
84 return VTableComponent(CK_DeletingDtorPointer,
85 reinterpret_cast<uintptr_t>(DD));
86 }
87
88 static VTableComponent MakeUnusedFunction(const CXXMethodDecl *MD) {
89 assert(!isa<CXXDestructorDecl>(MD) &&
90 "Don't use MakeUnusedFunction with destructors!");
91 return VTableComponent(CK_UnusedFunctionPointer,
92 reinterpret_cast<uintptr_t>(MD));
93 }
94
95 static VTableComponent getFromOpaqueInteger(uint64_t I) {
96 return VTableComponent(I);
97 }
98
99 /// getKind - Get the kind of this vtable component.
100 Kind getKind() const {
101 return (Kind)(Value & 0x7);
102 }
103
104 CharUnits getVCallOffset() const {
105 assert(getKind() == CK_VCallOffset && "Invalid component kind!");
106
107 return getOffset();
108 }
109
110 CharUnits getVBaseOffset() const {
111 assert(getKind() == CK_VBaseOffset && "Invalid component kind!");
112
113 return getOffset();
114 }
115
116 CharUnits getOffsetToTop() const {
117 assert(getKind() == CK_OffsetToTop && "Invalid component kind!");
118
119 return getOffset();
120 }
121
122 const CXXRecordDecl *getRTTIDecl() const {
123 assert(getKind() == CK_RTTI && "Invalid component kind!");
124
125 return reinterpret_cast<CXXRecordDecl *>(getPointer());
126 }
127
128 const CXXMethodDecl *getFunctionDecl() const {
129 assert(getKind() == CK_FunctionPointer);
130
131 return reinterpret_cast<CXXMethodDecl *>(getPointer());
132 }
133
134 const CXXDestructorDecl *getDestructorDecl() const {
135 assert((getKind() == CK_CompleteDtorPointer ||
136 getKind() == CK_DeletingDtorPointer) && "Invalid component kind!");
137
138 return reinterpret_cast<CXXDestructorDecl *>(getPointer());
139 }
140
141 const CXXMethodDecl *getUnusedFunctionDecl() const {
142 assert(getKind() == CK_UnusedFunctionPointer);
143
144 return reinterpret_cast<CXXMethodDecl *>(getPointer());
145 }
146
147private:
148 VTableComponent(Kind ComponentKind, CharUnits Offset) {
149 assert((ComponentKind == CK_VCallOffset ||
150 ComponentKind == CK_VBaseOffset ||
151 ComponentKind == CK_OffsetToTop) && "Invalid component kind!");
152 assert(Offset.getQuantity() <= ((1LL << 56) - 1) && "Offset is too big!");
153
154 Value = ((Offset.getQuantity() << 3) | ComponentKind);
155 }
156
157 VTableComponent(Kind ComponentKind, uintptr_t Ptr) {
158 assert((ComponentKind == CK_RTTI ||
159 ComponentKind == CK_FunctionPointer ||
160 ComponentKind == CK_CompleteDtorPointer ||
161 ComponentKind == CK_DeletingDtorPointer ||
162 ComponentKind == CK_UnusedFunctionPointer) &&
163 "Invalid component kind!");
164
165 assert((Ptr & 7) == 0 && "Pointer not sufficiently aligned!");
166
167 Value = Ptr | ComponentKind;
168 }
169
170 CharUnits getOffset() const {
171 assert((getKind() == CK_VCallOffset || getKind() == CK_VBaseOffset ||
172 getKind() == CK_OffsetToTop) && "Invalid component kind!");
173
174 return CharUnits::fromQuantity(Value >> 3);
175 }
176
177 uintptr_t getPointer() const {
178 assert((getKind() == CK_RTTI ||
179 getKind() == CK_FunctionPointer ||
180 getKind() == CK_CompleteDtorPointer ||
181 getKind() == CK_DeletingDtorPointer ||
182 getKind() == CK_UnusedFunctionPointer) &&
183 "Invalid component kind!");
184
185 return static_cast<uintptr_t>(Value & ~7ULL);
186 }
187
188 explicit VTableComponent(uint64_t Value)
189 : Value(Value) { }
190
191 /// The kind is stored in the lower 3 bits of the value. For offsets, we
192 /// make use of the facts that classes can't be larger than 2^55 bytes,
193 /// so we store the offset in the lower part of the 61 bytes that remain.
194 /// (The reason that we're not simply using a PointerIntPair here is that we
195 /// need the offsets to be 64-bit, even when on a 32-bit machine).
196 int64_t Value;
197};
198
Peter Collingbournee09cdf42011-09-26 01:56:50 +0000199class VTableLayout {
200public:
201 typedef std::pair<uint64_t, ThunkInfo> VTableThunkTy;
202 typedef llvm::SmallVector<ThunkInfo, 1> ThunkInfoVectorTy;
203
204 typedef const VTableComponent *vtable_component_iterator;
205 typedef const VTableThunkTy *vtable_thunk_iterator;
206
207 typedef llvm::DenseMap<BaseSubobject, uint64_t> AddressPointsMapTy;
208private:
209 uint64_t NumVTableComponents;
210 VTableComponent *VTableComponents;
211
212 /// VTableThunks - Contains thunks needed by vtables.
213 uint64_t NumVTableThunks;
214 VTableThunkTy *VTableThunks;
215
216 /// Address points - Address points for all vtables.
217 AddressPointsMapTy AddressPoints;
218
219public:
220 VTableLayout(uint64_t NumVTableComponents,
221 const VTableComponent *VTableComponents,
222 uint64_t NumVTableThunks,
223 const VTableThunkTy *VTableThunks,
224 const AddressPointsMapTy &AddressPoints);
225 ~VTableLayout();
226
227 uint64_t getNumVTableComponents() const {
228 return NumVTableComponents;
229 }
230
231 vtable_component_iterator vtable_component_begin() const {
232 return VTableComponents;
233 }
234
235 vtable_component_iterator vtable_component_end() const {
236 return VTableComponents+NumVTableComponents;
237 }
238
239 uint64_t getNumVTableThunks() const {
240 return NumVTableThunks;
241 }
242
243 vtable_thunk_iterator vtable_thunk_begin() const {
244 return VTableThunks;
245 }
246
247 vtable_thunk_iterator vtable_thunk_end() const {
248 return VTableThunks+NumVTableThunks;
249 }
250
251 uint64_t getAddressPoint(BaseSubobject Base) const {
252 assert(AddressPoints.count(Base) &&
253 "Did not find address point!");
254
255 uint64_t AddressPoint = AddressPoints.lookup(Base);
256 assert(AddressPoint && "Address point must not be zero!");
257
258 return AddressPoint;
259 }
Peter Collingbourneab172b52011-09-26 01:57:04 +0000260
261 const AddressPointsMapTy &getAddressPoints() const {
262 return AddressPoints;
263 }
Peter Collingbournee09cdf42011-09-26 01:56:50 +0000264};
265
Peter Collingbourne1d2b3172011-09-26 01:56:30 +0000266class VTableContext {
267 ASTContext &Context;
Benjamin Kramer39411b92009-11-26 13:09:03 +0000268
Peter Collingbourne84fcc482011-09-26 01:56:41 +0000269public:
270 typedef SmallVector<std::pair<uint64_t, ThunkInfo>, 1>
271 VTableThunksTy;
272 typedef SmallVector<ThunkInfo, 1> ThunkInfoVectorTy;
273
274private:
Anders Carlsson046c2942010-04-17 20:15:18 +0000275 /// MethodVTableIndices - Contains the index (relative to the vtable address
Anders Carlssondbd920c2009-10-11 22:13:54 +0000276 /// point) where the function pointer for a virtual function is stored.
Anders Carlsson046c2942010-04-17 20:15:18 +0000277 typedef llvm::DenseMap<GlobalDecl, int64_t> MethodVTableIndicesTy;
278 MethodVTableIndicesTy MethodVTableIndices;
Benjamin Kramer39411b92009-11-26 13:09:03 +0000279
Peter Collingbournee09cdf42011-09-26 01:56:50 +0000280 typedef llvm::DenseMap<const CXXRecordDecl *, const VTableLayout *>
281 VTableLayoutMapTy;
282 VTableLayoutMapTy VTableLayouts;
283
Peter Collingbourne1d2b3172011-09-26 01:56:30 +0000284 /// NumVirtualFunctionPointers - Contains the number of virtual function
285 /// pointers in the vtable for a given record decl.
286 llvm::DenseMap<const CXXRecordDecl *, uint64_t> NumVirtualFunctionPointers;
287
Anders Carlssondbd920c2009-10-11 22:13:54 +0000288 typedef std::pair<const CXXRecordDecl *,
289 const CXXRecordDecl *> ClassPairTy;
Benjamin Kramer39411b92009-11-26 13:09:03 +0000290
Anders Carlssonbba16072010-03-11 07:15:17 +0000291 /// VirtualBaseClassOffsetOffsets - Contains the vtable offset (relative to
Ken Dyck1a7f7522011-04-07 01:22:42 +0000292 /// the address point) in chars where the offsets for virtual bases of a class
Anders Carlssonbba16072010-03-11 07:15:17 +0000293 /// are stored.
Ken Dyck1a7f7522011-04-07 01:22:42 +0000294 typedef llvm::DenseMap<ClassPairTy, CharUnits>
Anders Carlssonbba16072010-03-11 07:15:17 +0000295 VirtualBaseClassOffsetOffsetsMapTy;
296 VirtualBaseClassOffsetOffsetsMapTy VirtualBaseClassOffsetOffsets;
Mike Stump380dd752009-11-10 07:44:33 +0000297
Peter Collingbourne84fcc482011-09-26 01:56:41 +0000298 typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy;
299
300 /// Thunks - Contains all thunks that a given method decl will need.
301 ThunksMapTy Thunks;
302
Peter Collingbourne1d2b3172011-09-26 01:56:30 +0000303 void ComputeMethodVTableIndices(const CXXRecordDecl *RD);
304
Peter Collingbourne84fcc482011-09-26 01:56:41 +0000305 /// ComputeVTableRelatedInformation - Compute and store all vtable related
306 /// information (vtable layout, vbase offset offsets, thunks etc) for the
307 /// given record decl.
308 void ComputeVTableRelatedInformation(const CXXRecordDecl *RD);
309
Peter Collingbourne1d2b3172011-09-26 01:56:30 +0000310public:
311 VTableContext(ASTContext &Context) : Context(Context) {}
Peter Collingbournee09cdf42011-09-26 01:56:50 +0000312 ~VTableContext();
Peter Collingbourne1d2b3172011-09-26 01:56:30 +0000313
Peter Collingbournee09cdf42011-09-26 01:56:50 +0000314 const VTableLayout &getVTableLayout(const CXXRecordDecl *RD) {
Peter Collingbourne84fcc482011-09-26 01:56:41 +0000315 ComputeVTableRelatedInformation(RD);
Peter Collingbournee09cdf42011-09-26 01:56:50 +0000316 assert(VTableLayouts.count(RD) && "No layout for this record decl!");
Peter Collingbourne84fcc482011-09-26 01:56:41 +0000317
Peter Collingbournee09cdf42011-09-26 01:56:50 +0000318 return *VTableLayouts[RD];
Peter Collingbourne84fcc482011-09-26 01:56:41 +0000319 }
320
Peter Collingbournee00fe692011-09-26 01:56:55 +0000321 VTableLayout *
322 createConstructionVTableLayout(const CXXRecordDecl *MostDerivedClass,
323 CharUnits MostDerivedClassOffset,
324 bool MostDerivedClassIsVirtual,
325 const CXXRecordDecl *LayoutClass);
326
Peter Collingbourne84fcc482011-09-26 01:56:41 +0000327 const ThunkInfoVectorTy *getThunkInfo(const CXXMethodDecl *MD) {
328 ComputeVTableRelatedInformation(MD->getParent());
329
330 ThunksMapTy::const_iterator I = Thunks.find(MD);
331 if (I == Thunks.end()) {
332 // We did not find a thunk for this method.
333 return 0;
334 }
335
336 return &I->second;
337 }
338
Peter Collingbourne1d2b3172011-09-26 01:56:30 +0000339 /// getNumVirtualFunctionPointers - Return the number of virtual function
340 /// pointers in the vtable for a given record decl.
341 uint64_t getNumVirtualFunctionPointers(const CXXRecordDecl *RD);
342
343 /// getMethodVTableIndex - Return the index (relative to the vtable address
344 /// point) where the function pointer for the given virtual function is
345 /// stored.
346 uint64_t getMethodVTableIndex(GlobalDecl GD);
347
348 /// getVirtualBaseOffsetOffset - Return the offset in chars (relative to the
349 /// vtable address point) where the offset of the virtual base that contains
350 /// the given base is stored, otherwise, if no virtual base contains the given
351 /// class, return 0. Base must be a virtual base class or an unambigious
352 /// base.
353 CharUnits getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
354 const CXXRecordDecl *VBase);
Peter Collingbourne1d2b3172011-09-26 01:56:30 +0000355};
356
357class CodeGenVTables {
358 CodeGenModule &CGM;
359
360 VTableContext VTContext;
361
Anders Carlsson046c2942010-04-17 20:15:18 +0000362 /// VTables - All the vtables which have been defined.
363 llvm::DenseMap<const CXXRecordDecl *, llvm::GlobalVariable *> VTables;
Anders Carlssond6b07fb2009-11-27 20:47:55 +0000364
Anders Carlsson2c822f12010-03-26 03:56:54 +0000365 /// VTableAddressPointsMapTy - Address points for a single vtable.
366 typedef llvm::DenseMap<BaseSubobject, uint64_t> VTableAddressPointsMapTy;
367
Peter Collingbourne84fcc482011-09-26 01:56:41 +0000368 typedef std::pair<const CXXRecordDecl *, BaseSubobject> BaseSubobjectPairTy;
Anders Carlsson3855a072010-05-03 00:55:11 +0000369 typedef llvm::DenseMap<BaseSubobjectPairTy, uint64_t> SubVTTIndiciesMapTy;
Anders Carlssone1dcc222010-03-26 04:23:58 +0000370
371 /// SubVTTIndicies - Contains indices into the various sub-VTTs.
372 SubVTTIndiciesMapTy SubVTTIndicies;
373
Anders Carlsson3855a072010-05-03 00:55:11 +0000374 typedef llvm::DenseMap<BaseSubobjectPairTy, uint64_t>
Anders Carlssone1dcc222010-03-26 04:23:58 +0000375 SecondaryVirtualPointerIndicesMapTy;
376
377 /// SecondaryVirtualPointerIndices - Contains the secondary virtual pointer
378 /// indices.
379 SecondaryVirtualPointerIndicesMapTy SecondaryVirtualPointerIndices;
Anders Carlssonc997d422010-01-02 01:01:18 +0000380
Anders Carlssonfbf6ed42010-03-23 16:36:50 +0000381 /// EmitThunk - Emit a single thunk.
Anders Carlsson14e82fd2011-02-06 18:31:40 +0000382 void EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk,
383 bool UseAvailableExternallyLinkage);
384
385 /// MaybeEmitThunkAvailableExternally - Try to emit the given thunk with
386 /// available_externally linkage to allow for inlining of thunks.
387 /// This will be done iff optimizations are enabled and the member function
388 /// doesn't contain any incomplete types.
389 void MaybeEmitThunkAvailableExternally(GlobalDecl GD, const ThunkInfo &Thunk);
390
Anders Carlsson0d1407e2010-03-25 15:26:28 +0000391 /// CreateVTableInitializer - Create a vtable initializer for the given record
392 /// decl.
393 /// \param Components - The vtable components; this is really an array of
394 /// VTableComponents.
395 llvm::Constant *CreateVTableInitializer(const CXXRecordDecl *RD,
Peter Collingbournee09cdf42011-09-26 01:56:50 +0000396 const VTableComponent *Components,
Anders Carlsson0d1407e2010-03-25 15:26:28 +0000397 unsigned NumComponents,
Peter Collingbournee09cdf42011-09-26 01:56:50 +0000398 const VTableLayout::VTableThunkTy *VTableThunks,
399 unsigned NumVTableThunks);
Anders Carlsson2c822f12010-03-26 03:56:54 +0000400
Anders Carlssondbd920c2009-10-11 22:13:54 +0000401public:
Peter Collingbourne1d2b3172011-09-26 01:56:30 +0000402 CodeGenVTables(CodeGenModule &CGM);
403
404 VTableContext &getVTableContext() { return VTContext; }
Anders Carlssondbd920c2009-10-11 22:13:54 +0000405
Argyrios Kyrtzidisd2c47bd2010-10-11 03:25:57 +0000406 /// \brief True if the VTable of this record must be emitted in the
407 /// translation unit.
408 bool ShouldEmitVTableInThisTU(const CXXRecordDecl *RD);
Rafael Espindolab8cab182010-04-19 00:44:22 +0000409
Anders Carlssonc997d422010-01-02 01:01:18 +0000410 /// needsVTTParameter - Return whether the given global decl needs a VTT
411 /// parameter, which it does if it's a base constructor or destructor with
412 /// virtual bases.
413 static bool needsVTTParameter(GlobalDecl GD);
414
415 /// getSubVTTIndex - Return the index of the sub-VTT for the base class of the
416 /// given record decl.
Anders Carlssonc11bb212010-05-02 23:53:25 +0000417 uint64_t getSubVTTIndex(const CXXRecordDecl *RD, BaseSubobject Base);
Anders Carlssonc997d422010-01-02 01:01:18 +0000418
Anders Carlssone1dcc222010-03-26 04:23:58 +0000419 /// getSecondaryVirtualPointerIndex - Return the index in the VTT where the
420 /// virtual pointer for the given subobject is located.
421 uint64_t getSecondaryVirtualPointerIndex(const CXXRecordDecl *RD,
422 BaseSubobject Base);
423
Anders Carlsson64c9eca2010-03-29 02:08:26 +0000424 /// getAddressPoint - Get the address point of the given subobject in the
425 /// class decl.
426 uint64_t getAddressPoint(BaseSubobject Base, const CXXRecordDecl *RD);
427
Anders Carlsson5eea8762010-03-24 05:32:05 +0000428 /// GetAddrOfVTable - Get the address of the vtable for the given record decl.
Anders Carlsson9dc338a2010-03-30 03:35:35 +0000429 llvm::GlobalVariable *GetAddrOfVTable(const CXXRecordDecl *RD);
Anders Carlsson5c6c1d92010-03-24 03:57:14 +0000430
Anders Carlssona7cde3b2010-03-29 03:38:52 +0000431 /// EmitVTableDefinition - Emit the definition of the given vtable.
432 void EmitVTableDefinition(llvm::GlobalVariable *VTable,
433 llvm::GlobalVariable::LinkageTypes Linkage,
434 const CXXRecordDecl *RD);
435
Anders Carlssonff143f82010-03-25 00:35:49 +0000436 /// GenerateConstructionVTable - Generate a construction vtable for the given
437 /// base subobject.
438 llvm::GlobalVariable *
439 GenerateConstructionVTable(const CXXRecordDecl *RD, const BaseSubobject &Base,
440 bool BaseIsVirtual,
John McCallbda0d6b2011-03-27 09:00:25 +0000441 llvm::GlobalVariable::LinkageTypes Linkage,
Anders Carlsson2c822f12010-03-26 03:56:54 +0000442 VTableAddressPointsMapTy& AddressPoints);
Anders Carlsson1cbce122011-01-29 19:16:51 +0000443
444
445 /// GetAddrOfVTable - Get the address of the VTT for the given record decl.
446 llvm::GlobalVariable *GetAddrOfVTT(const CXXRecordDecl *RD);
447
448 /// EmitVTTDefinition - Emit the definition of the given vtable.
449 void EmitVTTDefinition(llvm::GlobalVariable *VTT,
450 llvm::GlobalVariable::LinkageTypes Linkage,
451 const CXXRecordDecl *RD);
Rafael Espindolabbf58bb2010-03-10 02:19:29 +0000452
Douglas Gregor6fb745b2010-05-13 16:44:06 +0000453 /// EmitThunks - Emit the associated thunks for the given global decl.
454 void EmitThunks(GlobalDecl GD);
455
Anders Carlsson7986ad52010-03-23 18:18:41 +0000456 /// GenerateClassData - Generate all the class data required to be generated
Rafael Espindolabbf58bb2010-03-10 02:19:29 +0000457 /// upon definition of a KeyFunction. This includes the vtable, the
458 /// rtti data structure and the VTT.
459 ///
460 /// \param Linkage - The desired linkage of the vtable, the RTTI and the VTT.
461 void GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage,
462 const CXXRecordDecl *RD);
Anders Carlssondbd920c2009-10-11 22:13:54 +0000463};
Benjamin Kramer39411b92009-11-26 13:09:03 +0000464
Anders Carlsson1bb60992010-01-14 02:29:07 +0000465} // end namespace CodeGen
466} // end namespace clang
Anders Carlssondbd920c2009-10-11 22:13:54 +0000467#endif