Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:36:52

0001 //===- ConstantInitBuilder.h - Builder for LLVM IR constants ----*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 // This class provides a convenient interface for building complex
0010 // global initializers of the sort that are frequently required for
0011 // language ABIs.
0012 //
0013 //===----------------------------------------------------------------------===//
0014 
0015 #ifndef LLVM_CLANG_CODEGEN_CONSTANTINITBUILDER_H
0016 #define LLVM_CLANG_CODEGEN_CONSTANTINITBUILDER_H
0017 
0018 #include "llvm/ADT/ArrayRef.h"
0019 #include "llvm/ADT/SmallVector.h"
0020 #include "llvm/IR/Constants.h"
0021 #include "llvm/IR/GlobalValue.h"
0022 #include "clang/AST/CharUnits.h"
0023 #include "clang/CodeGen/ConstantInitFuture.h"
0024 
0025 #include <vector>
0026 
0027 namespace clang {
0028 class GlobalDecl;
0029 class PointerAuthSchema;
0030 class QualType;
0031 
0032 namespace CodeGen {
0033 class CodeGenModule;
0034 
0035 /// A convenience builder class for complex constant initializers,
0036 /// especially for anonymous global structures used by various language
0037 /// runtimes.
0038 ///
0039 /// The basic usage pattern is expected to be something like:
0040 ///    ConstantInitBuilder builder(CGM);
0041 ///    auto toplevel = builder.beginStruct();
0042 ///    toplevel.addInt(CGM.SizeTy, widgets.size());
0043 ///    auto widgetArray = builder.beginArray();
0044 ///    for (auto &widget : widgets) {
0045 ///      auto widgetDesc = widgetArray.beginStruct();
0046 ///      widgetDesc.addInt(CGM.SizeTy, widget.getPower());
0047 ///      widgetDesc.add(CGM.GetAddrOfConstantStringFromLiteral(widget.getName()));
0048 ///      widgetDesc.add(CGM.GetAddrOfGlobal(widget.getInitializerDecl()));
0049 ///      widgetDesc.finishAndAddTo(widgetArray);
0050 ///    }
0051 ///    widgetArray.finishAndAddTo(toplevel);
0052 ///    auto global = toplevel.finishAndCreateGlobal("WIDGET_LIST", Align,
0053 ///                                                 /*constant*/ true);
0054 class ConstantInitBuilderBase {
0055   struct SelfReference {
0056     llvm::GlobalVariable *Dummy;
0057     llvm::SmallVector<llvm::Constant*, 4> Indices;
0058 
0059     SelfReference(llvm::GlobalVariable *dummy) : Dummy(dummy) {}
0060   };
0061   CodeGenModule &CGM;
0062   llvm::SmallVector<llvm::Constant*, 16> Buffer;
0063   std::vector<SelfReference> SelfReferences;
0064   bool Frozen = false;
0065 
0066   friend class ConstantInitFuture;
0067   friend class ConstantAggregateBuilderBase;
0068   template <class, class>
0069   friend class ConstantAggregateBuilderTemplateBase;
0070 
0071 protected:
0072   explicit ConstantInitBuilderBase(CodeGenModule &CGM) : CGM(CGM) {}
0073 
0074   ~ConstantInitBuilderBase() {
0075     assert(Buffer.empty() && "didn't claim all values out of buffer");
0076     assert(SelfReferences.empty() && "didn't apply all self-references");
0077   }
0078 
0079 private:
0080   llvm::GlobalVariable *createGlobal(llvm::Constant *initializer,
0081                                      const llvm::Twine &name,
0082                                      CharUnits alignment,
0083                                      bool constant = false,
0084                                      llvm::GlobalValue::LinkageTypes linkage
0085                                        = llvm::GlobalValue::InternalLinkage,
0086                                      unsigned addressSpace = 0);
0087 
0088   ConstantInitFuture createFuture(llvm::Constant *initializer);
0089 
0090   void setGlobalInitializer(llvm::GlobalVariable *GV,
0091                             llvm::Constant *initializer);
0092 
0093   void resolveSelfReferences(llvm::GlobalVariable *GV);
0094 
0095   void abandon(size_t newEnd);
0096 };
0097 
0098 /// A concrete base class for struct and array aggregate
0099 /// initializer builders.
0100 class ConstantAggregateBuilderBase {
0101 protected:
0102   ConstantInitBuilderBase &Builder;
0103   ConstantAggregateBuilderBase *Parent;
0104   size_t Begin;
0105   mutable size_t CachedOffsetEnd = 0;
0106   bool Finished = false;
0107   bool Frozen = false;
0108   bool Packed = false;
0109   mutable CharUnits CachedOffsetFromGlobal;
0110 
0111   llvm::SmallVectorImpl<llvm::Constant*> &getBuffer() {
0112     return Builder.Buffer;
0113   }
0114 
0115   const llvm::SmallVectorImpl<llvm::Constant*> &getBuffer() const {
0116     return Builder.Buffer;
0117   }
0118 
0119   ConstantAggregateBuilderBase(ConstantInitBuilderBase &builder,
0120                                ConstantAggregateBuilderBase *parent)
0121       : Builder(builder), Parent(parent), Begin(builder.Buffer.size()) {
0122     if (parent) {
0123       assert(!parent->Frozen && "parent already has child builder active");
0124       parent->Frozen = true;
0125     } else {
0126       assert(!builder.Frozen && "builder already has child builder active");
0127       builder.Frozen = true;
0128     }
0129   }
0130 
0131   ~ConstantAggregateBuilderBase() {
0132     assert(Finished && "didn't finish aggregate builder");
0133   }
0134 
0135   void markFinished() {
0136     assert(!Frozen && "child builder still active");
0137     assert(!Finished && "builder already finished");
0138     Finished = true;
0139     if (Parent) {
0140       assert(Parent->Frozen &&
0141              "parent not frozen while child builder active");
0142       Parent->Frozen = false;
0143     } else {
0144       assert(Builder.Frozen &&
0145              "builder not frozen while child builder active");
0146       Builder.Frozen = false;
0147     }
0148   }
0149 
0150 public:
0151   // Not copyable.
0152   ConstantAggregateBuilderBase(const ConstantAggregateBuilderBase &) = delete;
0153   ConstantAggregateBuilderBase &operator=(const ConstantAggregateBuilderBase &)
0154     = delete;
0155 
0156   // Movable, mostly to allow returning.  But we have to write this out
0157   // properly to satisfy the assert in the destructor.
0158   ConstantAggregateBuilderBase(ConstantAggregateBuilderBase &&other)
0159     : Builder(other.Builder), Parent(other.Parent), Begin(other.Begin),
0160       CachedOffsetEnd(other.CachedOffsetEnd),
0161       Finished(other.Finished), Frozen(other.Frozen), Packed(other.Packed),
0162       CachedOffsetFromGlobal(other.CachedOffsetFromGlobal) {
0163     other.Finished = true;
0164   }
0165   ConstantAggregateBuilderBase &operator=(ConstantAggregateBuilderBase &&other)
0166     = delete;
0167 
0168   /// Return the number of elements that have been added to
0169   /// this struct or array.
0170   size_t size() const {
0171     assert(!this->Finished && "cannot query after finishing builder");
0172     assert(!this->Frozen && "cannot query while sub-builder is active");
0173     assert(this->Begin <= this->getBuffer().size());
0174     return this->getBuffer().size() - this->Begin;
0175   }
0176 
0177   /// Return true if no elements have yet been added to this struct or array.
0178   bool empty() const {
0179     return size() == 0;
0180   }
0181 
0182   /// Abandon this builder completely.
0183   void abandon() {
0184     markFinished();
0185     Builder.abandon(Begin);
0186   }
0187 
0188   /// Add a new value to this initializer.
0189   void add(llvm::Constant *value) {
0190     assert(value && "adding null value to constant initializer");
0191     assert(!Finished && "cannot add more values after finishing builder");
0192     assert(!Frozen && "cannot add values while subbuilder is active");
0193     Builder.Buffer.push_back(value);
0194   }
0195 
0196   /// Add an integer value of type size_t.
0197   void addSize(CharUnits size);
0198 
0199   /// Add an integer value of a specific type.
0200   void addInt(llvm::IntegerType *intTy, uint64_t value,
0201               bool isSigned = false) {
0202     add(llvm::ConstantInt::get(intTy, value, isSigned));
0203   }
0204 
0205   /// Add a signed pointer using the given pointer authentication schema.
0206   void addSignedPointer(llvm::Constant *Pointer,
0207                         const PointerAuthSchema &Schema, GlobalDecl CalleeDecl,
0208                         QualType CalleeType);
0209 
0210   /// Add a null pointer of a specific type.
0211   void addNullPointer(llvm::PointerType *ptrTy) {
0212     add(llvm::ConstantPointerNull::get(ptrTy));
0213   }
0214 
0215   /// Add a bunch of new values to this initializer.
0216   void addAll(llvm::ArrayRef<llvm::Constant *> values) {
0217     assert(!Finished && "cannot add more values after finishing builder");
0218     assert(!Frozen && "cannot add values while subbuilder is active");
0219     Builder.Buffer.append(values.begin(), values.end());
0220   }
0221 
0222   /// Add a relative offset to the given target address, i.e. the
0223   /// static difference between the target address and the address
0224   /// of the relative offset.  The target must be known to be defined
0225   /// in the current linkage unit.  The offset will have the given
0226   /// integer type, which must be no wider than intptr_t.  Some
0227   /// targets may not fully support this operation.
0228   void addRelativeOffset(llvm::IntegerType *type, llvm::Constant *target) {
0229     add(getRelativeOffset(type, target));
0230   }
0231 
0232   /// Same as addRelativeOffset(), but instead relative to an element in this
0233   /// aggregate, identified by its index.
0234   void addRelativeOffsetToPosition(llvm::IntegerType *type,
0235                                    llvm::Constant *target, size_t position) {
0236     add(getRelativeOffsetToPosition(type, target, position));
0237   }
0238 
0239   /// Add a relative offset to the target address, plus a small
0240   /// constant offset.  This is primarily useful when the relative
0241   /// offset is known to be a multiple of (say) four and therefore
0242   /// the tag can be used to express an extra two bits of information.
0243   void addTaggedRelativeOffset(llvm::IntegerType *type,
0244                                llvm::Constant *address,
0245                                unsigned tag) {
0246     llvm::Constant *offset = getRelativeOffset(type, address);
0247     if (tag) {
0248       offset = llvm::ConstantExpr::getAdd(offset,
0249                                           llvm::ConstantInt::get(type, tag));
0250     }
0251     add(offset);
0252   }
0253 
0254   /// Return the offset from the start of the initializer to the
0255   /// next position, assuming no padding is required prior to it.
0256   ///
0257   /// This operation will not succeed if any unsized placeholders are
0258   /// currently in place in the initializer.
0259   CharUnits getNextOffsetFromGlobal() const {
0260     assert(!Finished && "cannot add more values after finishing builder");
0261     assert(!Frozen && "cannot add values while subbuilder is active");
0262     return getOffsetFromGlobalTo(Builder.Buffer.size());
0263   }
0264 
0265   /// An opaque class to hold the abstract position of a placeholder.
0266   class PlaceholderPosition {
0267     size_t Index;
0268     friend class ConstantAggregateBuilderBase;
0269     PlaceholderPosition(size_t index) : Index(index) {}
0270   };
0271 
0272   /// Add a placeholder value to the structure.  The returned position
0273   /// can be used to set the value later; it will not be invalidated by
0274   /// any intermediate operations except (1) filling the same position or
0275   /// (2) finishing the entire builder.
0276   ///
0277   /// This is useful for emitting certain kinds of structure which
0278   /// contain some sort of summary field, generally a count, before any
0279   /// of the data.  By emitting a placeholder first, the structure can
0280   /// be emitted eagerly.
0281   PlaceholderPosition addPlaceholder() {
0282     assert(!Finished && "cannot add more values after finishing builder");
0283     assert(!Frozen && "cannot add values while subbuilder is active");
0284     Builder.Buffer.push_back(nullptr);
0285     return Builder.Buffer.size() - 1;
0286   }
0287 
0288   /// Add a placeholder, giving the expected type that will be filled in.
0289   PlaceholderPosition addPlaceholderWithSize(llvm::Type *expectedType);
0290 
0291   /// Fill a previously-added placeholder.
0292   void fillPlaceholderWithInt(PlaceholderPosition position,
0293                               llvm::IntegerType *type, uint64_t value,
0294                               bool isSigned = false) {
0295     fillPlaceholder(position, llvm::ConstantInt::get(type, value, isSigned));
0296   }
0297 
0298   /// Fill a previously-added placeholder.
0299   void fillPlaceholder(PlaceholderPosition position, llvm::Constant *value) {
0300     assert(!Finished && "cannot change values after finishing builder");
0301     assert(!Frozen && "cannot add values while subbuilder is active");
0302     llvm::Constant *&slot = Builder.Buffer[position.Index];
0303     assert(slot == nullptr && "placeholder already filled");
0304     slot = value;
0305   }
0306 
0307   /// Produce an address which will eventually point to the next
0308   /// position to be filled.  This is computed with an indexed
0309   /// getelementptr rather than by computing offsets.
0310   ///
0311   /// The returned pointer will have type T*, where T is the given type. This
0312   /// type can differ from the type of the actual element.
0313   llvm::Constant *getAddrOfCurrentPosition(llvm::Type *type);
0314 
0315   /// Produce an address which points to a position in the aggregate being
0316   /// constructed. This is computed with an indexed getelementptr rather than by
0317   /// computing offsets.
0318   ///
0319   /// The returned pointer will have type T*, where T is the given type. This
0320   /// type can differ from the type of the actual element.
0321   llvm::Constant *getAddrOfPosition(llvm::Type *type, size_t position);
0322 
0323   llvm::ArrayRef<llvm::Constant*> getGEPIndicesToCurrentPosition(
0324                            llvm::SmallVectorImpl<llvm::Constant*> &indices) {
0325     getGEPIndicesTo(indices, Builder.Buffer.size());
0326     return indices;
0327   }
0328 
0329 protected:
0330   llvm::Constant *finishArray(llvm::Type *eltTy);
0331   llvm::Constant *finishStruct(llvm::StructType *structTy);
0332 
0333 private:
0334   void getGEPIndicesTo(llvm::SmallVectorImpl<llvm::Constant*> &indices,
0335                        size_t position) const;
0336 
0337   llvm::Constant *getRelativeOffset(llvm::IntegerType *offsetType,
0338                                     llvm::Constant *target);
0339 
0340   llvm::Constant *getRelativeOffsetToPosition(llvm::IntegerType *offsetType,
0341                                               llvm::Constant *target,
0342                                               size_t position);
0343 
0344   CharUnits getOffsetFromGlobalTo(size_t index) const;
0345 };
0346 
0347 template <class Impl, class Traits>
0348 class ConstantAggregateBuilderTemplateBase
0349     : public Traits::AggregateBuilderBase {
0350   using super = typename Traits::AggregateBuilderBase;
0351 public:
0352   using InitBuilder = typename Traits::InitBuilder;
0353   using ArrayBuilder = typename Traits::ArrayBuilder;
0354   using StructBuilder = typename Traits::StructBuilder;
0355   using AggregateBuilderBase = typename Traits::AggregateBuilderBase;
0356 
0357 protected:
0358   ConstantAggregateBuilderTemplateBase(InitBuilder &builder,
0359                                        AggregateBuilderBase *parent)
0360     : super(builder, parent) {}
0361 
0362   Impl &asImpl() { return *static_cast<Impl*>(this); }
0363 
0364 public:
0365   ArrayBuilder beginArray(llvm::Type *eltTy = nullptr) {
0366     return ArrayBuilder(static_cast<InitBuilder&>(this->Builder), this, eltTy);
0367   }
0368 
0369   StructBuilder beginStruct(llvm::StructType *ty = nullptr) {
0370     return StructBuilder(static_cast<InitBuilder&>(this->Builder), this, ty);
0371   }
0372 
0373   /// Given that this builder was created by beginning an array or struct
0374   /// component on the given parent builder, finish the array/struct
0375   /// component and add it to the parent.
0376   ///
0377   /// It is an intentional choice that the parent is passed in explicitly
0378   /// despite it being redundant with information already kept in the
0379   /// builder.  This aids in readability by making it easier to find the
0380   /// places that add components to a builder, as well as "bookending"
0381   /// the sub-builder more explicitly.
0382   void finishAndAddTo(AggregateBuilderBase &parent) {
0383     assert(this->Parent == &parent && "adding to non-parent builder");
0384     parent.add(asImpl().finishImpl());
0385   }
0386 
0387   /// Given that this builder was created by beginning an array or struct
0388   /// directly on a ConstantInitBuilder, finish the array/struct and
0389   /// create a global variable with it as the initializer.
0390   template <class... As>
0391   llvm::GlobalVariable *finishAndCreateGlobal(As &&...args) {
0392     assert(!this->Parent && "finishing non-root builder");
0393     return this->Builder.createGlobal(asImpl().finishImpl(),
0394                                       std::forward<As>(args)...);
0395   }
0396 
0397   /// Given that this builder was created by beginning an array or struct
0398   /// directly on a ConstantInitBuilder, finish the array/struct and
0399   /// set it as the initializer of the given global variable.
0400   void finishAndSetAsInitializer(llvm::GlobalVariable *global) {
0401     assert(!this->Parent && "finishing non-root builder");
0402     return this->Builder.setGlobalInitializer(global, asImpl().finishImpl());
0403   }
0404 
0405   /// Given that this builder was created by beginning an array or struct
0406   /// directly on a ConstantInitBuilder, finish the array/struct and
0407   /// return a future which can be used to install the initializer in
0408   /// a global later.
0409   ///
0410   /// This is useful for allowing a finished initializer to passed to
0411   /// an API which will build the global.  However, the "future" preserves
0412   /// a dependency on the original builder; it is an error to pass it aside.
0413   ConstantInitFuture finishAndCreateFuture() {
0414     assert(!this->Parent && "finishing non-root builder");
0415     return this->Builder.createFuture(asImpl().finishImpl());
0416   }
0417 };
0418 
0419 template <class Traits>
0420 class ConstantArrayBuilderTemplateBase
0421   : public ConstantAggregateBuilderTemplateBase<typename Traits::ArrayBuilder,
0422                                                 Traits> {
0423   using super =
0424     ConstantAggregateBuilderTemplateBase<typename Traits::ArrayBuilder, Traits>;
0425 
0426 public:
0427   using InitBuilder = typename Traits::InitBuilder;
0428   using AggregateBuilderBase = typename Traits::AggregateBuilderBase;
0429 
0430 private:
0431   llvm::Type *EltTy;
0432 
0433   template <class, class>
0434   friend class ConstantAggregateBuilderTemplateBase;
0435 
0436 protected:
0437   ConstantArrayBuilderTemplateBase(InitBuilder &builder,
0438                                    AggregateBuilderBase *parent,
0439                                    llvm::Type *eltTy)
0440     : super(builder, parent), EltTy(eltTy) {}
0441 
0442 private:
0443   /// Form an array constant from the values that have been added to this
0444   /// builder.
0445   llvm::Constant *finishImpl() {
0446     return AggregateBuilderBase::finishArray(EltTy);
0447   }
0448 };
0449 
0450 /// A template class designed to allow other frontends to
0451 /// easily customize the builder classes used by ConstantInitBuilder,
0452 /// and thus to extend the API to work with the abstractions they
0453 /// prefer.  This would probably not be necessary if C++ just
0454 /// supported extension methods.
0455 template <class Traits>
0456 class ConstantStructBuilderTemplateBase
0457   : public ConstantAggregateBuilderTemplateBase<typename Traits::StructBuilder,
0458                                                 Traits> {
0459   using super =
0460     ConstantAggregateBuilderTemplateBase<typename Traits::StructBuilder,Traits>;
0461 
0462 public:
0463   using InitBuilder = typename Traits::InitBuilder;
0464   using AggregateBuilderBase = typename Traits::AggregateBuilderBase;
0465 
0466 private:
0467   llvm::StructType *StructTy;
0468 
0469   template <class, class>
0470   friend class ConstantAggregateBuilderTemplateBase;
0471 
0472 protected:
0473   ConstantStructBuilderTemplateBase(InitBuilder &builder,
0474                                     AggregateBuilderBase *parent,
0475                                     llvm::StructType *structTy)
0476     : super(builder, parent), StructTy(structTy) {
0477     if (structTy) this->Packed = structTy->isPacked();
0478   }
0479 
0480 public:
0481   void setPacked(bool packed) {
0482     this->Packed = packed;
0483   }
0484 
0485   /// Use the given type for the struct if its element count is correct.
0486   /// Don't add more elements after calling this.
0487   void suggestType(llvm::StructType *structTy) {
0488     if (this->size() == structTy->getNumElements()) {
0489       StructTy = structTy;
0490     }
0491   }
0492 
0493 private:
0494   /// Form an array constant from the values that have been added to this
0495   /// builder.
0496   llvm::Constant *finishImpl() {
0497     return AggregateBuilderBase::finishStruct(StructTy);
0498   }
0499 };
0500 
0501 /// A template class designed to allow other frontends to
0502 /// easily customize the builder classes used by ConstantInitBuilder,
0503 /// and thus to extend the API to work with the abstractions they
0504 /// prefer.  This would probably not be necessary if C++ just
0505 /// supported extension methods.
0506 template <class Traits>
0507 class ConstantInitBuilderTemplateBase : public ConstantInitBuilderBase {
0508 protected:
0509   ConstantInitBuilderTemplateBase(CodeGenModule &CGM)
0510     : ConstantInitBuilderBase(CGM) {}
0511 
0512 public:
0513   using InitBuilder = typename Traits::InitBuilder;
0514   using ArrayBuilder = typename Traits::ArrayBuilder;
0515   using StructBuilder = typename Traits::StructBuilder;
0516 
0517   ArrayBuilder beginArray(llvm::Type *eltTy = nullptr) {
0518     return ArrayBuilder(static_cast<InitBuilder&>(*this), nullptr, eltTy);
0519   }
0520 
0521   StructBuilder beginStruct(llvm::StructType *structTy = nullptr) {
0522     return StructBuilder(static_cast<InitBuilder&>(*this), nullptr, structTy);
0523   }
0524 };
0525 
0526 class ConstantInitBuilder;
0527 class ConstantStructBuilder;
0528 class ConstantArrayBuilder;
0529 
0530 struct ConstantInitBuilderTraits {
0531   using InitBuilder = ConstantInitBuilder;
0532   using AggregateBuilderBase = ConstantAggregateBuilderBase;
0533   using ArrayBuilder = ConstantArrayBuilder;
0534   using StructBuilder = ConstantStructBuilder;
0535 };
0536 
0537 /// The standard implementation of ConstantInitBuilder used in Clang.
0538 class ConstantInitBuilder
0539     : public ConstantInitBuilderTemplateBase<ConstantInitBuilderTraits> {
0540 public:
0541   explicit ConstantInitBuilder(CodeGenModule &CGM) :
0542     ConstantInitBuilderTemplateBase(CGM) {}
0543 };
0544 
0545 /// A helper class of ConstantInitBuilder, used for building constant
0546 /// array initializers.
0547 class ConstantArrayBuilder
0548     : public ConstantArrayBuilderTemplateBase<ConstantInitBuilderTraits> {
0549   template <class Traits>
0550   friend class ConstantInitBuilderTemplateBase;
0551 
0552   // The use of explicit qualification is a GCC workaround.
0553   template <class Impl, class Traits>
0554   friend class CodeGen::ConstantAggregateBuilderTemplateBase;
0555 
0556   ConstantArrayBuilder(ConstantInitBuilder &builder,
0557                        ConstantAggregateBuilderBase *parent,
0558                        llvm::Type *eltTy)
0559     : ConstantArrayBuilderTemplateBase(builder, parent, eltTy) {}
0560 };
0561 
0562 /// A helper class of ConstantInitBuilder, used for building constant
0563 /// struct initializers.
0564 class ConstantStructBuilder
0565     : public ConstantStructBuilderTemplateBase<ConstantInitBuilderTraits> {
0566   template <class Traits>
0567   friend class ConstantInitBuilderTemplateBase;
0568 
0569   // The use of explicit qualification is a GCC workaround.
0570   template <class Impl, class Traits>
0571   friend class CodeGen::ConstantAggregateBuilderTemplateBase;
0572 
0573   ConstantStructBuilder(ConstantInitBuilder &builder,
0574                         ConstantAggregateBuilderBase *parent,
0575                         llvm::StructType *structTy)
0576     : ConstantStructBuilderTemplateBase(builder, parent, structTy) {}
0577 };
0578 
0579 }  // end namespace CodeGen
0580 }  // end namespace clang
0581 
0582 #endif