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