diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-04-10 20:39:37 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-04-10 20:39:37 +0000 |
commit | 0a0428e96c6f1e8bef7a481a9eb69a6f6df38951 (patch) | |
tree | 1bc2ebbf5fdbdea6f8d302d8e6d5318def494ffd /lib/Frontend | |
parent | 6a1284ac1707273ff474bfc6968b72e847191ba6 (diff) |
Implement serialization/deserialization of LangOptions in the PCH
file. When de-serializing LangOptions, we check that the
currently-provided language options are consistent with the options
used to compile the PCH file. If they are not, we emit a diagnostic
and ignore the PCH file.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@68820 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Frontend')
-rw-r--r-- | lib/Frontend/PCHReader.cpp | 162 | ||||
-rw-r--r-- | lib/Frontend/PCHWriter.cpp | 70 |
2 files changed, 209 insertions, 23 deletions
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index 0e5b6ee8aa..a00fee27fb 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -11,7 +11,7 @@ // //===----------------------------------------------------------------------===// #include "clang/Frontend/PCHReader.h" -#include "clang/Frontend/PCHBitCodes.h" +#include "clang/Frontend/FrontendDiagnostic.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/Type.h" @@ -192,18 +192,22 @@ bool PCHReader::ReadSourceManagerBlock() { } } -bool PCHReader::ReadPCHBlock() { - if (Stream.EnterSubBlock(pch::PCH_BLOCK_ID)) - return Error("Malformed block record"); +PCHReader::PCHReadResult PCHReader::ReadPCHBlock() { + if (Stream.EnterSubBlock(pch::PCH_BLOCK_ID)) { + Error("Malformed block record"); + return Failure; + } // Read all of the records and blocks for the PCH file. RecordData Record; while (!Stream.AtEndOfStream()) { unsigned Code = Stream.ReadCode(); if (Code == llvm::bitc::END_BLOCK) { - if (Stream.ReadBlockEnd()) - return Error("Error at end of module block"); - return false; + if (Stream.ReadBlockEnd()) { + Error("Error at end of module block"); + return Failure; + } + return Success; } if (Code == llvm::bitc::ENTER_SUBBLOCK) { @@ -211,13 +215,17 @@ bool PCHReader::ReadPCHBlock() { case pch::DECLS_BLOCK_ID: // Skip decls block (lazily loaded) case pch::TYPES_BLOCK_ID: // Skip types block (lazily loaded) default: // Skip unknown content. - if (Stream.SkipBlock()) - return Error("Malformed block record"); + if (Stream.SkipBlock()) { + Error("Malformed block record"); + return Failure; + } break; case pch::SOURCE_MANAGER_BLOCK_ID: - if (ReadSourceManagerBlock()) - return Error("Malformed source manager block"); + if (ReadSourceManagerBlock()) { + Error("Malformed source manager block"); + return Failure; + } break; } continue; @@ -235,27 +243,40 @@ bool PCHReader::ReadPCHBlock() { break; case pch::TYPE_OFFSET: - if (!TypeOffsets.empty()) - return Error("Duplicate TYPE_OFFSET record in PCH file"); + if (!TypeOffsets.empty()) { + Error("Duplicate TYPE_OFFSET record in PCH file"); + return Failure; + } TypeOffsets.swap(Record); TypeAlreadyLoaded.resize(TypeOffsets.size(), false); break; case pch::DECL_OFFSET: - if (!DeclOffsets.empty()) - return Error("Duplicate DECL_OFFSET record in PCH file"); + if (!DeclOffsets.empty()) { + Error("Duplicate DECL_OFFSET record in PCH file"); + return Failure; + } DeclOffsets.swap(Record); DeclAlreadyLoaded.resize(DeclOffsets.size(), false); break; + + case pch::LANGUAGE_OPTIONS: + if (ParseLanguageOptions(Record)) + return IgnorePCH; + break; } } - return Error("Premature end of bitstream"); + Error("Premature end of bitstream"); + return Failure; } PCHReader::~PCHReader() { } bool PCHReader::ReadPCH(const std::string &FileName) { + // Set the PCH file name. + this->FileName = FileName; + // Open the PCH file. std::string ErrStr; Buffer.reset(llvm::MemoryBuffer::getFile(FileName.c_str(), &ErrStr)); @@ -290,8 +311,20 @@ bool PCHReader::ReadPCH(const std::string &FileName) { return Error("Malformed BlockInfoBlock"); break; case pch::PCH_BLOCK_ID: - if (ReadPCHBlock()) + switch (ReadPCHBlock()) { + case Success: + break; + + case Failure: return true; + + case IgnorePCH: + if (Stream.SkipBlock()) { + Error("Malformed block record"); + return true; + } + return false; + } break; default: if (Stream.SkipBlock()) @@ -306,6 +339,95 @@ bool PCHReader::ReadPCH(const std::string &FileName) { return false; } +/// \brief Parse the record that corresponds to a LangOptions data +/// structure. +/// +/// This routine compares the language options used to generate the +/// PCH file against the language options set for the current +/// compilation. For each option, we classify differences between the +/// two compiler states as either "benign" or "important". Benign +/// differences don't matter, and we accept them without complaint +/// (and without modifying the language options). Differences between +/// the states for important options cause the PCH file to be +/// unusable, so we emit a warning and return true to indicate that +/// there was an error. +/// +/// \returns true if the PCH file is unacceptable, false otherwise. +bool PCHReader::ParseLanguageOptions( + const llvm::SmallVectorImpl<uint64_t> &Record) { + const LangOptions &LangOpts = Context.getLangOptions(); +#define PARSE_LANGOPT_BENIGN(Option) ++Idx +#define PARSE_LANGOPT_IMPORTANT(Option, DiagID) \ + if (Record[Idx] != LangOpts.Option) { \ + Diag(DiagID) << (unsigned)Record[Idx] << LangOpts.Option; \ + Diag(diag::note_ignoring_pch) << FileName; \ + return true; \ + } \ + ++Idx + + unsigned Idx = 0; + PARSE_LANGOPT_BENIGN(Trigraphs); + PARSE_LANGOPT_BENIGN(BCPLComment); + PARSE_LANGOPT_BENIGN(DollarIdents); + PARSE_LANGOPT_BENIGN(AsmPreprocessor); + PARSE_LANGOPT_IMPORTANT(GNUMode, diag::warn_pch_gnu_extensions); + PARSE_LANGOPT_BENIGN(ImplicitInt); + PARSE_LANGOPT_BENIGN(Digraphs); + PARSE_LANGOPT_BENIGN(HexFloats); + PARSE_LANGOPT_IMPORTANT(C99, diag::warn_pch_c99); + PARSE_LANGOPT_IMPORTANT(Microsoft, diag::warn_pch_microsoft_extensions); + PARSE_LANGOPT_IMPORTANT(CPlusPlus, diag::warn_pch_cplusplus); + PARSE_LANGOPT_IMPORTANT(CPlusPlus0x, diag::warn_pch_cplusplus0x); + PARSE_LANGOPT_IMPORTANT(NoExtensions, diag::warn_pch_extensions); + PARSE_LANGOPT_BENIGN(CXXOperatorName); + PARSE_LANGOPT_IMPORTANT(ObjC1, diag::warn_pch_objective_c); + PARSE_LANGOPT_IMPORTANT(ObjC2, diag::warn_pch_objective_c2); + PARSE_LANGOPT_IMPORTANT(ObjCNonFragileABI, diag::warn_pch_nonfragile_abi); + PARSE_LANGOPT_BENIGN(PascalStrings); + PARSE_LANGOPT_BENIGN(Boolean); + PARSE_LANGOPT_BENIGN(WritableStrings); + PARSE_LANGOPT_IMPORTANT(LaxVectorConversions, + diag::warn_pch_lax_vector_conversions); + PARSE_LANGOPT_IMPORTANT(Exceptions, diag::warn_pch_exceptions); + PARSE_LANGOPT_IMPORTANT(NeXTRuntime, diag::warn_pch_objc_runtime); + PARSE_LANGOPT_IMPORTANT(Freestanding, diag::warn_pch_freestanding); + PARSE_LANGOPT_IMPORTANT(NoBuiltin, diag::warn_pch_builtins); + PARSE_LANGOPT_IMPORTANT(ThreadsafeStatics, + diag::warn_pch_thread_safe_statics); + PARSE_LANGOPT_IMPORTANT(Blocks, diag::warn_pch_blocks); + PARSE_LANGOPT_BENIGN(EmitAllDecls); + PARSE_LANGOPT_IMPORTANT(MathErrno, diag::warn_pch_math_errno); + PARSE_LANGOPT_IMPORTANT(OverflowChecking, diag::warn_pch_overflow_checking); + PARSE_LANGOPT_IMPORTANT(HeinousExtensions, + diag::warn_pch_heinous_extensions); + // FIXME: Most of the options below are benign if the macro wasn't + // used. Unfortunately, this means that a PCH compiled without + // optimization can't be used with optimization turned on, even + // though the only thing that changes is whether __OPTIMIZE__ was + // defined... but if __OPTIMIZE__ never showed up in the header, it + // doesn't matter. We could consider making this some special kind + // of check. + PARSE_LANGOPT_IMPORTANT(Optimize, diag::warn_pch_optimize); + PARSE_LANGOPT_IMPORTANT(OptimizeSize, diag::warn_pch_optimize_size); + PARSE_LANGOPT_IMPORTANT(Static, diag::warn_pch_static); + PARSE_LANGOPT_IMPORTANT(PICLevel, diag::warn_pch_pic_level); + PARSE_LANGOPT_IMPORTANT(GNUInline, diag::warn_pch_gnu_inline); + PARSE_LANGOPT_IMPORTANT(NoInline, diag::warn_pch_no_inline); + if ((LangOpts.getGCMode() != 0) != (Record[Idx] != 0)) { + Diag(diag::warn_pch_gc_mode) + << (unsigned)Record[Idx] << LangOpts.getGCMode(); + Diag(diag::note_ignoring_pch) << FileName; + return true; + } + ++Idx; + PARSE_LANGOPT_BENIGN(getVisibilityMode()); + PARSE_LANGOPT_BENIGN(InstantiationDepth); +#undef PARSE_LANGOPT_IRRELEVANT +#undef PARSE_LANGOPT_BENIGN + + return false; +} + /// \brief Read and return the type at the given offset. /// /// This routine actually reads the record corresponding to the type @@ -619,3 +741,9 @@ PCHReader::ReadDeclarationName(const RecordData &Record, unsigned &Idx) { // Required to silence GCC warning return DeclarationName(); } + +DiagnosticBuilder PCHReader::Diag(unsigned DiagID) { + return PP.getDiagnostics().Report(FullSourceLoc(SourceLocation(), + Context.getSourceManager()), + DiagID); +} diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index 6f4492bc8c..6feb726b42 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -328,6 +328,67 @@ void PCHDeclWriter::VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset, // PCHWriter Implementation //===----------------------------------------------------------------------===// +void PCHWriter::WriteLanguageOptions(const LangOptions &LangOpts) { + RecordData Record; + Record.push_back(LangOpts.Trigraphs); + Record.push_back(LangOpts.BCPLComment); // BCPL-style '//' comments. + Record.push_back(LangOpts.DollarIdents); // '$' allowed in identifiers. + Record.push_back(LangOpts.AsmPreprocessor); // Preprocessor in asm mode. + Record.push_back(LangOpts.GNUMode); // True in gnu99 mode false in c99 mode (etc) + Record.push_back(LangOpts.ImplicitInt); // C89 implicit 'int'. + Record.push_back(LangOpts.Digraphs); // C94, C99 and C++ + Record.push_back(LangOpts.HexFloats); // C99 Hexadecimal float constants. + Record.push_back(LangOpts.C99); // C99 Support + Record.push_back(LangOpts.Microsoft); // Microsoft extensions. + Record.push_back(LangOpts.CPlusPlus); // C++ Support + Record.push_back(LangOpts.CPlusPlus0x); // C++0x Support + Record.push_back(LangOpts.NoExtensions); // All extensions are disabled, strict mode. + Record.push_back(LangOpts.CXXOperatorNames); // Treat C++ operator names as keywords. + + Record.push_back(LangOpts.ObjC1); // Objective-C 1 support enabled. + Record.push_back(LangOpts.ObjC2); // Objective-C 2 support enabled. + Record.push_back(LangOpts.ObjCNonFragileABI); // Objective-C modern abi enabled + + Record.push_back(LangOpts.PascalStrings); // Allow Pascal strings + Record.push_back(LangOpts.Boolean); // Allow bool/true/false + Record.push_back(LangOpts.WritableStrings); // Allow writable strings + Record.push_back(LangOpts.LaxVectorConversions); + Record.push_back(LangOpts.Exceptions); // Support exception handling. + + Record.push_back(LangOpts.NeXTRuntime); // Use NeXT runtime. + Record.push_back(LangOpts.Freestanding); // Freestanding implementation + Record.push_back(LangOpts.NoBuiltin); // Do not use builtin functions (-fno-builtin) + + Record.push_back(LangOpts.ThreadsafeStatics); // Whether static initializers are protected + // by locks. + Record.push_back(LangOpts.Blocks); // block extension to C + Record.push_back(LangOpts.EmitAllDecls); // Emit all declarations, even if + // they are unused. + Record.push_back(LangOpts.MathErrno); // Math functions must respect errno + // (modulo the platform support). + + Record.push_back(LangOpts.OverflowChecking); // Extension to call a handler function when + // signed integer arithmetic overflows. + + Record.push_back(LangOpts.HeinousExtensions); // Extensions that we really don't like and + // may be ripped out at any time. + + Record.push_back(LangOpts.Optimize); // Whether __OPTIMIZE__ should be defined. + Record.push_back(LangOpts.OptimizeSize); // Whether __OPTIMIZE_SIZE__ should be + // defined. + Record.push_back(LangOpts.Static); // Should __STATIC__ be defined (as + // opposed to __DYNAMIC__). + Record.push_back(LangOpts.PICLevel); // The value for __PIC__, if non-zero. + + Record.push_back(LangOpts.GNUInline); // Should GNU inline semantics be + // used (instead of C99 semantics). + Record.push_back(LangOpts.NoInline); // Should __NO_INLINE__ be defined. + Record.push_back(LangOpts.getGCMode()); + Record.push_back(LangOpts.getVisibilityMode()); + Record.push_back(LangOpts.InstantiationDepth); + S.EmitRecord(pch::LANGUAGE_OPTIONS, Record); +} + //===----------------------------------------------------------------------===// // Source Manager Serialization //===----------------------------------------------------------------------===// @@ -625,9 +686,6 @@ void PCHWriter::WriteTypesBlock(ASTContext &Context) { // Exit the types block S.ExitBlock(); - - // Write the type offsets record - S.EmitRecord(pch::TYPE_OFFSET, TypeOffsets); } /// \brief Write the block containing all of the declaration IDs @@ -740,9 +798,6 @@ void PCHWriter::WriteDeclsBlock(ASTContext &Context) { // Exit the declarations block S.ExitBlock(); - - // Write the declaration offsets record - S.EmitRecord(pch::DECL_OFFSET, DeclOffsets); } PCHWriter::PCHWriter(llvm::BitstreamWriter &S) @@ -761,10 +816,13 @@ void PCHWriter::WritePCH(ASTContext &Context, const Preprocessor &PP) { // Write the remaining PCH contents. S.EnterSubblock(pch::PCH_BLOCK_ID, 2); + WriteLanguageOptions(Context.getLangOptions()); WriteSourceManagerBlock(Context.getSourceManager()); WritePreprocessor(PP); WriteTypesBlock(Context); WriteDeclsBlock(Context); + S.EmitRecord(pch::TYPE_OFFSET, TypeOffsets); + S.EmitRecord(pch::DECL_OFFSET, DeclOffsets); S.ExitBlock(); } |