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 = -1); 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 addPointerdBitCastOrAddrSpaceCast(llvm::Constant * value,llvm::Type * type)212 void addPointerdBitCastOrAddrSpaceCast(llvm::Constant *value, llvm::Type *type) { 213 add(llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast(value, type)); 214 } 215 216 /// Add a bunch of new values to this initializer. addAll(llvm::ArrayRef<llvm::Constant * > values)217 void addAll(llvm::ArrayRef<llvm::Constant *> values) { 218 assert(!Finished && "cannot add more values after finishing builder"); 219 assert(!Frozen && "cannot add values while subbuilder is active"); 220 Builder.Buffer.append(values.begin(), values.end()); 221 } 222 223 /// Add a relative offset to the given target address, i.e. the 224 /// static difference between the target address and the address 225 /// of the relative offset. The target must be known to be defined 226 /// in the current linkage unit. The offset will have the given 227 /// integer type, which must be no wider than intptr_t. Some 228 /// targets may not fully support this operation. addRelativeOffset(llvm::IntegerType * type,llvm::Constant * target)229 void addRelativeOffset(llvm::IntegerType *type, llvm::Constant *target) { 230 add(getRelativeOffset(type, target)); 231 } 232 233 /// Same as addRelativeOffset(), but instead relative to an element in this 234 /// aggregate, identified by its index. addRelativeOffsetToPosition(llvm::IntegerType * type,llvm::Constant * target,size_t position)235 void addRelativeOffsetToPosition(llvm::IntegerType *type, 236 llvm::Constant *target, size_t position) { 237 add(getRelativeOffsetToPosition(type, target, position)); 238 } 239 240 /// Add a relative offset to the target address, plus a small 241 /// constant offset. This is primarily useful when the relative 242 /// offset is known to be a multiple of (say) four and therefore 243 /// the tag can be used to express an extra two bits of information. addTaggedRelativeOffset(llvm::IntegerType * type,llvm::Constant * address,unsigned tag)244 void addTaggedRelativeOffset(llvm::IntegerType *type, 245 llvm::Constant *address, 246 unsigned tag) { 247 llvm::Constant *offset = getRelativeOffset(type, address); 248 if (tag) { 249 offset = llvm::ConstantExpr::getAdd(offset, 250 llvm::ConstantInt::get(type, tag)); 251 } 252 add(offset); 253 } 254 255 /// Return the offset from the start of the initializer to the 256 /// next position, assuming no padding is required prior to it. 257 /// 258 /// This operation will not succeed if any unsized placeholders are 259 /// currently in place in the initializer. getNextOffsetFromGlobal()260 CharUnits getNextOffsetFromGlobal() const { 261 assert(!Finished && "cannot add more values after finishing builder"); 262 assert(!Frozen && "cannot add values while subbuilder is active"); 263 return getOffsetFromGlobalTo(Builder.Buffer.size()); 264 } 265 266 /// An opaque class to hold the abstract position of a placeholder. 267 class PlaceholderPosition { 268 size_t Index; 269 friend class ConstantAggregateBuilderBase; PlaceholderPosition(size_t index)270 PlaceholderPosition(size_t index) : Index(index) {} 271 }; 272 273 /// Add a placeholder value to the structure. The returned position 274 /// can be used to set the value later; it will not be invalidated by 275 /// any intermediate operations except (1) filling the same position or 276 /// (2) finishing the entire builder. 277 /// 278 /// This is useful for emitting certain kinds of structure which 279 /// contain some sort of summary field, generally a count, before any 280 /// of the data. By emitting a placeholder first, the structure can 281 /// be emitted eagerly. addPlaceholder()282 PlaceholderPosition addPlaceholder() { 283 assert(!Finished && "cannot add more values after finishing builder"); 284 assert(!Frozen && "cannot add values while subbuilder is active"); 285 Builder.Buffer.push_back(nullptr); 286 return Builder.Buffer.size() - 1; 287 } 288 289 /// Add a placeholder, giving the expected type that will be filled in. 290 PlaceholderPosition addPlaceholderWithSize(llvm::Type *expectedType); 291 292 /// Fill a previously-added placeholder. 293 void fillPlaceholderWithInt(PlaceholderPosition position, 294 llvm::IntegerType *type, uint64_t value, 295 bool isSigned = false) { 296 fillPlaceholder(position, llvm::ConstantInt::get(type, value, isSigned)); 297 } 298 299 /// Fill a previously-added placeholder. fillPlaceholder(PlaceholderPosition position,llvm::Constant * value)300 void fillPlaceholder(PlaceholderPosition position, llvm::Constant *value) { 301 assert(!Finished && "cannot change values after finishing builder"); 302 assert(!Frozen && "cannot add values while subbuilder is active"); 303 llvm::Constant *&slot = Builder.Buffer[position.Index]; 304 assert(slot == nullptr && "placeholder already filled"); 305 slot = value; 306 } 307 308 /// Produce an address which will eventually point to the next 309 /// position to be filled. This is computed with an indexed 310 /// getelementptr rather than by computing offsets. 311 /// 312 /// The returned pointer will have type T*, where T is the given type. This 313 /// type can differ from the type of the actual element. 314 llvm::Constant *getAddrOfCurrentPosition(llvm::Type *type); 315 316 /// Produce an address which points to a position in the aggregate being 317 /// constructed. This is computed with an indexed getelementptr rather than by 318 /// computing offsets. 319 /// 320 /// The returned pointer will have type T*, where T is the given type. This 321 /// type can differ from the type of the actual element. 322 llvm::Constant *getAddrOfPosition(llvm::Type *type, size_t position); 323 getGEPIndicesToCurrentPosition(llvm::SmallVectorImpl<llvm::Constant * > & indices)324 llvm::ArrayRef<llvm::Constant*> getGEPIndicesToCurrentPosition( 325 llvm::SmallVectorImpl<llvm::Constant*> &indices) { 326 getGEPIndicesTo(indices, Builder.Buffer.size()); 327 return indices; 328 } 329 330 protected: 331 llvm::Constant *finishArray(llvm::Type *eltTy); 332 llvm::Constant *finishStruct(llvm::StructType *structTy); 333 334 private: 335 void getGEPIndicesTo(llvm::SmallVectorImpl<llvm::Constant*> &indices, 336 size_t position) const; 337 338 llvm::Constant *getRelativeOffset(llvm::IntegerType *offsetType, 339 llvm::Constant *target); 340 341 llvm::Constant *getRelativeOffsetToPosition(llvm::IntegerType *offsetType, 342 llvm::Constant *target, 343 size_t position); 344 345 CharUnits getOffsetFromGlobalTo(size_t index) const; 346 }; 347 348 template <class Impl, class Traits> 349 class ConstantAggregateBuilderTemplateBase 350 : public Traits::AggregateBuilderBase { 351 using super = typename Traits::AggregateBuilderBase; 352 public: 353 using InitBuilder = typename Traits::InitBuilder; 354 using ArrayBuilder = typename Traits::ArrayBuilder; 355 using StructBuilder = typename Traits::StructBuilder; 356 using AggregateBuilderBase = typename Traits::AggregateBuilderBase; 357 358 protected: ConstantAggregateBuilderTemplateBase(InitBuilder & builder,AggregateBuilderBase * parent)359 ConstantAggregateBuilderTemplateBase(InitBuilder &builder, 360 AggregateBuilderBase *parent) 361 : super(builder, parent) {} 362 asImpl()363 Impl &asImpl() { return *static_cast<Impl*>(this); } 364 365 public: 366 ArrayBuilder beginArray(llvm::Type *eltTy = nullptr) { 367 return ArrayBuilder(static_cast<InitBuilder&>(this->Builder), this, eltTy); 368 } 369 370 StructBuilder beginStruct(llvm::StructType *ty = nullptr) { 371 return StructBuilder(static_cast<InitBuilder&>(this->Builder), this, ty); 372 } 373 374 /// Given that this builder was created by beginning an array or struct 375 /// component on the given parent builder, finish the array/struct 376 /// component and add it to the parent. 377 /// 378 /// It is an intentional choice that the parent is passed in explicitly 379 /// despite it being redundant with information already kept in the 380 /// builder. This aids in readability by making it easier to find the 381 /// places that add components to a builder, as well as "bookending" 382 /// the sub-builder more explicitly. finishAndAddTo(AggregateBuilderBase & parent)383 void finishAndAddTo(AggregateBuilderBase &parent) { 384 assert(this->Parent == &parent && "adding to non-parent builder"); 385 parent.add(asImpl().finishImpl()); 386 } 387 388 /// Given that this builder was created by beginning an array or struct 389 /// directly on a ConstantInitBuilder, finish the array/struct and 390 /// create a global variable with it as the initializer. 391 template <class... As> finishAndCreateGlobal(As &&...args)392 llvm::GlobalVariable *finishAndCreateGlobal(As &&...args) { 393 assert(!this->Parent && "finishing non-root builder"); 394 return this->Builder.createGlobal(asImpl().finishImpl(), 395 std::forward<As>(args)...); 396 } 397 398 /// Given that this builder was created by beginning an array or struct 399 /// directly on a ConstantInitBuilder, finish the array/struct and 400 /// set it as the initializer of the given global variable. finishAndSetAsInitializer(llvm::GlobalVariable * global)401 void finishAndSetAsInitializer(llvm::GlobalVariable *global) { 402 assert(!this->Parent && "finishing non-root builder"); 403 return this->Builder.setGlobalInitializer(global, asImpl().finishImpl()); 404 } 405 406 /// Given that this builder was created by beginning an array or struct 407 /// directly on a ConstantInitBuilder, finish the array/struct and 408 /// return a future which can be used to install the initializer in 409 /// a global later. 410 /// 411 /// This is useful for allowing a finished initializer to passed to 412 /// an API which will build the global. However, the "future" preserves 413 /// a dependency on the original builder; it is an error to pass it aside. finishAndCreateFuture()414 ConstantInitFuture finishAndCreateFuture() { 415 assert(!this->Parent && "finishing non-root builder"); 416 return this->Builder.createFuture(asImpl().finishImpl()); 417 } 418 }; 419 420 template <class Traits> 421 class ConstantArrayBuilderTemplateBase 422 : public ConstantAggregateBuilderTemplateBase<typename Traits::ArrayBuilder, 423 Traits> { 424 using super = 425 ConstantAggregateBuilderTemplateBase<typename Traits::ArrayBuilder, Traits>; 426 427 public: 428 using InitBuilder = typename Traits::InitBuilder; 429 using AggregateBuilderBase = typename Traits::AggregateBuilderBase; 430 431 private: 432 llvm::Type *EltTy; 433 434 template <class, class> 435 friend class ConstantAggregateBuilderTemplateBase; 436 437 protected: ConstantArrayBuilderTemplateBase(InitBuilder & builder,AggregateBuilderBase * parent,llvm::Type * eltTy)438 ConstantArrayBuilderTemplateBase(InitBuilder &builder, 439 AggregateBuilderBase *parent, 440 llvm::Type *eltTy) 441 : super(builder, parent), EltTy(eltTy) {} 442 443 private: 444 /// Form an array constant from the values that have been added to this 445 /// builder. finishImpl()446 llvm::Constant *finishImpl() { 447 return AggregateBuilderBase::finishArray(EltTy); 448 } 449 }; 450 451 /// A template class designed to allow other frontends to 452 /// easily customize the builder classes used by ConstantInitBuilder, 453 /// and thus to extend the API to work with the abstractions they 454 /// prefer. This would probably not be necessary if C++ just 455 /// supported extension methods. 456 template <class Traits> 457 class ConstantStructBuilderTemplateBase 458 : public ConstantAggregateBuilderTemplateBase<typename Traits::StructBuilder, 459 Traits> { 460 using super = 461 ConstantAggregateBuilderTemplateBase<typename Traits::StructBuilder,Traits>; 462 463 public: 464 using InitBuilder = typename Traits::InitBuilder; 465 using AggregateBuilderBase = typename Traits::AggregateBuilderBase; 466 467 private: 468 llvm::StructType *StructTy; 469 470 template <class, class> 471 friend class ConstantAggregateBuilderTemplateBase; 472 473 protected: ConstantStructBuilderTemplateBase(InitBuilder & builder,AggregateBuilderBase * parent,llvm::StructType * structTy)474 ConstantStructBuilderTemplateBase(InitBuilder &builder, 475 AggregateBuilderBase *parent, 476 llvm::StructType *structTy) 477 : super(builder, parent), StructTy(structTy) { 478 if (structTy) this->Packed = structTy->isPacked(); 479 } 480 481 public: setPacked(bool packed)482 void setPacked(bool packed) { 483 this->Packed = packed; 484 } 485 486 /// Use the given type for the struct if its element count is correct. 487 /// Don't add more elements after calling this. suggestType(llvm::StructType * structTy)488 void suggestType(llvm::StructType *structTy) { 489 if (this->size() == structTy->getNumElements()) { 490 StructTy = structTy; 491 } 492 } 493 494 private: 495 /// Form an array constant from the values that have been added to this 496 /// builder. finishImpl()497 llvm::Constant *finishImpl() { 498 return AggregateBuilderBase::finishStruct(StructTy); 499 } 500 }; 501 502 /// A template class designed to allow other frontends to 503 /// easily customize the builder classes used by ConstantInitBuilder, 504 /// and thus to extend the API to work with the abstractions they 505 /// prefer. This would probably not be necessary if C++ just 506 /// supported extension methods. 507 template <class Traits> 508 class ConstantInitBuilderTemplateBase : public ConstantInitBuilderBase { 509 protected: ConstantInitBuilderTemplateBase(CodeGenModule & CGM)510 ConstantInitBuilderTemplateBase(CodeGenModule &CGM) 511 : ConstantInitBuilderBase(CGM) {} 512 513 public: 514 using InitBuilder = typename Traits::InitBuilder; 515 using ArrayBuilder = typename Traits::ArrayBuilder; 516 using StructBuilder = typename Traits::StructBuilder; 517 518 ArrayBuilder beginArray(llvm::Type *eltTy = nullptr) { 519 return ArrayBuilder(static_cast<InitBuilder&>(*this), nullptr, eltTy); 520 } 521 522 StructBuilder beginStruct(llvm::StructType *structTy = nullptr) { 523 return StructBuilder(static_cast<InitBuilder&>(*this), nullptr, structTy); 524 } 525 }; 526 527 class ConstantInitBuilder; 528 class ConstantStructBuilder; 529 class ConstantArrayBuilder; 530 531 struct ConstantInitBuilderTraits { 532 using InitBuilder = ConstantInitBuilder; 533 using AggregateBuilderBase = ConstantAggregateBuilderBase; 534 using ArrayBuilder = ConstantArrayBuilder; 535 using StructBuilder = ConstantStructBuilder; 536 }; 537 538 /// The standard implementation of ConstantInitBuilder used in Clang. 539 class ConstantInitBuilder 540 : public ConstantInitBuilderTemplateBase<ConstantInitBuilderTraits> { 541 public: ConstantInitBuilder(CodeGenModule & CGM)542 explicit ConstantInitBuilder(CodeGenModule &CGM) : 543 ConstantInitBuilderTemplateBase(CGM) {} 544 }; 545 546 /// A helper class of ConstantInitBuilder, used for building constant 547 /// array initializers. 548 class ConstantArrayBuilder 549 : public ConstantArrayBuilderTemplateBase<ConstantInitBuilderTraits> { 550 template <class Traits> 551 friend class ConstantInitBuilderTemplateBase; 552 553 // The use of explicit qualification is a GCC workaround. 554 template <class Impl, class Traits> 555 friend class CodeGen::ConstantAggregateBuilderTemplateBase; 556 ConstantArrayBuilder(ConstantInitBuilder & builder,ConstantAggregateBuilderBase * parent,llvm::Type * eltTy)557 ConstantArrayBuilder(ConstantInitBuilder &builder, 558 ConstantAggregateBuilderBase *parent, 559 llvm::Type *eltTy) 560 : ConstantArrayBuilderTemplateBase(builder, parent, eltTy) {} 561 }; 562 563 /// A helper class of ConstantInitBuilder, used for building constant 564 /// struct initializers. 565 class ConstantStructBuilder 566 : public ConstantStructBuilderTemplateBase<ConstantInitBuilderTraits> { 567 template <class Traits> 568 friend class ConstantInitBuilderTemplateBase; 569 570 // The use of explicit qualification is a GCC workaround. 571 template <class Impl, class Traits> 572 friend class CodeGen::ConstantAggregateBuilderTemplateBase; 573 ConstantStructBuilder(ConstantInitBuilder & builder,ConstantAggregateBuilderBase * parent,llvm::StructType * structTy)574 ConstantStructBuilder(ConstantInitBuilder &builder, 575 ConstantAggregateBuilderBase *parent, 576 llvm::StructType *structTy) 577 : ConstantStructBuilderTemplateBase(builder, parent, structTy) {} 578 }; 579 580 } // end namespace CodeGen 581 } // end namespace clang 582 583 #endif 584