aboutsummaryrefslogtreecommitdiff
path: root/lib/Frontend/PCHReader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Frontend/PCHReader.cpp')
-rw-r--r--lib/Frontend/PCHReader.cpp162
1 files changed, 145 insertions, 17 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);
+}