xref: /freebsd/contrib/llvm-project/clang/include/clang/CodeGen/ConstantInitBuilder.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1 //===- ConstantInitBuilder.h - Builder for LLVM IR constants ----*- C++ -*-===//
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 // This class provides a convenient interface for building complex
10 // global initializers of the sort that are frequently required for
11 // language ABIs.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #ifndef LLVM_CLANG_CODEGEN_CONSTANTINITBUILDER_H
16 #define LLVM_CLANG_CODEGEN_CONSTANTINITBUILDER_H
17 
18 #include "llvm/ADT/ArrayRef.h"
19 #include "llvm/ADT/SmallVector.h"
20 #include "llvm/IR/Constants.h"
21 #include "llvm/IR/GlobalValue.h"
22 #include "clang/AST/CharUnits.h"
23 #include "clang/CodeGen/ConstantInitFuture.h"
24 
25 #include <vector>
26 
27 namespace clang {
28 class GlobalDecl;
29 class PointerAuthSchema;
30 class QualType;
31 
32 namespace CodeGen {
33 class CodeGenModule;
34 
35 /// A convenience builder class for complex constant initializers,
36 /// especially for anonymous global structures used by various language
37 /// runtimes.
38 ///
39 /// The basic usage pattern is expected to be something like:
40 ///    ConstantInitBuilder builder(CGM);
41 ///    auto toplevel = builder.beginStruct();
42 ///    toplevel.addInt(CGM.SizeTy, widgets.size());
43 ///    auto widgetArray = builder.beginArray();
44 ///    for (auto &widget : widgets) {
45 ///      auto widgetDesc = widgetArray.beginStruct();
46 ///      widgetDesc.addInt(CGM.SizeTy, widget.getPower());
47 ///      widgetDesc.add(CGM.GetAddrOfConstantStringFromLiteral(widget.getName()));
48 ///      widgetDesc.add(CGM.GetAddrOfGlobal(widget.getInitializerDecl()));
49 ///      widgetDesc.finishAndAddTo(widgetArray);
50 ///    }
51 ///    widgetArray.finishAndAddTo(toplevel);
52 ///    auto global = toplevel.finishAndCreateGlobal("WIDGET_LIST", Align,
53 ///                                                 /*constant*/ true);
54 class ConstantInitBuilderBase {
55   struct SelfReference {
56     llvm::GlobalVariable *Dummy;
57     llvm::SmallVector<llvm::Constant*, 4> Indices;
58 
SelfReferenceSelfReference59     SelfReference(llvm::GlobalVariable *dummy) : Dummy(dummy) {}
60   };
61   CodeGenModule &CGM;
62   llvm::SmallVector<llvm::Constant*, 16> Buffer;
63   std::vector<SelfReference> SelfReferences;
64   bool Frozen = false;
65 
66   friend class ConstantInitFuture;
67   friend class ConstantAggregateBuilderBase;
68   template <class, class>
69   friend class ConstantAggregateBuilderTemplateBase;
70 
71 protected:
ConstantInitBuilderBase(CodeGenModule & CGM)72   explicit ConstantInitBuilderBase(CodeGenModule &CGM) : CGM(CGM) {}
73 
~ConstantInitBuilderBase()74   ~ConstantInitBuilderBase() {
75     assert(Buffer.empty() && "didn't claim all values out of buffer");
76     assert(SelfReferences.empty() && "didn't apply all self-references");
77   }
78 
79 private:
80   llvm::GlobalVariable *createGlobal(llvm::Constant *initializer,
81                                      const llvm::Twine &name,
82                                      CharUnits alignment,
83                                      bool constant = false,
84                                      llvm::GlobalValue::LinkageTypes linkage
85                                        = llvm::GlobalValue::InternalLinkage,
86                                      unsigned addressSpace = 0);
87 
88   ConstantInitFuture createFuture(llvm::Constant *initializer);
89 
90   void setGlobalInitializer(llvm::GlobalVariable *GV,
91                             llvm::Constant *initializer);
92 
93   void resolveSelfReferences(llvm::GlobalVariable *GV);
94 
95   void abandon(size_t newEnd);
96 };
97 
98 /// A concrete base class for struct and array aggregate
99 /// initializer builders.
100 class ConstantAggregateBuilderBase {
101 protected:
102   ConstantInitBuilderBase &Builder;
103   ConstantAggregateBuilderBase *Parent;
104   size_t Begin;
105   mutable size_t CachedOffsetEnd = 0;
106   bool Finished = false;
107   bool Frozen = false;
108   bool Packed = false;
109   mutable CharUnits CachedOffsetFromGlobal;
110 
getBuffer()111   llvm::SmallVectorImpl<llvm::Constant*> &getBuffer() {
112     return Builder.Buffer;
113   }
114 
getBuffer()115   const llvm::SmallVectorImpl<llvm::Constant*> &getBuffer() const {
116     return Builder.Buffer;
117   }
118 
ConstantAggregateBuilderBase(ConstantInitBuilderBase & builder,ConstantAggregateBuilderBase * parent)119   ConstantAggregateBuilderBase(ConstantInitBuilderBase &builder,
120                                ConstantAggregateBuilderBase *parent)
121       : Builder(builder), Parent(parent), Begin(builder.Buffer.size()) {
122     if (parent) {
123       assert(!parent->Frozen && "parent already has child builder active");
124       parent->Frozen = true;
125     } else {
126       assert(!builder.Frozen && "builder already has child builder active");
127       builder.Frozen = true;
128     }
129   }
130 
~ConstantAggregateBuilderBase()131   ~ConstantAggregateBuilderBase() {
132     assert(Finished && "didn't finish aggregate builder");
133   }
134 
markFinished()135   void markFinished() {
136     assert(!Frozen && "child builder still active");
137     assert(!Finished && "builder already finished");
138     Finished = true;
139     if (Parent) {
140       assert(Parent->Frozen &&
141              "parent not frozen while child builder active");
142       Parent->Frozen = false;
143     } else {
144       assert(Builder.Frozen &&
145              "builder not frozen while child builder active");
146       Builder.Frozen = false;
147     }
148   }
149 
150 public:
151   // Not copyable.
152   ConstantAggregateBuilderBase(const ConstantAggregateBuilderBase &) = delete;
153   ConstantAggregateBuilderBase &operator=(const ConstantAggregateBuilderBase &)
154     = delete;
155 
156   // Movable, mostly to allow returning.  But we have to write this out
157   // properly to satisfy the assert in the destructor.
ConstantAggregateBuilderBase(ConstantAggregateBuilderBase && other)158   ConstantAggregateBuilderBase(ConstantAggregateBuilderBase &&other)
159     : Builder(other.Builder), Parent(other.Parent), Begin(other.Begin),
160       CachedOffsetEnd(other.CachedOffsetEnd),
161       Finished(other.Finished), Frozen(other.Frozen), Packed(other.Packed),
162       CachedOffsetFromGlobal(other.CachedOffsetFromGlobal) {
163     other.Finished = true;
164   }
165   ConstantAggregateBuilderBase &operator=(ConstantAggregateBuilderBase &&other)
166     = delete;
167 
168   /// Return the number of elements that have been added to
169   /// this struct or array.
size()170   size_t size() const {
171     assert(!this->Finished && "cannot query after finishing builder");
172     assert(!this->Frozen && "cannot query while sub-builder is active");
173     assert(this->Begin <= this->getBuffer().size());
174     return this->getBuffer().size() - this->Begin;
175   }
176 
177   /// Return true if no elements have yet been added to this struct or array.
empty()178   bool empty() const {
179     return size() == 0;
180   }
181 
182   /// Abandon this builder completely.
abandon()183   void abandon() {
184     markFinished();
185     Builder.abandon(Begin);
186   }
187 
188   /// Add a new value to this initializer.
add(llvm::Constant * value)189   void add(llvm::Constant *value) {
190     assert(value && "adding null value to constant initializer");
191     assert(!Finished && "cannot add more values after finishing builder");
192     assert(!Frozen && "cannot add values while subbuilder is active");
193     Builder.Buffer.push_back(value);
194   }
195 
196   /// Add an integer value of type size_t.
197   void addSize(CharUnits size);
198 
199   /// Add an integer value of a specific type.
200   void addInt(llvm::IntegerType *intTy, uint64_t value,
201               bool isSigned = false) {
202     add(llvm::ConstantInt::get(intTy, value, isSigned));
203   }
204 
205   /// Add a signed pointer using the given pointer authentication schema.
206   void addSignedPointer(llvm::Constant *Pointer,
207                         const PointerAuthSchema &Schema, GlobalDecl CalleeDecl,
208                         QualType CalleeType);
209 
210   /// Add a null pointer of a specific type.
addNullPointer(llvm::PointerType * ptrTy)211   void addNullPointer(llvm::PointerType *ptrTy) {
212     add(llvm::ConstantPointerNull::get(ptrTy));
213   }
214 
215   /// Add a bunch of new values to this initializer.
addAll(llvm::ArrayRef<llvm::Constant * > values)216   void addAll(llvm::ArrayRef<llvm::Constant *> values) {
217     assert(!Finished && "cannot add more values after finishing builder");
218     assert(!Frozen && "cannot add values while subbuilder is active");
219     Builder.Buffer.append(values.begin(), values.end());
220   }
221 
222   /// Add a relative offset to the given target address, i.e. the
223   /// static difference between the target address and the address
224   /// of the relative offset.  The target must be known to be defined
225   /// in the current linkage unit.  The offset will have the given
226   /// integer type, which must be no wider than intptr_t.  Some
227   /// targets may not fully support this operation.
addRelativeOffset(llvm::IntegerType * type,llvm::Constant * target)228   void addRelativeOffset(llvm::IntegerType *type, llvm::Constant *target) {
229     add(getRelativeOffset(type, target));
230   }
231 
232   /// Same as addRelativeOffset(), but instead relative to an element in this
233   /// aggregate, identified by its index.
addRelativeOffsetToPosition(llvm::IntegerType * type,llvm::Constant * target,size_t position)234   void addRelativeOffsetToPosition(llvm::IntegerType *type,
235                                    llvm::Constant *target, size_t position) {
236     add(getRelativeOffsetToPosition(type, target, position));
237   }
238 
239   /// Add a relative offset to the target address, plus a small
240   /// constant offset.  This is primarily useful when the relative
241   /// offset is known to be a multiple of (say) four and therefore
242   /// the tag can be used to express an extra two bits of information.
addTaggedRelativeOffset(llvm::IntegerType * type,llvm::Constant * address,unsigned tag)243   void addTaggedRelativeOffset(llvm::IntegerType *type,
244                                llvm::Constant *address,
245                                unsigned tag) {
246     llvm::Constant *offset = getRelativeOffset(type, address);
247     if (tag) {
248       offset = llvm::ConstantExpr::getAdd(offset,
249                                           llvm::ConstantInt::get(type, tag));
250     }
251     add(offset);
252   }
253 
254   /// Return the offset from the start of the initializer to the
255   /// next position, assuming no padding is required prior to it.
256   ///
257   /// This operation will not succeed if any unsized placeholders are
258   /// currently in place in the initializer.
getNextOffsetFromGlobal()259   CharUnits getNextOffsetFromGlobal() const {
260     assert(!Finished && "cannot add more values after finishing builder");
261     assert(!Frozen && "cannot add values while subbuilder is active");
262     return getOffsetFromGlobalTo(Builder.Buffer.size());
263   }
264 
265   /// An opaque class to hold the abstract position of a placeholder.
266   class PlaceholderPosition {
267     size_t Index;
268     friend class ConstantAggregateBuilderBase;
PlaceholderPosition(size_t index)269     PlaceholderPosition(size_t index) : Index(index) {}
270   };
271 
272   /// Add a placeholder value to the structure.  The returned position
273   /// can be used to set the value later; it will not be invalidated by
274   /// any intermediate operations except (1) filling the same position or
275   /// (2) finishing the entire builder.
276   ///
277   /// This is useful for emitting certain kinds of structure which
278   /// contain some sort of summary field, generally a count, before any
279   /// of the data.  By emitting a placeholder first, the structure can
280   /// be emitted eagerly.
addPlaceholder()281   PlaceholderPosition addPlaceholder() {
282     assert(!Finished && "cannot add more values after finishing builder");
283     assert(!Frozen && "cannot add values while subbuilder is active");
284     Builder.Buffer.push_back(nullptr);
285     return Builder.Buffer.size() - 1;
286   }
287 
288   /// Add a placeholder, giving the expected type that will be filled in.
289   PlaceholderPosition addPlaceholderWithSize(llvm::Type *expectedType);
290 
291   /// Fill a previously-added placeholder.
292   void fillPlaceholderWithInt(PlaceholderPosition position,
293                               llvm::IntegerType *type, uint64_t value,
294                               bool isSigned = false) {
295     fillPlaceholder(position, llvm::ConstantInt::get(type, value, isSigned));
296   }
297 
298   /// Fill a previously-added placeholder.
fillPlaceholder(PlaceholderPosition position,llvm::Constant * value)299   void fillPlaceholder(PlaceholderPosition position, llvm::Constant *value) {
300     assert(!Finished && "cannot change values after finishing builder");
301     assert(!Frozen && "cannot add values while subbuilder is active");
302     llvm::Constant *&slot = Builder.Buffer[position.Index];
303     assert(slot == nullptr && "placeholder already filled");
304     slot = value;
305   }
306 
307   /// Produce an address which will eventually point to the next
308   /// position to be filled.  This is computed with an indexed
309   /// getelementptr rather than by computing offsets.
310   ///
311   /// The returned pointer will have type T*, where T is the given type. This
312   /// type can differ from the type of the actual element.
313   llvm::Constant *getAddrOfCurrentPosition(llvm::Type *type);
314 
315   /// Produce an address which points to a position in the aggregate being
316   /// constructed. This is computed with an indexed getelementptr rather than by
317   /// computing offsets.
318   ///
319   /// The returned pointer will have type T*, where T is the given type. This
320   /// type can differ from the type of the actual element.
321   llvm::Constant *getAddrOfPosition(llvm::Type *type, size_t position);
322 
getGEPIndicesToCurrentPosition(llvm::SmallVectorImpl<llvm::Constant * > & indices)323   llvm::ArrayRef<llvm::Constant*> getGEPIndicesToCurrentPosition(
324                            llvm::SmallVectorImpl<llvm::Constant*> &indices) {
325     getGEPIndicesTo(indices, Builder.Buffer.size());
326     return indices;
327   }
328 
329 protected:
330   llvm::Constant *finishArray(llvm::Type *eltTy);
331   llvm::Constant *finishStruct(llvm::StructType *structTy);
332 
333 private:
334   void getGEPIndicesTo(llvm::SmallVectorImpl<llvm::Constant*> &indices,
335                        size_t position) const;
336 
337   llvm::Constant *getRelativeOffset(llvm::IntegerType *offsetType,
338                                     llvm::Constant *target);
339 
340   llvm::Constant *getRelativeOffsetToPosition(llvm::IntegerType *offsetType,
341                                               llvm::Constant *target,
342                                               size_t position);
343 
344   CharUnits getOffsetFromGlobalTo(size_t index) const;
345 };
346 
347 template <class Impl, class Traits>
348 class ConstantAggregateBuilderTemplateBase
349     : public Traits::AggregateBuilderBase {
350   using super = typename Traits::AggregateBuilderBase;
351 public:
352   using InitBuilder = typename Traits::InitBuilder;
353   using ArrayBuilder = typename Traits::ArrayBuilder;
354   using StructBuilder = typename Traits::StructBuilder;
355   using AggregateBuilderBase = typename Traits::AggregateBuilderBase;
356 
357 protected:
ConstantAggregateBuilderTemplateBase(InitBuilder & builder,AggregateBuilderBase * parent)358   ConstantAggregateBuilderTemplateBase(InitBuilder &builder,
359                                        AggregateBuilderBase *parent)
360     : super(builder, parent) {}
361 
asImpl()362   Impl &asImpl() { return *static_cast<Impl*>(this); }
363 
364 public:
365   ArrayBuilder beginArray(llvm::Type *eltTy = nullptr) {
366     return ArrayBuilder(static_cast<InitBuilder&>(this->Builder), this, eltTy);
367   }
368 
369   StructBuilder beginStruct(llvm::StructType *ty = nullptr) {
370     return StructBuilder(static_cast<InitBuilder&>(this->Builder), this, ty);
371   }
372 
373   /// Given that this builder was created by beginning an array or struct
374   /// component on the given parent builder, finish the array/struct
375   /// component and add it to the parent.
376   ///
377   /// It is an intentional choice that the parent is passed in explicitly
378   /// despite it being redundant with information already kept in the
379   /// builder.  This aids in readability by making it easier to find the
380   /// places that add components to a builder, as well as "bookending"
381   /// the sub-builder more explicitly.
finishAndAddTo(AggregateBuilderBase & parent)382   void finishAndAddTo(AggregateBuilderBase &parent) {
383     assert(this->Parent == &parent && "adding to non-parent builder");
384     parent.add(asImpl().finishImpl());
385   }
386 
387   /// Given that this builder was created by beginning an array or struct
388   /// directly on a ConstantInitBuilder, finish the array/struct and
389   /// create a global variable with it as the initializer.
390   template <class... As>
finishAndCreateGlobal(As &&...args)391   llvm::GlobalVariable *finishAndCreateGlobal(As &&...args) {
392     assert(!this->Parent && "finishing non-root builder");
393     return this->Builder.createGlobal(asImpl().finishImpl(),
394                                       std::forward<As>(args)...);
395   }
396 
397   /// Given that this builder was created by beginning an array or struct
398   /// directly on a ConstantInitBuilder, finish the array/struct and
399   /// set it as the initializer of the given global variable.
finishAndSetAsInitializer(llvm::GlobalVariable * global)400   void finishAndSetAsInitializer(llvm::GlobalVariable *global) {
401     assert(!this->Parent && "finishing non-root builder");
402     return this->Builder.setGlobalInitializer(global, asImpl().finishImpl());
403   }
404 
405   /// Given that this builder was created by beginning an array or struct
406   /// directly on a ConstantInitBuilder, finish the array/struct and
407   /// return a future which can be used to install the initializer in
408   /// a global later.
409   ///
410   /// This is useful for allowing a finished initializer to passed to
411   /// an API which will build the global.  However, the "future" preserves
412   /// a dependency on the original builder; it is an error to pass it aside.
finishAndCreateFuture()413   ConstantInitFuture finishAndCreateFuture() {
414     assert(!this->Parent && "finishing non-root builder");
415     return this->Builder.createFuture(asImpl().finishImpl());
416   }
417 };
418 
419 template <class Traits>
420 class ConstantArrayBuilderTemplateBase
421   : public ConstantAggregateBuilderTemplateBase<typename Traits::ArrayBuilder,
422                                                 Traits> {
423   using super =
424     ConstantAggregateBuilderTemplateBase<typename Traits::ArrayBuilder, Traits>;
425 
426 public:
427   using InitBuilder = typename Traits::InitBuilder;
428   using AggregateBuilderBase = typename Traits::AggregateBuilderBase;
429 
430 private:
431   llvm::Type *EltTy;
432 
433   template <class, class>
434   friend class ConstantAggregateBuilderTemplateBase;
435 
436 protected:
ConstantArrayBuilderTemplateBase(InitBuilder & builder,AggregateBuilderBase * parent,llvm::Type * eltTy)437   ConstantArrayBuilderTemplateBase(InitBuilder &builder,
438                                    AggregateBuilderBase *parent,
439                                    llvm::Type *eltTy)
440     : super(builder, parent), EltTy(eltTy) {}
441 
442 private:
443   /// Form an array constant from the values that have been added to this
444   /// builder.
finishImpl()445   llvm::Constant *finishImpl() {
446     return AggregateBuilderBase::finishArray(EltTy);
447   }
448 };
449 
450 /// A template class designed to allow other frontends to
451 /// easily customize the builder classes used by ConstantInitBuilder,
452 /// and thus to extend the API to work with the abstractions they
453 /// prefer.  This would probably not be necessary if C++ just
454 /// supported extension methods.
455 template <class Traits>
456 class ConstantStructBuilderTemplateBase
457   : public ConstantAggregateBuilderTemplateBase<typename Traits::StructBuilder,
458                                                 Traits> {
459   using super =
460     ConstantAggregateBuilderTemplateBase<typename Traits::StructBuilder,Traits>;
461 
462 public:
463   using InitBuilder = typename Traits::InitBuilder;
464   using AggregateBuilderBase = typename Traits::AggregateBuilderBase;
465 
466 private:
467   llvm::StructType *StructTy;
468 
469   template <class, class>
470   friend class ConstantAggregateBuilderTemplateBase;
471 
472 protected:
ConstantStructBuilderTemplateBase(InitBuilder & builder,AggregateBuilderBase * parent,llvm::StructType * structTy)473   ConstantStructBuilderTemplateBase(InitBuilder &builder,
474                                     AggregateBuilderBase *parent,
475                                     llvm::StructType *structTy)
476     : super(builder, parent), StructTy(structTy) {
477     if (structTy) this->Packed = structTy->isPacked();
478   }
479 
480 public:
setPacked(bool packed)481   void setPacked(bool packed) {
482     this->Packed = packed;
483   }
484 
485   /// Use the given type for the struct if its element count is correct.
486   /// Don't add more elements after calling this.
suggestType(llvm::StructType * structTy)487   void suggestType(llvm::StructType *structTy) {
488     if (this->size() == structTy->getNumElements()) {
489       StructTy = structTy;
490     }
491   }
492 
493 private:
494   /// Form an array constant from the values that have been added to this
495   /// builder.
finishImpl()496   llvm::Constant *finishImpl() {
497     return AggregateBuilderBase::finishStruct(StructTy);
498   }
499 };
500 
501 /// A template class designed to allow other frontends to
502 /// easily customize the builder classes used by ConstantInitBuilder,
503 /// and thus to extend the API to work with the abstractions they
504 /// prefer.  This would probably not be necessary if C++ just
505 /// supported extension methods.
506 template <class Traits>
507 class ConstantInitBuilderTemplateBase : public ConstantInitBuilderBase {
508 protected:
ConstantInitBuilderTemplateBase(CodeGenModule & CGM)509   ConstantInitBuilderTemplateBase(CodeGenModule &CGM)
510     : ConstantInitBuilderBase(CGM) {}
511 
512 public:
513   using InitBuilder = typename Traits::InitBuilder;
514   using ArrayBuilder = typename Traits::ArrayBuilder;
515   using StructBuilder = typename Traits::StructBuilder;
516 
517   ArrayBuilder beginArray(llvm::Type *eltTy = nullptr) {
518     return ArrayBuilder(static_cast<InitBuilder&>(*this), nullptr, eltTy);
519   }
520 
521   StructBuilder beginStruct(llvm::StructType *structTy = nullptr) {
522     return StructBuilder(static_cast<InitBuilder&>(*this), nullptr, structTy);
523   }
524 };
525 
526 class ConstantInitBuilder;
527 class ConstantStructBuilder;
528 class ConstantArrayBuilder;
529 
530 struct ConstantInitBuilderTraits {
531   using InitBuilder = ConstantInitBuilder;
532   using AggregateBuilderBase = ConstantAggregateBuilderBase;
533   using ArrayBuilder = ConstantArrayBuilder;
534   using StructBuilder = ConstantStructBuilder;
535 };
536 
537 /// The standard implementation of ConstantInitBuilder used in Clang.
538 class ConstantInitBuilder
539     : public ConstantInitBuilderTemplateBase<ConstantInitBuilderTraits> {
540 public:
ConstantInitBuilder(CodeGenModule & CGM)541   explicit ConstantInitBuilder(CodeGenModule &CGM) :
542     ConstantInitBuilderTemplateBase(CGM) {}
543 };
544 
545 /// A helper class of ConstantInitBuilder, used for building constant
546 /// array initializers.
547 class ConstantArrayBuilder
548     : public ConstantArrayBuilderTemplateBase<ConstantInitBuilderTraits> {
549   template <class Traits>
550   friend class ConstantInitBuilderTemplateBase;
551 
552   // The use of explicit qualification is a GCC workaround.
553   template <class Impl, class Traits>
554   friend class CodeGen::ConstantAggregateBuilderTemplateBase;
555 
ConstantArrayBuilder(ConstantInitBuilder & builder,ConstantAggregateBuilderBase * parent,llvm::Type * eltTy)556   ConstantArrayBuilder(ConstantInitBuilder &builder,
557                        ConstantAggregateBuilderBase *parent,
558                        llvm::Type *eltTy)
559     : ConstantArrayBuilderTemplateBase(builder, parent, eltTy) {}
560 };
561 
562 /// A helper class of ConstantInitBuilder, used for building constant
563 /// struct initializers.
564 class ConstantStructBuilder
565     : public ConstantStructBuilderTemplateBase<ConstantInitBuilderTraits> {
566   template <class Traits>
567   friend class ConstantInitBuilderTemplateBase;
568 
569   // The use of explicit qualification is a GCC workaround.
570   template <class Impl, class Traits>
571   friend class CodeGen::ConstantAggregateBuilderTemplateBase;
572 
ConstantStructBuilder(ConstantInitBuilder & builder,ConstantAggregateBuilderBase * parent,llvm::StructType * structTy)573   ConstantStructBuilder(ConstantInitBuilder &builder,
574                         ConstantAggregateBuilderBase *parent,
575                         llvm::StructType *structTy)
576     : ConstantStructBuilderTemplateBase(builder, parent, structTy) {}
577 };
578 
579 }  // end namespace CodeGen
580 }  // end namespace clang
581 
582 #endif
583