blob: a00fee27fbb58d9b09b7f6d7f911cf5ac38d05aa [file] [log] [blame]
Douglas Gregorc34897d2009-04-09 22:27:44 +00001//===--- PCHReader.cpp - Precompiled Headers Reader -------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file defines the PCHReader class, which reads a precompiled header.
11//
12//===----------------------------------------------------------------------===//
13#include "clang/Frontend/PCHReader.h"
Douglas Gregor179cfb12009-04-10 20:39:37 +000014#include "clang/Frontend/FrontendDiagnostic.h"
Douglas Gregorc34897d2009-04-09 22:27:44 +000015#include "clang/AST/ASTContext.h"
16#include "clang/AST/Decl.h"
17#include "clang/AST/Type.h"
Douglas Gregorab1cef72009-04-10 03:52:48 +000018#include "clang/Lex/Preprocessor.h"
19#include "clang/Basic/SourceManager.h"
20#include "clang/Basic/FileManager.h"
Douglas Gregorc34897d2009-04-09 22:27:44 +000021#include "llvm/Bitcode/BitstreamReader.h"
22#include "llvm/Support/Compiler.h"
23#include "llvm/Support/MemoryBuffer.h"
24#include <algorithm>
25#include <cstdio>
26
27using namespace clang;
28
29//===----------------------------------------------------------------------===//
30// Declaration deserialization
31//===----------------------------------------------------------------------===//
32namespace {
33 class VISIBILITY_HIDDEN PCHDeclReader {
34 PCHReader &Reader;
35 const PCHReader::RecordData &Record;
36 unsigned &Idx;
37
38 public:
39 PCHDeclReader(PCHReader &Reader, const PCHReader::RecordData &Record,
40 unsigned &Idx)
41 : Reader(Reader), Record(Record), Idx(Idx) { }
42
43 void VisitDecl(Decl *D);
44 void VisitTranslationUnitDecl(TranslationUnitDecl *TU);
45 void VisitNamedDecl(NamedDecl *ND);
46 void VisitTypeDecl(TypeDecl *TD);
47 void VisitTypedefDecl(TypedefDecl *TD);
48 void VisitValueDecl(ValueDecl *VD);
49 void VisitVarDecl(VarDecl *VD);
50
51 std::pair<uint64_t, uint64_t> VisitDeclContext(DeclContext *DC);
52 };
53}
54
55void PCHDeclReader::VisitDecl(Decl *D) {
56 D->setDeclContext(cast_or_null<DeclContext>(Reader.GetDecl(Record[Idx++])));
57 D->setLexicalDeclContext(
58 cast_or_null<DeclContext>(Reader.GetDecl(Record[Idx++])));
59 D->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
60 D->setInvalidDecl(Record[Idx++]);
61 // FIXME: hasAttrs
62 D->setImplicit(Record[Idx++]);
63 D->setAccess((AccessSpecifier)Record[Idx++]);
64}
65
66void PCHDeclReader::VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
67 VisitDecl(TU);
68}
69
70void PCHDeclReader::VisitNamedDecl(NamedDecl *ND) {
71 VisitDecl(ND);
72 ND->setDeclName(Reader.ReadDeclarationName(Record, Idx));
73}
74
75void PCHDeclReader::VisitTypeDecl(TypeDecl *TD) {
76 VisitNamedDecl(TD);
77 // FIXME: circular dependencies here?
78 TD->setTypeForDecl(Reader.GetType(Record[Idx++]).getTypePtr());
79}
80
81void PCHDeclReader::VisitTypedefDecl(TypedefDecl *TD) {
82 VisitTypeDecl(TD);
83 TD->setUnderlyingType(Reader.GetType(Record[Idx++]));
84}
85
86void PCHDeclReader::VisitValueDecl(ValueDecl *VD) {
87 VisitNamedDecl(VD);
88 VD->setType(Reader.GetType(Record[Idx++]));
89}
90
91void PCHDeclReader::VisitVarDecl(VarDecl *VD) {
92 VisitValueDecl(VD);
93 VD->setStorageClass((VarDecl::StorageClass)Record[Idx++]);
94 VD->setThreadSpecified(Record[Idx++]);
95 VD->setCXXDirectInitializer(Record[Idx++]);
96 VD->setDeclaredInCondition(Record[Idx++]);
97 VD->setPreviousDeclaration(
98 cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
99 VD->setTypeSpecStartLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
100}
101
102std::pair<uint64_t, uint64_t>
103PCHDeclReader::VisitDeclContext(DeclContext *DC) {
104 uint64_t LexicalOffset = Record[Idx++];
105 uint64_t VisibleOffset = 0;
106 if (DC->getPrimaryContext() == DC)
107 VisibleOffset = Record[Idx++];
108 return std::make_pair(LexicalOffset, VisibleOffset);
109}
110
111// FIXME: use the diagnostics machinery
112static bool Error(const char *Str) {
113 std::fprintf(stderr, "%s\n", Str);
114 return true;
115}
116
Douglas Gregorab1cef72009-04-10 03:52:48 +0000117/// \brief Read the source manager block
118bool PCHReader::ReadSourceManagerBlock() {
119 using namespace SrcMgr;
120 if (Stream.EnterSubBlock(pch::SOURCE_MANAGER_BLOCK_ID))
121 return Error("Malformed source manager block record");
122
123 SourceManager &SourceMgr = Context.getSourceManager();
124 RecordData Record;
125 while (true) {
126 unsigned Code = Stream.ReadCode();
127 if (Code == llvm::bitc::END_BLOCK) {
128 if (Stream.ReadBlockEnd())
129 return Error("Error at end of Source Manager block");
130 return false;
131 }
132
133 if (Code == llvm::bitc::ENTER_SUBBLOCK) {
134 // No known subblocks, always skip them.
135 Stream.ReadSubBlockID();
136 if (Stream.SkipBlock())
137 return Error("Malformed block record");
138 continue;
139 }
140
141 if (Code == llvm::bitc::DEFINE_ABBREV) {
142 Stream.ReadAbbrevRecord();
143 continue;
144 }
145
146 // Read a record.
147 const char *BlobStart;
148 unsigned BlobLen;
149 Record.clear();
150 switch (Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
151 default: // Default behavior: ignore.
152 break;
153
154 case pch::SM_SLOC_FILE_ENTRY: {
155 // FIXME: We would really like to delay the creation of this
156 // FileEntry until it is actually required, e.g., when producing
157 // a diagnostic with a source location in this file.
158 const FileEntry *File
159 = PP.getFileManager().getFile(BlobStart, BlobStart + BlobLen);
160 // FIXME: Error recovery if file cannot be found.
161 SourceMgr.createFileID(File,
162 SourceLocation::getFromRawEncoding(Record[1]),
163 (CharacteristicKind)Record[2]);
164 break;
165 }
166
167 case pch::SM_SLOC_BUFFER_ENTRY: {
168 const char *Name = BlobStart;
169 unsigned Code = Stream.ReadCode();
170 Record.clear();
171 unsigned RecCode = Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen);
172 assert(RecCode == pch::SM_SLOC_BUFFER_BLOB && "Ill-formed PCH file");
173 SourceMgr.createFileIDForMemBuffer(
174 llvm::MemoryBuffer::getMemBuffer(BlobStart, BlobStart + BlobLen - 1,
175 Name));
176 break;
177 }
178
179 case pch::SM_SLOC_INSTANTIATION_ENTRY: {
180 SourceLocation SpellingLoc
181 = SourceLocation::getFromRawEncoding(Record[1]);
182 SourceMgr.createInstantiationLoc(
183 SpellingLoc,
184 SourceLocation::getFromRawEncoding(Record[2]),
185 SourceLocation::getFromRawEncoding(Record[3]),
186 Lexer::MeasureTokenLength(SpellingLoc,
187 SourceMgr));
188 break;
189 }
190
191 }
192 }
193}
194
Douglas Gregor179cfb12009-04-10 20:39:37 +0000195PCHReader::PCHReadResult PCHReader::ReadPCHBlock() {
196 if (Stream.EnterSubBlock(pch::PCH_BLOCK_ID)) {
197 Error("Malformed block record");
198 return Failure;
199 }
Douglas Gregorc34897d2009-04-09 22:27:44 +0000200
201 // Read all of the records and blocks for the PCH file.
Douglas Gregorac8f2802009-04-10 17:25:41 +0000202 RecordData Record;
Douglas Gregorc34897d2009-04-09 22:27:44 +0000203 while (!Stream.AtEndOfStream()) {
204 unsigned Code = Stream.ReadCode();
205 if (Code == llvm::bitc::END_BLOCK) {
Douglas Gregor179cfb12009-04-10 20:39:37 +0000206 if (Stream.ReadBlockEnd()) {
207 Error("Error at end of module block");
208 return Failure;
209 }
210 return Success;
Douglas Gregorc34897d2009-04-09 22:27:44 +0000211 }
212
213 if (Code == llvm::bitc::ENTER_SUBBLOCK) {
214 switch (Stream.ReadSubBlockID()) {
215 case pch::DECLS_BLOCK_ID: // Skip decls block (lazily loaded)
216 case pch::TYPES_BLOCK_ID: // Skip types block (lazily loaded)
217 default: // Skip unknown content.
Douglas Gregor179cfb12009-04-10 20:39:37 +0000218 if (Stream.SkipBlock()) {
219 Error("Malformed block record");
220 return Failure;
221 }
Douglas Gregorc34897d2009-04-09 22:27:44 +0000222 break;
223
Douglas Gregorab1cef72009-04-10 03:52:48 +0000224 case pch::SOURCE_MANAGER_BLOCK_ID:
Douglas Gregor179cfb12009-04-10 20:39:37 +0000225 if (ReadSourceManagerBlock()) {
226 Error("Malformed source manager block");
227 return Failure;
228 }
Douglas Gregorab1cef72009-04-10 03:52:48 +0000229 break;
Douglas Gregorc34897d2009-04-09 22:27:44 +0000230 }
Douglas Gregorac8f2802009-04-10 17:25:41 +0000231 continue;
232 }
233
234 if (Code == llvm::bitc::DEFINE_ABBREV) {
235 Stream.ReadAbbrevRecord();
236 continue;
237 }
238
239 // Read and process a record.
240 Record.clear();
241 switch ((pch::PCHRecordTypes)Stream.ReadRecord(Code, Record)) {
242 default: // Default behavior: ignore.
243 break;
244
245 case pch::TYPE_OFFSET:
Douglas Gregor179cfb12009-04-10 20:39:37 +0000246 if (!TypeOffsets.empty()) {
247 Error("Duplicate TYPE_OFFSET record in PCH file");
248 return Failure;
249 }
Douglas Gregorac8f2802009-04-10 17:25:41 +0000250 TypeOffsets.swap(Record);
251 TypeAlreadyLoaded.resize(TypeOffsets.size(), false);
252 break;
253
254 case pch::DECL_OFFSET:
Douglas Gregor179cfb12009-04-10 20:39:37 +0000255 if (!DeclOffsets.empty()) {
256 Error("Duplicate DECL_OFFSET record in PCH file");
257 return Failure;
258 }
Douglas Gregorac8f2802009-04-10 17:25:41 +0000259 DeclOffsets.swap(Record);
260 DeclAlreadyLoaded.resize(DeclOffsets.size(), false);
261 break;
Douglas Gregor179cfb12009-04-10 20:39:37 +0000262
263 case pch::LANGUAGE_OPTIONS:
264 if (ParseLanguageOptions(Record))
265 return IgnorePCH;
266 break;
Douglas Gregorc34897d2009-04-09 22:27:44 +0000267 }
268 }
269
Douglas Gregor179cfb12009-04-10 20:39:37 +0000270 Error("Premature end of bitstream");
271 return Failure;
Douglas Gregorc34897d2009-04-09 22:27:44 +0000272}
273
274PCHReader::~PCHReader() { }
275
276bool PCHReader::ReadPCH(const std::string &FileName) {
Douglas Gregor179cfb12009-04-10 20:39:37 +0000277 // Set the PCH file name.
278 this->FileName = FileName;
279
Douglas Gregorc34897d2009-04-09 22:27:44 +0000280 // Open the PCH file.
281 std::string ErrStr;
282 Buffer.reset(llvm::MemoryBuffer::getFile(FileName.c_str(), &ErrStr));
283 if (!Buffer)
284 return Error(ErrStr.c_str());
285
286 // Initialize the stream
287 Stream.init((const unsigned char *)Buffer->getBufferStart(),
288 (const unsigned char *)Buffer->getBufferEnd());
289
290 // Sniff for the signature.
291 if (Stream.Read(8) != 'C' ||
292 Stream.Read(8) != 'P' ||
293 Stream.Read(8) != 'C' ||
294 Stream.Read(8) != 'H')
295 return Error("Not a PCH file");
296
297 // We expect a number of well-defined blocks, though we don't necessarily
298 // need to understand them all.
299 while (!Stream.AtEndOfStream()) {
300 unsigned Code = Stream.ReadCode();
301
302 if (Code != llvm::bitc::ENTER_SUBBLOCK)
303 return Error("Invalid record at top-level");
304
305 unsigned BlockID = Stream.ReadSubBlockID();
306
307 // We only know the PCH subblock ID.
308 switch (BlockID) {
309 case llvm::bitc::BLOCKINFO_BLOCK_ID:
310 if (Stream.ReadBlockInfoBlock())
311 return Error("Malformed BlockInfoBlock");
312 break;
313 case pch::PCH_BLOCK_ID:
Douglas Gregor179cfb12009-04-10 20:39:37 +0000314 switch (ReadPCHBlock()) {
315 case Success:
316 break;
317
318 case Failure:
Douglas Gregorc34897d2009-04-09 22:27:44 +0000319 return true;
Douglas Gregor179cfb12009-04-10 20:39:37 +0000320
321 case IgnorePCH:
322 if (Stream.SkipBlock()) {
323 Error("Malformed block record");
324 return true;
325 }
326 return false;
327 }
Douglas Gregorc34897d2009-04-09 22:27:44 +0000328 break;
329 default:
330 if (Stream.SkipBlock())
331 return Error("Malformed block record");
332 break;
333 }
334 }
335
336 // Load the translation unit declaration
337 ReadDeclRecord(DeclOffsets[0], 0);
338
339 return false;
340}
341
Douglas Gregor179cfb12009-04-10 20:39:37 +0000342/// \brief Parse the record that corresponds to a LangOptions data
343/// structure.
344///
345/// This routine compares the language options used to generate the
346/// PCH file against the language options set for the current
347/// compilation. For each option, we classify differences between the
348/// two compiler states as either "benign" or "important". Benign
349/// differences don't matter, and we accept them without complaint
350/// (and without modifying the language options). Differences between
351/// the states for important options cause the PCH file to be
352/// unusable, so we emit a warning and return true to indicate that
353/// there was an error.
354///
355/// \returns true if the PCH file is unacceptable, false otherwise.
356bool PCHReader::ParseLanguageOptions(
357 const llvm::SmallVectorImpl<uint64_t> &Record) {
358 const LangOptions &LangOpts = Context.getLangOptions();
359#define PARSE_LANGOPT_BENIGN(Option) ++Idx
360#define PARSE_LANGOPT_IMPORTANT(Option, DiagID) \
361 if (Record[Idx] != LangOpts.Option) { \
362 Diag(DiagID) << (unsigned)Record[Idx] << LangOpts.Option; \
363 Diag(diag::note_ignoring_pch) << FileName; \
364 return true; \
365 } \
366 ++Idx
367
368 unsigned Idx = 0;
369 PARSE_LANGOPT_BENIGN(Trigraphs);
370 PARSE_LANGOPT_BENIGN(BCPLComment);
371 PARSE_LANGOPT_BENIGN(DollarIdents);
372 PARSE_LANGOPT_BENIGN(AsmPreprocessor);
373 PARSE_LANGOPT_IMPORTANT(GNUMode, diag::warn_pch_gnu_extensions);
374 PARSE_LANGOPT_BENIGN(ImplicitInt);
375 PARSE_LANGOPT_BENIGN(Digraphs);
376 PARSE_LANGOPT_BENIGN(HexFloats);
377 PARSE_LANGOPT_IMPORTANT(C99, diag::warn_pch_c99);
378 PARSE_LANGOPT_IMPORTANT(Microsoft, diag::warn_pch_microsoft_extensions);
379 PARSE_LANGOPT_IMPORTANT(CPlusPlus, diag::warn_pch_cplusplus);
380 PARSE_LANGOPT_IMPORTANT(CPlusPlus0x, diag::warn_pch_cplusplus0x);
381 PARSE_LANGOPT_IMPORTANT(NoExtensions, diag::warn_pch_extensions);
382 PARSE_LANGOPT_BENIGN(CXXOperatorName);
383 PARSE_LANGOPT_IMPORTANT(ObjC1, diag::warn_pch_objective_c);
384 PARSE_LANGOPT_IMPORTANT(ObjC2, diag::warn_pch_objective_c2);
385 PARSE_LANGOPT_IMPORTANT(ObjCNonFragileABI, diag::warn_pch_nonfragile_abi);
386 PARSE_LANGOPT_BENIGN(PascalStrings);
387 PARSE_LANGOPT_BENIGN(Boolean);
388 PARSE_LANGOPT_BENIGN(WritableStrings);
389 PARSE_LANGOPT_IMPORTANT(LaxVectorConversions,
390 diag::warn_pch_lax_vector_conversions);
391 PARSE_LANGOPT_IMPORTANT(Exceptions, diag::warn_pch_exceptions);
392 PARSE_LANGOPT_IMPORTANT(NeXTRuntime, diag::warn_pch_objc_runtime);
393 PARSE_LANGOPT_IMPORTANT(Freestanding, diag::warn_pch_freestanding);
394 PARSE_LANGOPT_IMPORTANT(NoBuiltin, diag::warn_pch_builtins);
395 PARSE_LANGOPT_IMPORTANT(ThreadsafeStatics,
396 diag::warn_pch_thread_safe_statics);
397 PARSE_LANGOPT_IMPORTANT(Blocks, diag::warn_pch_blocks);
398 PARSE_LANGOPT_BENIGN(EmitAllDecls);
399 PARSE_LANGOPT_IMPORTANT(MathErrno, diag::warn_pch_math_errno);
400 PARSE_LANGOPT_IMPORTANT(OverflowChecking, diag::warn_pch_overflow_checking);
401 PARSE_LANGOPT_IMPORTANT(HeinousExtensions,
402 diag::warn_pch_heinous_extensions);
403 // FIXME: Most of the options below are benign if the macro wasn't
404 // used. Unfortunately, this means that a PCH compiled without
405 // optimization can't be used with optimization turned on, even
406 // though the only thing that changes is whether __OPTIMIZE__ was
407 // defined... but if __OPTIMIZE__ never showed up in the header, it
408 // doesn't matter. We could consider making this some special kind
409 // of check.
410 PARSE_LANGOPT_IMPORTANT(Optimize, diag::warn_pch_optimize);
411 PARSE_LANGOPT_IMPORTANT(OptimizeSize, diag::warn_pch_optimize_size);
412 PARSE_LANGOPT_IMPORTANT(Static, diag::warn_pch_static);
413 PARSE_LANGOPT_IMPORTANT(PICLevel, diag::warn_pch_pic_level);
414 PARSE_LANGOPT_IMPORTANT(GNUInline, diag::warn_pch_gnu_inline);
415 PARSE_LANGOPT_IMPORTANT(NoInline, diag::warn_pch_no_inline);
416 if ((LangOpts.getGCMode() != 0) != (Record[Idx] != 0)) {
417 Diag(diag::warn_pch_gc_mode)
418 << (unsigned)Record[Idx] << LangOpts.getGCMode();
419 Diag(diag::note_ignoring_pch) << FileName;
420 return true;
421 }
422 ++Idx;
423 PARSE_LANGOPT_BENIGN(getVisibilityMode());
424 PARSE_LANGOPT_BENIGN(InstantiationDepth);
425#undef PARSE_LANGOPT_IRRELEVANT
426#undef PARSE_LANGOPT_BENIGN
427
428 return false;
429}
430
Douglas Gregorc34897d2009-04-09 22:27:44 +0000431/// \brief Read and return the type at the given offset.
432///
433/// This routine actually reads the record corresponding to the type
434/// at the given offset in the bitstream. It is a helper routine for
435/// GetType, which deals with reading type IDs.
436QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
437 Stream.JumpToBit(Offset);
438 RecordData Record;
439 unsigned Code = Stream.ReadCode();
440 switch ((pch::TypeCode)Stream.ReadRecord(Code, Record)) {
441 case pch::TYPE_FIXED_WIDTH_INT: {
442 assert(Record.size() == 2 && "Incorrect encoding of fixed-width int type");
443 return Context.getFixedWidthIntType(Record[0], Record[1]);
444 }
445
446 case pch::TYPE_COMPLEX: {
447 assert(Record.size() == 1 && "Incorrect encoding of complex type");
448 QualType ElemType = GetType(Record[0]);
449 return Context.getComplexType(ElemType);
450 }
451
452 case pch::TYPE_POINTER: {
453 assert(Record.size() == 1 && "Incorrect encoding of pointer type");
454 QualType PointeeType = GetType(Record[0]);
455 return Context.getPointerType(PointeeType);
456 }
457
458 case pch::TYPE_BLOCK_POINTER: {
459 assert(Record.size() == 1 && "Incorrect encoding of block pointer type");
460 QualType PointeeType = GetType(Record[0]);
461 return Context.getBlockPointerType(PointeeType);
462 }
463
464 case pch::TYPE_LVALUE_REFERENCE: {
465 assert(Record.size() == 1 && "Incorrect encoding of lvalue reference type");
466 QualType PointeeType = GetType(Record[0]);
467 return Context.getLValueReferenceType(PointeeType);
468 }
469
470 case pch::TYPE_RVALUE_REFERENCE: {
471 assert(Record.size() == 1 && "Incorrect encoding of rvalue reference type");
472 QualType PointeeType = GetType(Record[0]);
473 return Context.getRValueReferenceType(PointeeType);
474 }
475
476 case pch::TYPE_MEMBER_POINTER: {
477 assert(Record.size() == 1 && "Incorrect encoding of member pointer type");
478 QualType PointeeType = GetType(Record[0]);
479 QualType ClassType = GetType(Record[1]);
480 return Context.getMemberPointerType(PointeeType, ClassType.getTypePtr());
481 }
482
483 // FIXME: Several other kinds of types to deserialize here!
484 default:
Douglas Gregorac8f2802009-04-10 17:25:41 +0000485 assert(false && "Unable to deserialize this type");
Douglas Gregorc34897d2009-04-09 22:27:44 +0000486 break;
487 }
488
489 // Suppress a GCC warning
490 return QualType();
491}
492
493/// \brief Note that we have loaded the declaration with the given
494/// Index.
495///
496/// This routine notes that this declaration has already been loaded,
497/// so that future GetDecl calls will return this declaration rather
498/// than trying to load a new declaration.
499inline void PCHReader::LoadedDecl(unsigned Index, Decl *D) {
500 assert(!DeclAlreadyLoaded[Index] && "Decl loaded twice?");
501 DeclAlreadyLoaded[Index] = true;
502 DeclOffsets[Index] = reinterpret_cast<uint64_t>(D);
503}
504
505/// \brief Read the declaration at the given offset from the PCH file.
506Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) {
507 Decl *D = 0;
508 Stream.JumpToBit(Offset);
509 RecordData Record;
510 unsigned Code = Stream.ReadCode();
511 unsigned Idx = 0;
512 PCHDeclReader Reader(*this, Record, Idx);
513 switch ((pch::DeclCode)Stream.ReadRecord(Code, Record)) {
514 case pch::DECL_TRANSLATION_UNIT:
515 assert(Index == 0 && "Translation unit must be at index 0");
516 Reader.VisitTranslationUnitDecl(Context.getTranslationUnitDecl());
517 D = Context.getTranslationUnitDecl();
518 LoadedDecl(Index, D);
519 break;
520
521 case pch::DECL_TYPEDEF: {
522 TypedefDecl *Typedef = TypedefDecl::Create(Context, 0, SourceLocation(),
523 0, QualType());
524 LoadedDecl(Index, Typedef);
525 Reader.VisitTypedefDecl(Typedef);
526 D = Typedef;
527 break;
528 }
529
530 case pch::DECL_VAR: {
531 VarDecl *Var = VarDecl::Create(Context, 0, SourceLocation(), 0, QualType(),
532 VarDecl::None, SourceLocation());
533 LoadedDecl(Index, Var);
534 Reader.VisitVarDecl(Var);
535 D = Var;
536 break;
537 }
538
539 default:
540 assert(false && "Cannot de-serialize this kind of declaration");
541 break;
542 }
543
544 // If this declaration is also a declaration context, get the
545 // offsets for its tables of lexical and visible declarations.
546 if (DeclContext *DC = dyn_cast<DeclContext>(D)) {
547 std::pair<uint64_t, uint64_t> Offsets = Reader.VisitDeclContext(DC);
548 if (Offsets.first || Offsets.second) {
549 DC->setHasExternalLexicalStorage(Offsets.first != 0);
550 DC->setHasExternalVisibleStorage(Offsets.second != 0);
551 DeclContextOffsets[DC] = Offsets;
552 }
553 }
554 assert(Idx == Record.size());
555
556 return D;
557}
558
Douglas Gregorac8f2802009-04-10 17:25:41 +0000559QualType PCHReader::GetType(pch::TypeID ID) {
Douglas Gregorc34897d2009-04-09 22:27:44 +0000560 unsigned Quals = ID & 0x07;
561 unsigned Index = ID >> 3;
562
563 if (Index < pch::NUM_PREDEF_TYPE_IDS) {
564 QualType T;
565 switch ((pch::PredefinedTypeIDs)Index) {
566 case pch::PREDEF_TYPE_NULL_ID: return QualType();
567 case pch::PREDEF_TYPE_VOID_ID: T = Context.VoidTy; break;
568 case pch::PREDEF_TYPE_BOOL_ID: T = Context.BoolTy; break;
569
570 case pch::PREDEF_TYPE_CHAR_U_ID:
571 case pch::PREDEF_TYPE_CHAR_S_ID:
572 // FIXME: Check that the signedness of CharTy is correct!
573 T = Context.CharTy;
574 break;
575
576 case pch::PREDEF_TYPE_UCHAR_ID: T = Context.UnsignedCharTy; break;
577 case pch::PREDEF_TYPE_USHORT_ID: T = Context.UnsignedShortTy; break;
578 case pch::PREDEF_TYPE_UINT_ID: T = Context.UnsignedIntTy; break;
579 case pch::PREDEF_TYPE_ULONG_ID: T = Context.UnsignedLongTy; break;
580 case pch::PREDEF_TYPE_ULONGLONG_ID: T = Context.UnsignedLongLongTy; break;
581 case pch::PREDEF_TYPE_SCHAR_ID: T = Context.SignedCharTy; break;
582 case pch::PREDEF_TYPE_WCHAR_ID: T = Context.WCharTy; break;
583 case pch::PREDEF_TYPE_SHORT_ID: T = Context.ShortTy; break;
584 case pch::PREDEF_TYPE_INT_ID: T = Context.IntTy; break;
585 case pch::PREDEF_TYPE_LONG_ID: T = Context.LongTy; break;
586 case pch::PREDEF_TYPE_LONGLONG_ID: T = Context.LongLongTy; break;
587 case pch::PREDEF_TYPE_FLOAT_ID: T = Context.FloatTy; break;
588 case pch::PREDEF_TYPE_DOUBLE_ID: T = Context.DoubleTy; break;
589 case pch::PREDEF_TYPE_LONGDOUBLE_ID: T = Context.LongDoubleTy; break;
590 case pch::PREDEF_TYPE_OVERLOAD_ID: T = Context.OverloadTy; break;
591 case pch::PREDEF_TYPE_DEPENDENT_ID: T = Context.DependentTy; break;
592 }
593
594 assert(!T.isNull() && "Unknown predefined type");
595 return T.getQualifiedType(Quals);
596 }
597
598 Index -= pch::NUM_PREDEF_TYPE_IDS;
599 if (!TypeAlreadyLoaded[Index]) {
600 // Load the type from the PCH file.
601 TypeOffsets[Index] = reinterpret_cast<uint64_t>(
602 ReadTypeRecord(TypeOffsets[Index]).getTypePtr());
603 TypeAlreadyLoaded[Index] = true;
604 }
605
606 return QualType(reinterpret_cast<Type *>(TypeOffsets[Index]), Quals);
607}
608
Douglas Gregorac8f2802009-04-10 17:25:41 +0000609Decl *PCHReader::GetDecl(pch::DeclID ID) {
Douglas Gregorc34897d2009-04-09 22:27:44 +0000610 if (ID == 0)
611 return 0;
612
613 unsigned Index = ID - 1;
614 if (DeclAlreadyLoaded[Index])
615 return reinterpret_cast<Decl *>(DeclOffsets[Index]);
616
617 // Load the declaration from the PCH file.
618 return ReadDeclRecord(DeclOffsets[Index], Index);
619}
620
621bool PCHReader::ReadDeclsLexicallyInContext(DeclContext *DC,
Douglas Gregorac8f2802009-04-10 17:25:41 +0000622 llvm::SmallVectorImpl<pch::DeclID> &Decls) {
Douglas Gregorc34897d2009-04-09 22:27:44 +0000623 assert(DC->hasExternalLexicalStorage() &&
624 "DeclContext has no lexical decls in storage");
625 uint64_t Offset = DeclContextOffsets[DC].first;
626 assert(Offset && "DeclContext has no lexical decls in storage");
627
628 // Load the record containing all of the declarations lexically in
629 // this context.
630 Stream.JumpToBit(Offset);
631 RecordData Record;
632 unsigned Code = Stream.ReadCode();
633 unsigned RecCode = Stream.ReadRecord(Code, Record);
634 assert(RecCode == pch::DECL_CONTEXT_LEXICAL && "Expected lexical block");
635
636 // Load all of the declaration IDs
637 Decls.clear();
638 Decls.insert(Decls.end(), Record.begin(), Record.end());
639 return false;
640}
641
642bool PCHReader::ReadDeclsVisibleInContext(DeclContext *DC,
643 llvm::SmallVectorImpl<VisibleDeclaration> & Decls) {
644 assert(DC->hasExternalVisibleStorage() &&
645 "DeclContext has no visible decls in storage");
646 uint64_t Offset = DeclContextOffsets[DC].second;
647 assert(Offset && "DeclContext has no visible decls in storage");
648
649 // Load the record containing all of the declarations visible in
650 // this context.
651 Stream.JumpToBit(Offset);
652 RecordData Record;
653 unsigned Code = Stream.ReadCode();
654 unsigned RecCode = Stream.ReadRecord(Code, Record);
655 assert(RecCode == pch::DECL_CONTEXT_VISIBLE && "Expected visible block");
656 if (Record.size() == 0)
657 return false;
658
659 Decls.clear();
660
661 unsigned Idx = 0;
662 // llvm::SmallVector<uintptr_t, 16> DeclIDs;
663 while (Idx < Record.size()) {
664 Decls.push_back(VisibleDeclaration());
665 Decls.back().Name = ReadDeclarationName(Record, Idx);
666
667 // FIXME: Don't actually read anything here!
668 unsigned Size = Record[Idx++];
669 llvm::SmallVector<unsigned, 4> & LoadedDecls
670 = Decls.back().Declarations;
671 LoadedDecls.reserve(Size);
672 for (unsigned I = 0; I < Size; ++I)
673 LoadedDecls.push_back(Record[Idx++]);
674 }
675
676 return false;
677}
678
679void PCHReader::PrintStats() {
680 std::fprintf(stderr, "*** PCH Statistics:\n");
681
682 unsigned NumTypesLoaded = std::count(TypeAlreadyLoaded.begin(),
683 TypeAlreadyLoaded.end(),
684 true);
685 unsigned NumDeclsLoaded = std::count(DeclAlreadyLoaded.begin(),
686 DeclAlreadyLoaded.end(),
687 true);
688 std::fprintf(stderr, " %u/%u types read (%f%%)\n",
689 NumTypesLoaded, (unsigned)TypeAlreadyLoaded.size(),
690 ((float)NumTypesLoaded/(float)TypeAlreadyLoaded.size() * 100));
691 std::fprintf(stderr, " %u/%u declarations read (%f%%)\n",
692 NumDeclsLoaded, (unsigned)DeclAlreadyLoaded.size(),
693 ((float)NumDeclsLoaded/(float)DeclAlreadyLoaded.size() * 100));
694 std::fprintf(stderr, "\n");
695}
696
697const IdentifierInfo *PCHReader::GetIdentifierInfo(const RecordData &Record,
698 unsigned &Idx) {
699 // FIXME: we need unique IDs for identifiers.
700 std::string Str;
701 unsigned Length = Record[Idx++];
702 Str.resize(Length);
703 for (unsigned I = 0; I != Length; ++I)
704 Str[I] = Record[Idx++];
705 return &Context.Idents.get(Str);
706}
707
708DeclarationName
709PCHReader::ReadDeclarationName(const RecordData &Record, unsigned &Idx) {
710 DeclarationName::NameKind Kind = (DeclarationName::NameKind)Record[Idx++];
711 switch (Kind) {
712 case DeclarationName::Identifier:
713 return DeclarationName(GetIdentifierInfo(Record, Idx));
714
715 case DeclarationName::ObjCZeroArgSelector:
716 case DeclarationName::ObjCOneArgSelector:
717 case DeclarationName::ObjCMultiArgSelector:
718 assert(false && "Unable to de-serialize Objective-C selectors");
719 break;
720
721 case DeclarationName::CXXConstructorName:
722 return Context.DeclarationNames.getCXXConstructorName(
723 GetType(Record[Idx++]));
724
725 case DeclarationName::CXXDestructorName:
726 return Context.DeclarationNames.getCXXDestructorName(
727 GetType(Record[Idx++]));
728
729 case DeclarationName::CXXConversionFunctionName:
730 return Context.DeclarationNames.getCXXConversionFunctionName(
731 GetType(Record[Idx++]));
732
733 case DeclarationName::CXXOperatorName:
734 return Context.DeclarationNames.getCXXOperatorName(
735 (OverloadedOperatorKind)Record[Idx++]);
736
737 case DeclarationName::CXXUsingDirective:
738 return DeclarationName::getUsingDirectiveName();
739 }
740
741 // Required to silence GCC warning
742 return DeclarationName();
743}
Douglas Gregor179cfb12009-04-10 20:39:37 +0000744
745DiagnosticBuilder PCHReader::Diag(unsigned DiagID) {
746 return PP.getDiagnostics().Report(FullSourceLoc(SourceLocation(),
747 Context.getSourceManager()),
748 DiagID);
749}