ExternalASTSource.h 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===- ExternalASTSource.h - Abstract External AST Interface ----*- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. //
  14. // This file defines the ExternalASTSource interface, which enables
  15. // construction of AST nodes from some external source.
  16. //
  17. //===----------------------------------------------------------------------===//
  18. #ifndef LLVM_CLANG_AST_EXTERNALASTSOURCE_H
  19. #define LLVM_CLANG_AST_EXTERNALASTSOURCE_H
  20. #include "clang/AST/CharUnits.h"
  21. #include "clang/AST/DeclBase.h"
  22. #include "clang/Basic/LLVM.h"
  23. #include "llvm/ADT/ArrayRef.h"
  24. #include "llvm/ADT/DenseMap.h"
  25. #include "llvm/ADT/IntrusiveRefCntPtr.h"
  26. #include "llvm/ADT/Optional.h"
  27. #include "llvm/ADT/PointerUnion.h"
  28. #include "llvm/ADT/STLExtras.h"
  29. #include "llvm/ADT/SmallVector.h"
  30. #include "llvm/ADT/iterator.h"
  31. #include "llvm/Support/PointerLikeTypeTraits.h"
  32. #include <cassert>
  33. #include <cstddef>
  34. #include <cstdint>
  35. #include <iterator>
  36. #include <utility>
  37. namespace clang {
  38. class ASTConsumer;
  39. class ASTContext;
  40. class ASTSourceDescriptor;
  41. class CXXBaseSpecifier;
  42. class CXXCtorInitializer;
  43. class CXXRecordDecl;
  44. class DeclarationName;
  45. class FieldDecl;
  46. class IdentifierInfo;
  47. class NamedDecl;
  48. class ObjCInterfaceDecl;
  49. class RecordDecl;
  50. class Selector;
  51. class Stmt;
  52. class TagDecl;
  53. /// Abstract interface for external sources of AST nodes.
  54. ///
  55. /// External AST sources provide AST nodes constructed from some
  56. /// external source, such as a precompiled header. External AST
  57. /// sources can resolve types and declarations from abstract IDs into
  58. /// actual type and declaration nodes, and read parts of declaration
  59. /// contexts.
  60. class ExternalASTSource : public RefCountedBase<ExternalASTSource> {
  61. friend class ExternalSemaSource;
  62. /// Generation number for this external AST source. Must be increased
  63. /// whenever we might have added new redeclarations for existing decls.
  64. uint32_t CurrentGeneration = 0;
  65. /// LLVM-style RTTI.
  66. static char ID;
  67. public:
  68. ExternalASTSource() = default;
  69. virtual ~ExternalASTSource();
  70. /// RAII class for safely pairing a StartedDeserializing call
  71. /// with FinishedDeserializing.
  72. class Deserializing {
  73. ExternalASTSource *Source;
  74. public:
  75. explicit Deserializing(ExternalASTSource *source) : Source(source) {
  76. assert(Source);
  77. Source->StartedDeserializing();
  78. }
  79. ~Deserializing() {
  80. Source->FinishedDeserializing();
  81. }
  82. };
  83. /// Get the current generation of this AST source. This number
  84. /// is incremented each time the AST source lazily extends an existing
  85. /// entity.
  86. uint32_t getGeneration() const { return CurrentGeneration; }
  87. /// Resolve a declaration ID into a declaration, potentially
  88. /// building a new declaration.
  89. ///
  90. /// This method only needs to be implemented if the AST source ever
  91. /// passes back decl sets as VisibleDeclaration objects.
  92. ///
  93. /// The default implementation of this method is a no-op.
  94. virtual Decl *GetExternalDecl(uint32_t ID);
  95. /// Resolve a selector ID into a selector.
  96. ///
  97. /// This operation only needs to be implemented if the AST source
  98. /// returns non-zero for GetNumKnownSelectors().
  99. ///
  100. /// The default implementation of this method is a no-op.
  101. virtual Selector GetExternalSelector(uint32_t ID);
  102. /// Returns the number of selectors known to the external AST
  103. /// source.
  104. ///
  105. /// The default implementation of this method is a no-op.
  106. virtual uint32_t GetNumExternalSelectors();
  107. /// Resolve the offset of a statement in the decl stream into
  108. /// a statement.
  109. ///
  110. /// This operation is meant to be used via a LazyOffsetPtr. It only
  111. /// needs to be implemented if the AST source uses methods like
  112. /// FunctionDecl::setLazyBody when building decls.
  113. ///
  114. /// The default implementation of this method is a no-op.
  115. virtual Stmt *GetExternalDeclStmt(uint64_t Offset);
  116. /// Resolve the offset of a set of C++ constructor initializers in
  117. /// the decl stream into an array of initializers.
  118. ///
  119. /// The default implementation of this method is a no-op.
  120. virtual CXXCtorInitializer **GetExternalCXXCtorInitializers(uint64_t Offset);
  121. /// Resolve the offset of a set of C++ base specifiers in the decl
  122. /// stream into an array of specifiers.
  123. ///
  124. /// The default implementation of this method is a no-op.
  125. virtual CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset);
  126. /// Update an out-of-date identifier.
  127. virtual void updateOutOfDateIdentifier(IdentifierInfo &II) {}
  128. /// Find all declarations with the given name in the given context,
  129. /// and add them to the context by calling SetExternalVisibleDeclsForName
  130. /// or SetNoExternalVisibleDeclsForName.
  131. /// \return \c true if any declarations might have been found, \c false if
  132. /// we definitely have no declarations with tbis name.
  133. ///
  134. /// The default implementation of this method is a no-op returning \c false.
  135. virtual bool
  136. FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name);
  137. /// Ensures that the table of all visible declarations inside this
  138. /// context is up to date.
  139. ///
  140. /// The default implementation of this function is a no-op.
  141. virtual void completeVisibleDeclsMap(const DeclContext *DC);
  142. /// Retrieve the module that corresponds to the given module ID.
  143. virtual Module *getModule(unsigned ID) { return nullptr; }
  144. /// Return a descriptor for the corresponding module, if one exists.
  145. virtual llvm::Optional<ASTSourceDescriptor> getSourceDescriptor(unsigned ID);
  146. enum ExtKind { EK_Always, EK_Never, EK_ReplyHazy };
  147. virtual ExtKind hasExternalDefinitions(const Decl *D);
  148. /// Finds all declarations lexically contained within the given
  149. /// DeclContext, after applying an optional filter predicate.
  150. ///
  151. /// \param IsKindWeWant a predicate function that returns true if the passed
  152. /// declaration kind is one we are looking for.
  153. ///
  154. /// The default implementation of this method is a no-op.
  155. virtual void
  156. FindExternalLexicalDecls(const DeclContext *DC,
  157. llvm::function_ref<bool(Decl::Kind)> IsKindWeWant,
  158. SmallVectorImpl<Decl *> &Result);
  159. /// Finds all declarations lexically contained within the given
  160. /// DeclContext.
  161. void FindExternalLexicalDecls(const DeclContext *DC,
  162. SmallVectorImpl<Decl *> &Result) {
  163. FindExternalLexicalDecls(DC, [](Decl::Kind) { return true; }, Result);
  164. }
  165. /// Get the decls that are contained in a file in the Offset/Length
  166. /// range. \p Length can be 0 to indicate a point at \p Offset instead of
  167. /// a range.
  168. virtual void FindFileRegionDecls(FileID File, unsigned Offset,
  169. unsigned Length,
  170. SmallVectorImpl<Decl *> &Decls);
  171. /// Gives the external AST source an opportunity to complete
  172. /// the redeclaration chain for a declaration. Called each time we
  173. /// need the most recent declaration of a declaration after the
  174. /// generation count is incremented.
  175. virtual void CompleteRedeclChain(const Decl *D);
  176. /// Gives the external AST source an opportunity to complete
  177. /// an incomplete type.
  178. virtual void CompleteType(TagDecl *Tag);
  179. /// Gives the external AST source an opportunity to complete an
  180. /// incomplete Objective-C class.
  181. ///
  182. /// This routine will only be invoked if the "externally completed" bit is
  183. /// set on the ObjCInterfaceDecl via the function
  184. /// \c ObjCInterfaceDecl::setExternallyCompleted().
  185. virtual void CompleteType(ObjCInterfaceDecl *Class);
  186. /// Loads comment ranges.
  187. virtual void ReadComments();
  188. /// Notify ExternalASTSource that we started deserialization of
  189. /// a decl or type so until FinishedDeserializing is called there may be
  190. /// decls that are initializing. Must be paired with FinishedDeserializing.
  191. ///
  192. /// The default implementation of this method is a no-op.
  193. virtual void StartedDeserializing();
  194. /// Notify ExternalASTSource that we finished the deserialization of
  195. /// a decl or type. Must be paired with StartedDeserializing.
  196. ///
  197. /// The default implementation of this method is a no-op.
  198. virtual void FinishedDeserializing();
  199. /// Function that will be invoked when we begin parsing a new
  200. /// translation unit involving this external AST source.
  201. ///
  202. /// The default implementation of this method is a no-op.
  203. virtual void StartTranslationUnit(ASTConsumer *Consumer);
  204. /// Print any statistics that have been gathered regarding
  205. /// the external AST source.
  206. ///
  207. /// The default implementation of this method is a no-op.
  208. virtual void PrintStats();
  209. /// Perform layout on the given record.
  210. ///
  211. /// This routine allows the external AST source to provide an specific
  212. /// layout for a record, overriding the layout that would normally be
  213. /// constructed. It is intended for clients who receive specific layout
  214. /// details rather than source code (such as LLDB). The client is expected
  215. /// to fill in the field offsets, base offsets, virtual base offsets, and
  216. /// complete object size.
  217. ///
  218. /// \param Record The record whose layout is being requested.
  219. ///
  220. /// \param Size The final size of the record, in bits.
  221. ///
  222. /// \param Alignment The final alignment of the record, in bits.
  223. ///
  224. /// \param FieldOffsets The offset of each of the fields within the record,
  225. /// expressed in bits. All of the fields must be provided with offsets.
  226. ///
  227. /// \param BaseOffsets The offset of each of the direct, non-virtual base
  228. /// classes. If any bases are not given offsets, the bases will be laid
  229. /// out according to the ABI.
  230. ///
  231. /// \param VirtualBaseOffsets The offset of each of the virtual base classes
  232. /// (either direct or not). If any bases are not given offsets, the bases will be laid
  233. /// out according to the ABI.
  234. ///
  235. /// \returns true if the record layout was provided, false otherwise.
  236. virtual bool layoutRecordType(
  237. const RecordDecl *Record, uint64_t &Size, uint64_t &Alignment,
  238. llvm::DenseMap<const FieldDecl *, uint64_t> &FieldOffsets,
  239. llvm::DenseMap<const CXXRecordDecl *, CharUnits> &BaseOffsets,
  240. llvm::DenseMap<const CXXRecordDecl *, CharUnits> &VirtualBaseOffsets);
  241. //===--------------------------------------------------------------------===//
  242. // Queries for performance analysis.
  243. //===--------------------------------------------------------------------===//
  244. struct MemoryBufferSizes {
  245. size_t malloc_bytes;
  246. size_t mmap_bytes;
  247. MemoryBufferSizes(size_t malloc_bytes, size_t mmap_bytes)
  248. : malloc_bytes(malloc_bytes), mmap_bytes(mmap_bytes) {}
  249. };
  250. /// Return the amount of memory used by memory buffers, breaking down
  251. /// by heap-backed versus mmap'ed memory.
  252. MemoryBufferSizes getMemoryBufferSizes() const {
  253. MemoryBufferSizes sizes(0, 0);
  254. getMemoryBufferSizes(sizes);
  255. return sizes;
  256. }
  257. virtual void getMemoryBufferSizes(MemoryBufferSizes &sizes) const;
  258. /// LLVM-style RTTI.
  259. /// \{
  260. virtual bool isA(const void *ClassID) const { return ClassID == &ID; }
  261. static bool classof(const ExternalASTSource *S) { return S->isA(&ID); }
  262. /// \}
  263. protected:
  264. static DeclContextLookupResult
  265. SetExternalVisibleDeclsForName(const DeclContext *DC,
  266. DeclarationName Name,
  267. ArrayRef<NamedDecl*> Decls);
  268. static DeclContextLookupResult
  269. SetNoExternalVisibleDeclsForName(const DeclContext *DC,
  270. DeclarationName Name);
  271. /// Increment the current generation.
  272. uint32_t incrementGeneration(ASTContext &C);
  273. };
  274. /// A lazy pointer to an AST node (of base type T) that resides
  275. /// within an external AST source.
  276. ///
  277. /// The AST node is identified within the external AST source by a
  278. /// 63-bit offset, and can be retrieved via an operation on the
  279. /// external AST source itself.
  280. template<typename T, typename OffsT, T* (ExternalASTSource::*Get)(OffsT Offset)>
  281. struct LazyOffsetPtr {
  282. /// Either a pointer to an AST node or the offset within the
  283. /// external AST source where the AST node can be found.
  284. ///
  285. /// If the low bit is clear, a pointer to the AST node. If the low
  286. /// bit is set, the upper 63 bits are the offset.
  287. mutable uint64_t Ptr = 0;
  288. public:
  289. LazyOffsetPtr() = default;
  290. explicit LazyOffsetPtr(T *Ptr) : Ptr(reinterpret_cast<uint64_t>(Ptr)) {}
  291. explicit LazyOffsetPtr(uint64_t Offset) : Ptr((Offset << 1) | 0x01) {
  292. assert((Offset << 1 >> 1) == Offset && "Offsets must require < 63 bits");
  293. if (Offset == 0)
  294. Ptr = 0;
  295. }
  296. LazyOffsetPtr &operator=(T *Ptr) {
  297. this->Ptr = reinterpret_cast<uint64_t>(Ptr);
  298. return *this;
  299. }
  300. LazyOffsetPtr &operator=(uint64_t Offset) {
  301. assert((Offset << 1 >> 1) == Offset && "Offsets must require < 63 bits");
  302. if (Offset == 0)
  303. Ptr = 0;
  304. else
  305. Ptr = (Offset << 1) | 0x01;
  306. return *this;
  307. }
  308. /// Whether this pointer is non-NULL.
  309. ///
  310. /// This operation does not require the AST node to be deserialized.
  311. explicit operator bool() const { return Ptr != 0; }
  312. /// Whether this pointer is non-NULL.
  313. ///
  314. /// This operation does not require the AST node to be deserialized.
  315. bool isValid() const { return Ptr != 0; }
  316. /// Whether this pointer is currently stored as an offset.
  317. bool isOffset() const { return Ptr & 0x01; }
  318. /// Retrieve the pointer to the AST node that this lazy pointer points to.
  319. ///
  320. /// \param Source the external AST source.
  321. ///
  322. /// \returns a pointer to the AST node.
  323. T* get(ExternalASTSource *Source) const {
  324. if (isOffset()) {
  325. assert(Source &&
  326. "Cannot deserialize a lazy pointer without an AST source");
  327. Ptr = reinterpret_cast<uint64_t>((Source->*Get)(Ptr >> 1));
  328. }
  329. return reinterpret_cast<T*>(Ptr);
  330. }
  331. };
  332. /// A lazy value (of type T) that is within an AST node of type Owner,
  333. /// where the value might change in later generations of the external AST
  334. /// source.
  335. template<typename Owner, typename T, void (ExternalASTSource::*Update)(Owner)>
  336. struct LazyGenerationalUpdatePtr {
  337. /// A cache of the value of this pointer, in the most recent generation in
  338. /// which we queried it.
  339. struct LazyData {
  340. ExternalASTSource *ExternalSource;
  341. uint32_t LastGeneration = 0;
  342. T LastValue;
  343. LazyData(ExternalASTSource *Source, T Value)
  344. : ExternalSource(Source), LastValue(Value) {}
  345. };
  346. // Our value is represented as simply T if there is no external AST source.
  347. using ValueType = llvm::PointerUnion<T, LazyData*>;
  348. ValueType Value;
  349. LazyGenerationalUpdatePtr(ValueType V) : Value(V) {}
  350. // Defined in ASTContext.h
  351. static ValueType makeValue(const ASTContext &Ctx, T Value);
  352. public:
  353. explicit LazyGenerationalUpdatePtr(const ASTContext &Ctx, T Value = T())
  354. : Value(makeValue(Ctx, Value)) {}
  355. /// Create a pointer that is not potentially updated by later generations of
  356. /// the external AST source.
  357. enum NotUpdatedTag { NotUpdated };
  358. LazyGenerationalUpdatePtr(NotUpdatedTag, T Value = T())
  359. : Value(Value) {}
  360. /// Forcibly set this pointer (which must be lazy) as needing updates.
  361. void markIncomplete() {
  362. Value.template get<LazyData *>()->LastGeneration = 0;
  363. }
  364. /// Set the value of this pointer, in the current generation.
  365. void set(T NewValue) {
  366. if (auto *LazyVal = Value.template dyn_cast<LazyData *>()) {
  367. LazyVal->LastValue = NewValue;
  368. return;
  369. }
  370. Value = NewValue;
  371. }
  372. /// Set the value of this pointer, for this and all future generations.
  373. void setNotUpdated(T NewValue) { Value = NewValue; }
  374. /// Get the value of this pointer, updating its owner if necessary.
  375. T get(Owner O) {
  376. if (auto *LazyVal = Value.template dyn_cast<LazyData *>()) {
  377. if (LazyVal->LastGeneration != LazyVal->ExternalSource->getGeneration()) {
  378. LazyVal->LastGeneration = LazyVal->ExternalSource->getGeneration();
  379. (LazyVal->ExternalSource->*Update)(O);
  380. }
  381. return LazyVal->LastValue;
  382. }
  383. return Value.template get<T>();
  384. }
  385. /// Get the most recently computed value of this pointer without updating it.
  386. T getNotUpdated() const {
  387. if (auto *LazyVal = Value.template dyn_cast<LazyData *>())
  388. return LazyVal->LastValue;
  389. return Value.template get<T>();
  390. }
  391. void *getOpaqueValue() { return Value.getOpaqueValue(); }
  392. static LazyGenerationalUpdatePtr getFromOpaqueValue(void *Ptr) {
  393. return LazyGenerationalUpdatePtr(ValueType::getFromOpaqueValue(Ptr));
  394. }
  395. };
  396. } // namespace clang
  397. namespace llvm {
  398. /// Specialize PointerLikeTypeTraits to allow LazyGenerationalUpdatePtr to be
  399. /// placed into a PointerUnion.
  400. template<typename Owner, typename T,
  401. void (clang::ExternalASTSource::*Update)(Owner)>
  402. struct PointerLikeTypeTraits<
  403. clang::LazyGenerationalUpdatePtr<Owner, T, Update>> {
  404. using Ptr = clang::LazyGenerationalUpdatePtr<Owner, T, Update>;
  405. static void *getAsVoidPointer(Ptr P) { return P.getOpaqueValue(); }
  406. static Ptr getFromVoidPointer(void *P) { return Ptr::getFromOpaqueValue(P); }
  407. static constexpr int NumLowBitsAvailable =
  408. PointerLikeTypeTraits<T>::NumLowBitsAvailable - 1;
  409. };
  410. } // namespace llvm
  411. namespace clang {
  412. /// Represents a lazily-loaded vector of data.
  413. ///
  414. /// The lazily-loaded vector of data contains data that is partially loaded
  415. /// from an external source and partially added by local translation. The
  416. /// items loaded from the external source are loaded lazily, when needed for
  417. /// iteration over the complete vector.
  418. template<typename T, typename Source,
  419. void (Source::*Loader)(SmallVectorImpl<T>&),
  420. unsigned LoadedStorage = 2, unsigned LocalStorage = 4>
  421. class LazyVector {
  422. SmallVector<T, LoadedStorage> Loaded;
  423. SmallVector<T, LocalStorage> Local;
  424. public:
  425. /// Iteration over the elements in the vector.
  426. ///
  427. /// In a complete iteration, the iterator walks the range [-M, N),
  428. /// where negative values are used to indicate elements
  429. /// loaded from the external source while non-negative values are used to
  430. /// indicate elements added via \c push_back().
  431. /// However, to provide iteration in source order (for, e.g., chained
  432. /// precompiled headers), dereferencing the iterator flips the negative
  433. /// values (corresponding to loaded entities), so that position -M
  434. /// corresponds to element 0 in the loaded entities vector, position -M+1
  435. /// corresponds to element 1 in the loaded entities vector, etc. This
  436. /// gives us a reasonably efficient, source-order walk.
  437. ///
  438. /// We define this as a wrapping iterator around an int. The
  439. /// iterator_adaptor_base class forwards the iterator methods to basic integer
  440. /// arithmetic.
  441. class iterator
  442. : public llvm::iterator_adaptor_base<
  443. iterator, int, std::random_access_iterator_tag, T, int, T *, T &> {
  444. friend class LazyVector;
  445. LazyVector *Self;
  446. iterator(LazyVector *Self, int Position)
  447. : iterator::iterator_adaptor_base(Position), Self(Self) {}
  448. bool isLoaded() const { return this->I < 0; }
  449. public:
  450. iterator() : iterator(nullptr, 0) {}
  451. typename iterator::reference operator*() const {
  452. if (isLoaded())
  453. return Self->Loaded.end()[this->I];
  454. return Self->Local.begin()[this->I];
  455. }
  456. };
  457. iterator begin(Source *source, bool LocalOnly = false) {
  458. if (LocalOnly)
  459. return iterator(this, 0);
  460. if (source)
  461. (source->*Loader)(Loaded);
  462. return iterator(this, -(int)Loaded.size());
  463. }
  464. iterator end() {
  465. return iterator(this, Local.size());
  466. }
  467. void push_back(const T& LocalValue) {
  468. Local.push_back(LocalValue);
  469. }
  470. void erase(iterator From, iterator To) {
  471. if (From.isLoaded() && To.isLoaded()) {
  472. Loaded.erase(&*From, &*To);
  473. return;
  474. }
  475. if (From.isLoaded()) {
  476. Loaded.erase(&*From, Loaded.end());
  477. From = begin(nullptr, true);
  478. }
  479. Local.erase(&*From, &*To);
  480. }
  481. };
  482. /// A lazy pointer to a statement.
  483. using LazyDeclStmtPtr =
  484. LazyOffsetPtr<Stmt, uint64_t, &ExternalASTSource::GetExternalDeclStmt>;
  485. /// A lazy pointer to a declaration.
  486. using LazyDeclPtr =
  487. LazyOffsetPtr<Decl, uint32_t, &ExternalASTSource::GetExternalDecl>;
  488. /// A lazy pointer to a set of CXXCtorInitializers.
  489. using LazyCXXCtorInitializersPtr =
  490. LazyOffsetPtr<CXXCtorInitializer *, uint64_t,
  491. &ExternalASTSource::GetExternalCXXCtorInitializers>;
  492. /// A lazy pointer to a set of CXXBaseSpecifiers.
  493. using LazyCXXBaseSpecifiersPtr =
  494. LazyOffsetPtr<CXXBaseSpecifier, uint64_t,
  495. &ExternalASTSource::GetExternalCXXBaseSpecifiers>;
  496. } // namespace clang
  497. #endif // LLVM_CLANG_AST_EXTERNALASTSOURCE_H
  498. #ifdef __GNUC__
  499. #pragma GCC diagnostic pop
  500. #endif