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