Index: include/clang/AST/ASTConsumer.h =================================================================== --- include/clang/AST/ASTConsumer.h +++ include/clang/AST/ASTConsumer.h @@ -15,6 +15,7 @@ #define LLVM_CLANG_AST_ASTCONSUMER_H #include "llvm/ADT/StringRef.h" +#include namespace clang { class ASTContext; @@ -29,6 +30,8 @@ class VarDecl; class FunctionDecl; class ImportDecl; + class PPCallbacks; + class Preprocessor; /// ASTConsumer - This is an abstract interface that should be implemented by /// clients that read ASTs. This abstraction layer allows the client to be @@ -152,6 +155,12 @@ /// body may be parsed anyway if it is needed (for instance, if it contains /// the code completion point or is constexpr). virtual bool shouldSkipFunctionBody(Decl *D) { return true; } + + /// If the consumer is interested in notifications from Preprocessor, + /// for example: notifications on macro definitions, etc., it should return + /// a pointer to a PPCallbacks here. + /// The caller takes ownership on the returned pointer. + virtual std::unique_ptr CreatePreprocessorCallbacks(Preprocessor &PP); }; } // end namespace clang. Index: lib/AST/ASTConsumer.cpp =================================================================== --- lib/AST/ASTConsumer.cpp +++ lib/AST/ASTConsumer.cpp @@ -15,6 +15,7 @@ #include "llvm/Bitcode/BitstreamReader.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclGroup.h" +#include "clang/Lex/PPCallbacks.h" using namespace clang; bool ASTConsumer::HandleTopLevelDecl(DeclGroupRef D) { @@ -30,3 +31,8 @@ void ASTConsumer::HandleImplicitImportDecl(ImportDecl *D) { HandleTopLevelDecl(DeclGroupRef(D)); } + +std::unique_ptr +ASTConsumer::CreatePreprocessorCallbacks(Preprocessor &PP) { + return nullptr; +} Index: lib/CodeGen/CGDebugInfo.h =================================================================== --- lib/CodeGen/CGDebugInfo.h +++ lib/CodeGen/CGDebugInfo.h @@ -376,6 +376,15 @@ void completeTemplateDefinition(const ClassTemplateSpecializationDecl &SD); + /// Get Macro debug info. + llvm::DIMacro *CreateMacro(llvm::DIMacroFile *Parent, bool IsUndef, + SourceLocation LineLoc, StringRef Name, + StringRef Value); + /// Get Macro File debug info. + llvm::DIMacroFile *CreateMacroFile(llvm::DIMacroFile *Parent, + SourceLocation LineLoc, + SourceLocation FileLoc); + private: /// Emit call to llvm.dbg.declare for a variable declaration. void EmitDeclare(const VarDecl *decl, llvm::Value *AI, Index: lib/CodeGen/CGDebugInfo.cpp =================================================================== --- lib/CodeGen/CGDebugInfo.cpp +++ lib/CodeGen/CGDebugInfo.cpp @@ -2096,6 +2096,23 @@ FullName); } +llvm::DIMacro *CGDebugInfo::CreateMacro(llvm::DIMacroFile *Parent, bool IsUndef, + SourceLocation LineLoc, StringRef Name, + StringRef Value) { + unsigned Line = LineLoc.isInvalid() ? 0 : getLineNumber(LineLoc); + + return DBuilder.createMacro(Parent, Line, IsUndef, Name, Value); +} + +llvm::DIMacroFile *CGDebugInfo::CreateMacroFile(llvm::DIMacroFile *Parent, + SourceLocation LineLoc, + SourceLocation FileLoc) { + llvm::DIFile *FName = getOrCreateFile(FileLoc); + unsigned Line = LineLoc.isInvalid() ? 0 : getLineNumber(LineLoc); + + return DBuilder.createMacroFile(Parent, Line, FName, llvm::DIMacroNodeArray()); +} + static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) { Qualifiers Quals; do { Index: lib/CodeGen/CMakeLists.txt =================================================================== --- lib/CodeGen/CMakeLists.txt +++ lib/CodeGen/CMakeLists.txt @@ -70,6 +70,7 @@ CodeGenTypes.cpp CoverageMappingGen.cpp ItaniumCXXABI.cpp + MacroPPCallbacks.cpp MicrosoftCXXABI.cpp ModuleBuilder.cpp ObjectFilePCHContainerOperations.cpp Index: lib/CodeGen/CodeGenAction.cpp =================================================================== --- lib/CodeGen/CodeGenAction.cpp +++ lib/CodeGen/CodeGenAction.cpp @@ -227,6 +227,11 @@ Gen->HandleDependentLibrary(Opts); } + std::unique_ptr + CreatePreprocessorCallbacks(Preprocessor &PP) override { + return Gen->CreatePreprocessorCallbacks(PP); + } + static void InlineAsmDiagHandler(const llvm::SMDiagnostic &SM,void *Context, unsigned LocCookie) { SourceLocation Loc = SourceLocation::getFromRawEncoding(LocCookie); Index: lib/CodeGen/CodeGenModule.h =================================================================== --- lib/CodeGen/CodeGenModule.h +++ lib/CodeGen/CodeGenModule.h @@ -76,6 +76,8 @@ class CXXDestructorDecl; class Module; class CoverageSourceInfo; +class Preprocessor; +class PPCallbacks; namespace CodeGen { @@ -585,6 +587,8 @@ CGDebugInfo *getModuleDebugInfo() { return DebugInfo; } + std::unique_ptr createPreprocessorCallbacks(Preprocessor &PP); + llvm::MDNode *getNoObjCARCExceptionsMetadata() { if (!NoObjCARCExceptionsMetadata) NoObjCARCExceptionsMetadata = llvm::MDNode::get(getLLVMContext(), None); Index: lib/CodeGen/CodeGenModule.cpp =================================================================== --- lib/CodeGen/CodeGenModule.cpp +++ lib/CodeGen/CodeGenModule.cpp @@ -24,6 +24,7 @@ #include "CodeGenPGO.h" #include "CodeGenTBAA.h" #include "CoverageMappingGen.h" +#include "MacroPPCallbacks.h" #include "TargetInfo.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CharUnits.h" @@ -208,6 +209,16 @@ CUDARuntime = CreateNVCUDARuntime(*this); } +std::unique_ptr +CodeGenModule::createPreprocessorCallbacks(Preprocessor &PP) { + // Enable generating macro debug info only in FullDebugInfo mode. + if (CodeGenOpts.getDebugInfo() < CodeGenOptions::FullDebugInfo || + !getModuleDebugInfo()) + return nullptr; + + return std::make_unique(*getModuleDebugInfo(), PP); +} + void CodeGenModule::addReplacement(StringRef Name, llvm::Constant *C) { Replacements[Name] = C; } Index: lib/CodeGen/MacroPPCallbacks.h =================================================================== --- lib/CodeGen/MacroPPCallbacks.h +++ lib/CodeGen/MacroPPCallbacks.h @@ -0,0 +1,94 @@ +//===--- MacroPPCallbacks.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines implementation for the macro preprocessors callbacks. +// +//===----------------------------------------------------------------------===// + +#include "clang/Lex/PPCallbacks.h" +#include "clang/Parse/Parser.h" +#include + +namespace llvm { + class DIMacroFile; +} +namespace clang { + +namespace CodeGen { + class CGDebugInfo; +} +class MacroPPCallbacks : public PPCallbacks { + CodeGen::CGDebugInfo &DebugInfo; + Preprocessor &PP; + SourceLocation LastHashLoc; + SourceLocation FirstIncludeFile; + bool FirstInclude; + bool FirstIncludeDone; + int CommandIncludeFiles; + int SkipFiles; + std::vector Parents; + + + static void getMacroDefinition(const IdentifierInfo &II, const MacroInfo &MI, + Preprocessor &PP, raw_ostream &Name, + raw_ostream &Value); + +public: + MacroPPCallbacks(CodeGen::CGDebugInfo& DI, Preprocessor &PP); + + /// \brief Callback invoked whenever a source file is entered or exited. + /// + /// \param Loc Indicates the new location. + /// \param PrevFID the file that was exited if \p Reason is ExitFile. + virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, + SrcMgr::CharacteristicKind FileType, + FileID PrevFID = FileID()); + + /// \brief Callback invoked whenever a source file is skipped as the result + /// of header guard optimization. + /// + /// \param SkippedFile The file that is skipped instead of entering \#include + /// + /// \param FilenameTok The file name token in \#include "FileName" directive + /// or macro expanded file name token from \#include MACRO(PARAMS) directive. + /// Note that FilenameTok contains corresponding quotes/angles symbols. + virtual void FileSkipped(const FileEntry &SkippedFile, + const Token &FilenameTok, + SrcMgr::CharacteristicKind FileType) {} + + + virtual void InclusionDirective(SourceLocation HashLoc, + const Token &IncludeTok, + StringRef FileName, + bool IsAngled, + CharSourceRange FilenameRange, + const FileEntry *File, + StringRef SearchPath, + StringRef RelativePath, + const Module *Imported); + + + /// \brief Called by Preprocessor::HandleMacroExpandedIdentifier when a + /// macro invocation is found. + virtual void MacroExpands(const Token &MacroNameTok, + const MacroDefinition &MD, SourceRange Range, + const MacroArgs *Args) {} + + /// \brief Hook called whenever a macro definition is seen. + virtual void MacroDefined(const Token &MacroNameTok, + const MacroDirective *MD); + + /// \brief Hook called whenever a macro \#undef is seen. + /// + /// MD is released immediately following this callback. + virtual void MacroUndefined(const Token &MacroNameTok, + const MacroDefinition &MD); +}; + +} // end namespace clang Index: lib/CodeGen/MacroPPCallbacks.cpp =================================================================== --- lib/CodeGen/MacroPPCallbacks.cpp +++ lib/CodeGen/MacroPPCallbacks.cpp @@ -0,0 +1,147 @@ +//===--- MacroPPCallbacks.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements for the macro preprocessors callbacks. +// +//===----------------------------------------------------------------------===// + +#include "MacroPPCallbacks.h" +#include "CGDebugInfo.h" +#include + +using namespace clang; + +void MacroPPCallbacks::getMacroDefinition(const IdentifierInfo &II, + const MacroInfo &MI, + Preprocessor &PP, + raw_ostream &Name, + raw_ostream &Value) { + Name << II.getName(); + + if (MI.isFunctionLike()) { + Name << '('; + if (!MI.arg_empty()) { + MacroInfo::arg_iterator AI = MI.arg_begin(), E = MI.arg_end(); + for (; AI + 1 != E; ++AI) { + Name << (*AI)->getName(); + Name << ','; + } + + // Last argument. + if ((*AI)->getName() == "__VA_ARGS__") + Name << "..."; + else + Name << (*AI)->getName(); + } + + if (MI.isGNUVarargs()) + Name << "..."; // #define foo(x...) + + Name << ')'; + } + + SmallString<128> SpellingBuffer; + bool First = true; + for (const auto &T : MI.tokens()) { + if (!First && T.hasLeadingSpace()) + Value << ' '; + + Value << PP.getSpelling(T, SpellingBuffer); + First = false; + } +} + +MacroPPCallbacks::MacroPPCallbacks(CodeGen::CGDebugInfo& DI, Preprocessor &PP) + : DebugInfo(DI), PP(PP), FirstInclude(false), FirstIncludeDone(false), + CommandIncludeFiles(0), SkipFiles(2) { + Parents.push_back(nullptr); +} + +void MacroPPCallbacks::FileChanged(SourceLocation Loc, FileChangeReason Reason, + SrcMgr::CharacteristicKind FileType, + FileID PrevFID) { + switch (Reason) { + case EnterFile: + if (!FirstInclude) { + FirstInclude = true; + FirstIncludeFile = Loc; + } + if (CommandIncludeFiles) { + if (FirstInclude && !FirstIncludeDone) { + assert(FirstIncludeFile.isValid()); + Parents.push_back(DebugInfo.CreateMacroFile(Parents.back(), SourceLocation(), FirstIncludeFile)); + FirstIncludeDone = true; + } + Parents.push_back(DebugInfo.CreateMacroFile(Parents.back(), SourceLocation(), Loc)); + } + else if (!SkipFiles) + Parents.push_back(DebugInfo.CreateMacroFile(Parents.back(), LastHashLoc, Loc)); + return; + case ExitFile: + if (CommandIncludeFiles) { + Parents.pop_back(); + --CommandIncludeFiles; + } + else if (SkipFiles) { + if (!(--SkipFiles)) { + if (FirstInclude && !FirstIncludeDone) { + assert(FirstIncludeFile.isValid()); + DebugInfo.CreateMacroFile(Parents.back(), SourceLocation(), FirstIncludeFile); + FirstIncludeDone = true; + } + } + } + else + Parents.pop_back(); + return; + default: + return; + } +} + +void MacroPPCallbacks::InclusionDirective(SourceLocation HashLoc, + const Token &IncludeTok, + StringRef FileName, + bool IsAngled, + CharSourceRange FilenameRange, + const FileEntry *File, + StringRef SearchPath, + StringRef RelativePath, + const Module *Imported) { + // FIXME: find a better way to check if this is #include + if (FileName.empty()) + return; + + if (SkipFiles) { + CommandIncludeFiles++; + } + LastHashLoc = HashLoc; +} + + +void MacroPPCallbacks::MacroDefined(const Token &MacroNameTok, + const MacroDirective *MD) { + IdentifierInfo *Id = MacroNameTok.getIdentifierInfo(); + SourceLocation location; + if (!SkipFiles) + location = MacroNameTok.getLocation(); + std::string NameBuffer, ValueBuffer; + llvm::raw_string_ostream Name(NameBuffer); + llvm::raw_string_ostream Value(ValueBuffer); + getMacroDefinition(*Id, *MD->getMacroInfo(), PP, Name, Value); + DebugInfo.CreateMacro(Parents.back(), false, location, Name.str(), + Value.str()); +} + +void MacroPPCallbacks::MacroUndefined(const Token &MacroNameTok, + const MacroDefinition &MD) { + IdentifierInfo *Id = MacroNameTok.getIdentifierInfo(); + SourceLocation location = MacroNameTok.getLocation(); + DebugInfo.CreateMacro(Parents.back(), true, location, Id->getName(), ""); +} Index: lib/CodeGen/ModuleBuilder.cpp =================================================================== --- lib/CodeGen/ModuleBuilder.cpp +++ lib/CodeGen/ModuleBuilder.cpp @@ -20,6 +20,7 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Basic/TargetInfo.h" #include "clang/Frontend/CodeGenOptions.h" +#include "clang/Lex/PPCallbacks.h" #include "llvm/ADT/StringRef.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/LLVMContext.h" @@ -234,6 +235,11 @@ void HandleDependentLibrary(llvm::StringRef Lib) override { Builder->AddDependentLib(Lib); } + + std::unique_ptr + CreatePreprocessorCallbacks(Preprocessor &PP) override { + return Builder->createPreprocessorCallbacks(PP); + } }; } Index: lib/Parse/ParseAST.cpp =================================================================== --- lib/Parse/ParseAST.cpp +++ lib/Parse/ParseAST.cpp @@ -128,6 +128,12 @@ new Parser(S.getPreprocessor(), S, SkipFunctionBodies)); Parser &P = *ParseOP.get(); + std::unique_ptr Callbacks = + Consumer->CreatePreprocessorCallbacks(S.getPreprocessor()); + if (Callbacks) { + S.getPreprocessor().addPPCallbacks(std::move(Callbacks)); + } + llvm::CrashRecoveryContextCleanupRegistrar CleanupPrettyStack(llvm::SavePrettyStackState()); PrettyStackTraceParserEntry CrashInfo(P);