diff --git a/clang/include/clang/Driver/CC1Options.td b/clang/include/clang/Driver/CC1Options.td index 79dc441075b1..a175ce5fb47f 100644 --- a/clang/include/clang/Driver/CC1Options.td +++ b/clang/include/clang/Driver/CC1Options.td @@ -475,6 +475,8 @@ def fno_validate_pch : Flag<"-fno-validate-pch">, HelpText<"Disable validation of precompiled headers">; def dump_deserialized_pch_decls : Flag<"-dump-deserialized-decls">, HelpText<"Dump declarations that are deserialized from PCH, for testing">; +def error_on_deserialized_pch_decl : Separate<"-error-on-deserialized-decl">, + HelpText<"Emit error if a specific declaration is deserialized from PCH, for testing">; def fshort_wchar : Flag<"-fshort-wchar">, HelpText<"Force wchar_t to be a short unsigned int">; def fshort_enums : Flag<"-fshort-enums">, diff --git a/clang/include/clang/Frontend/PreprocessorOptions.h b/clang/include/clang/Frontend/PreprocessorOptions.h index 34b49e1fac1f..2a540b61df7f 100644 --- a/clang/include/clang/Frontend/PreprocessorOptions.h +++ b/clang/include/clang/Frontend/PreprocessorOptions.h @@ -15,6 +15,7 @@ #include #include #include +#include namespace llvm { class MemoryBuffer; @@ -50,6 +51,10 @@ public: /// \brief Dump declarations that are deserialized from PCH, for testing. bool DumpDeserializedPCHDecls; + /// \brief This is a set of names for decls that we do not want to be + /// deserialized, and we emit an error if they are; for testing purposes. + std::set DeserializedPCHDeclsToErrorOn; + /// \brief If non-zero, the implicit PCH include is actually a precompiled /// preamble that covers this number of bytes in the main source file. /// diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 8f0cb089ee6c..3a928a520dab 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1409,7 +1409,13 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, Opts.UsePredefines = !Args.hasArg(OPT_undef); Opts.DetailedRecord = Args.hasArg(OPT_detailed_preprocessing_record); Opts.DisablePCHValidation = Args.hasArg(OPT_fno_validate_pch); + Opts.DumpDeserializedPCHDecls = Args.hasArg(OPT_dump_deserialized_pch_decls); + for (arg_iterator it = Args.filtered_begin(OPT_error_on_deserialized_pch_decl), + ie = Args.filtered_end(); it != ie; ++it) { + const Arg *A = *it; + Opts.DeserializedPCHDeclsToErrorOn.insert(A->getValue(Args)); + } if (const Arg *A = Args.getLastArg(OPT_preamble_bytes_EQ)) { llvm::StringRef Value(A->getValue(Args)); diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp index 429b00933325..819aa52a508e 100644 --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/lib/Frontend/FrontendAction.cpp @@ -51,6 +51,41 @@ public: MacroDefinition *MD) {} }; + /// \brief Checks deserialized declarations and emits error if a name + /// matches one given in command-line using -error-on-deserialized-decl. + class DeserializedDeclsChecker : public ASTDeserializationListener { + ASTContext &Ctx; + std::set NamesToCheck; + ASTDeserializationListener *Previous; + + public: + DeserializedDeclsChecker(ASTContext &Ctx, + const std::set &NamesToCheck, + ASTDeserializationListener *Previous) + : Ctx(Ctx), NamesToCheck(NamesToCheck), Previous(Previous) { } + + virtual void DeclRead(serialization::DeclID ID, const Decl *D) { + if (const NamedDecl *ND = dyn_cast(D)) + if (NamesToCheck.find(ND->getNameAsString()) != NamesToCheck.end()) { + unsigned DiagID + = Ctx.getDiagnostics().getCustomDiagID(Diagnostic::Error, + "%0 was deserialized"); + Ctx.getDiagnostics().Report(Ctx.getFullLoc(D->getLocation()), DiagID) + << ND->getNameAsString(); + } + + if (Previous) + Previous->DeclRead(ID, D); + } + + virtual void SetReader(ASTReader *Reader) {} + virtual void IdentifierRead(serialization::IdentID ID, IdentifierInfo *II) {} + virtual void TypeRead(serialization::TypeIdx Idx, QualType T) {} + virtual void SelectorRead(serialization::SelectorID iD, Selector Sel) {} + virtual void MacroDefinitionRead(serialization::MacroID, + MacroDefinition *MD) {} +}; + } // end anonymous namespace FrontendAction::FrontendAction() : Instance(0) {} @@ -154,6 +189,10 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, Consumer->GetASTDeserializationListener() : 0; if (CI.getPreprocessorOpts().DumpDeserializedPCHDecls) DeserialListener = new DeserializedDeclsDumper(DeserialListener); + if (!CI.getPreprocessorOpts().DeserializedPCHDeclsToErrorOn.empty()) + DeserialListener = new DeserializedDeclsChecker(CI.getASTContext(), + CI.getPreprocessorOpts().DeserializedPCHDeclsToErrorOn, + DeserialListener); CI.createPCHExternalASTSource( CI.getPreprocessorOpts().ImplicitPCHInclude, CI.getPreprocessorOpts().DisablePCHValidation,