diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst index 7a4486436c6a..17f26d1e8cd8 100644 --- a/clang/docs/UsersManual.rst +++ b/clang/docs/UsersManual.rst @@ -1696,6 +1696,22 @@ below. If multiple flags are present, the last one is used. Generate complete debug info. +Controlling Macro Debug Info Generation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Debug info for C preprocessor macros increases the size of debug information in +the binary. Macro debug info generated by Clang can be controlled by the flags +listed below. + +.. option:: -fdebug-macro + + Generate debug info for preprocessor macros. This flag is discarded when + **-g0** is enabled. + +.. option:: -fno-debug-macro + + Do not generate debug info for preprocessor macros (default). + Controlling Debugger "Tuning" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/CodeGen/ModuleBuilder.h b/clang/include/clang/CodeGen/ModuleBuilder.h index 58638348653f..6f81ea9d6370 100644 --- a/clang/include/clang/CodeGen/ModuleBuilder.h +++ b/clang/include/clang/CodeGen/ModuleBuilder.h @@ -35,6 +35,7 @@ namespace clang { namespace CodeGen { class CodeGenModule; + class CGDebugInfo; } /// The primary public interface to the Clang code generator. @@ -65,6 +66,9 @@ public: /// CodeGenerator after releasing its module. llvm::Module *ReleaseModule(); + /// Return debug info code generator. + CodeGen::CGDebugInfo *getCGDebugInfo(); + /// Given a mangled name, return a declaration which mangles that way /// which has been added to this code generator via a Handle method. /// diff --git a/clang/include/clang/Driver/CC1Options.td b/clang/include/clang/Driver/CC1Options.td index 35475b4f1eb5..f0e2bfe02fc2 100644 --- a/clang/include/clang/Driver/CC1Options.td +++ b/clang/include/clang/Driver/CC1Options.td @@ -136,6 +136,8 @@ def migrator_no_finalize_removal : Flag<["-"], "no-finalize-removal">, let Flags = [CC1Option, CC1AsOption, NoDriverOption] in { def debug_info_kind_EQ : Joined<["-"], "debug-info-kind=">; +def debug_info_macro : Flag<["-"], "debug-info-macro">, + HelpText<"Emit macro debug information">; def dwarf_version_EQ : Joined<["-"], "dwarf-version=">; def debugger_tuning_EQ : Joined<["-"], "debugger-tuning=">; def fdebug_compilation_dir : Separate<["-"], "fdebug-compilation-dir">, diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 4c6b0d1797c8..d63e565ea3e6 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1322,6 +1322,10 @@ def fno_standalone_debug : Flag<["-"], "fno-standalone-debug">, Group, HelpText<"Limit debug information produced to reduce size of debug binary">; def flimit_debug_info : Flag<["-"], "flimit-debug-info">, Flags<[CoreOption]>, Alias; def fno_limit_debug_info : Flag<["-"], "fno-limit-debug-info">, Flags<[CoreOption]>, Alias; +def fdebug_macro : Flag<["-"], "fdebug-macro">, Group, Flags<[CoreOption]>, + HelpText<"Emit macro debug information">; +def fno_debug_macro : Flag<["-"], "fno-debug-macro">, Group, Flags<[CoreOption]>, + HelpText<"Do not emit macro debug information">; def fstrict_aliasing : Flag<["-"], "fstrict-aliasing">, Group, Flags<[DriverOption, CoreOption]>; def fstrict_enums : Flag<["-"], "fstrict-enums">, Group, Flags<[CC1Option]>, diff --git a/clang/include/clang/Frontend/CodeGenOptions.def b/clang/include/clang/Frontend/CodeGenOptions.def index 7c1899e4f7a3..172380c00e72 100644 --- a/clang/include/clang/Frontend/CodeGenOptions.def +++ b/clang/include/clang/Frontend/CodeGenOptions.def @@ -224,6 +224,9 @@ VALUE_CODEGENOPT(SSPBufferSize, 32, 0) /// The kind of generated debug info. ENUM_CODEGENOPT(DebugInfo, codegenoptions::DebugInfoKind, 3, codegenoptions::NoDebugInfo) +/// Whether to generate macro debug info. +CODEGENOPT(MacroDebugInfo, 1, 0) + /// Tune the debug info for this debugger. ENUM_CODEGENOPT(DebuggerTuning, llvm::DebuggerKind, 2, llvm::DebuggerKind::Default) diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 7eb0af2d371a..b48714f69b97 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -2419,6 +2419,21 @@ llvm::DIType *CGDebugInfo::CreateTypeDefinition(const EnumType *Ty) { FullName); } +llvm::DIMacro *CGDebugInfo::CreateMacro(llvm::DIMacroFile *Parent, + unsigned MType, SourceLocation LineLoc, + StringRef Name, StringRef Value) { + unsigned Line = LineLoc.isInvalid() ? 0 : getLineNumber(LineLoc); + return DBuilder.createMacro(Parent, Line, MType, Name, Value); +} + +llvm::DIMacroFile *CGDebugInfo::CreateTempMacroFile(llvm::DIMacroFile *Parent, + SourceLocation LineLoc, + SourceLocation FileLoc) { + llvm::DIFile *FName = getOrCreateFile(FileLoc); + unsigned Line = LineLoc.isInvalid() ? 0 : getLineNumber(LineLoc); + return DBuilder.createTempMacroFile(Parent, Line, FName); +} + static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) { Qualifiers Quals; do { diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h index ea451d0548c9..050665e92e22 100644 --- a/clang/lib/CodeGen/CGDebugInfo.h +++ b/clang/lib/CodeGen/CGDebugInfo.h @@ -413,6 +413,16 @@ public: void completeTemplateDefinition(const ClassTemplateSpecializationDecl &SD); + /// Create debug info for a macro defined by a #define directive or a macro + /// undefined by a #undef directive. + llvm::DIMacro *CreateMacro(llvm::DIMacroFile *Parent, unsigned MType, + SourceLocation LineLoc, StringRef Name, + StringRef Value); + + /// Create debug info for a file referenced by an #include directive. + llvm::DIMacroFile *CreateTempMacroFile(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, diff --git a/clang/lib/CodeGen/CMakeLists.txt b/clang/lib/CodeGen/CMakeLists.txt index 1e9a43af5229..f34456e9fa54 100644 --- a/clang/lib/CodeGen/CMakeLists.txt +++ b/clang/lib/CodeGen/CMakeLists.txt @@ -77,6 +77,7 @@ add_clang_library(clangCodeGen CodeGenTypes.cpp CoverageMappingGen.cpp ItaniumCXXABI.cpp + MacroPPCallbacks.cpp MicrosoftCXXABI.cpp ModuleBuilder.cpp ObjectFilePCHContainerOperations.cpp diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp index 3828c5e17015..89a7c7c727b0 100644 --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -10,6 +10,7 @@ #include "clang/CodeGen/CodeGenAction.h" #include "CodeGenModule.h" #include "CoverageMappingGen.h" +#include "MacroPPCallbacks.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" @@ -97,6 +98,8 @@ namespace clang { return std::unique_ptr(Gen->ReleaseModule()); } + CodeGenerator *getCodeGenerator() { return Gen.get(); } + void HandleCXXStaticMemberVarInstantiation(VarDecl *VD) override { Gen->HandleCXXStaticMemberVarInstantiation(VD); } @@ -830,6 +833,17 @@ CodeGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { CI.getLangOpts(), CI.getFrontendOpts().ShowTimers, InFile, std::move(LinkModules), std::move(OS), *VMContext, CoverageInfo)); BEConsumer = Result.get(); + + // Enable generating macro debug info only when debug info is not disabled and + // also macro debug info is enabled. + if (CI.getCodeGenOpts().getDebugInfo() != codegenoptions::NoDebugInfo && + CI.getCodeGenOpts().MacroDebugInfo) { + std::unique_ptr Callbacks = + llvm::make_unique(BEConsumer->getCodeGenerator(), + CI.getPreprocessor()); + CI.getPreprocessor().addPPCallbacks(std::move(Callbacks)); + } + return std::move(Result); } diff --git a/clang/lib/CodeGen/MacroPPCallbacks.cpp b/clang/lib/CodeGen/MacroPPCallbacks.cpp new file mode 100644 index 000000000000..71eb55ca2f16 --- /dev/null +++ b/clang/lib/CodeGen/MacroPPCallbacks.cpp @@ -0,0 +1,211 @@ +//===--- MacroPPCallbacks.cpp ---------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains implementation for the macro preprocessors callbacks. +// +//===----------------------------------------------------------------------===// + +#include "MacroPPCallbacks.h" +#include "CGDebugInfo.h" +#include "clang/CodeGen/ModuleBuilder.h" +#include "clang/Parse/Parser.h" + +using namespace clang; + +void MacroPPCallbacks::writeMacroDefinition(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()) + // #define foo(x...) + Name << "..."; + + 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(CodeGenerator *Gen, Preprocessor &PP) + : Gen(Gen), PP(PP), Status(NoScope) {} + +/* + This is the expected flow of enter/exit compiler and user files: + - Main File Enter + - file enter + {Compiler macro definitions} - (Line=0, no scope) + - (Optional) file enter + {Command line macro definitions} - (Line=0, no scope) + - (Optional) file exit + {Command line file includes} - (Line=0, Main file scope) + {macro definitions and file includes} - (Line!=0, Parent scope) + - file exit + {User code macro definitions and file includes} - (Line!=0, Parent scope) +*/ + +llvm::DIMacroFile *MacroPPCallbacks::getCurrentScope() { + if (Status == MainFileScope || Status == CommandLineIncludeScope) + return Scopes.back(); + return nullptr; +} + +SourceLocation MacroPPCallbacks::getCorrectLocation(SourceLocation Loc) { + if (Status == MainFileScope || EnteredCommandLineIncludeFiles) + return Loc; + + // While parsing skipped files, location of macros is invalid. + // Invalid location represents line zero. + return SourceLocation(); +} + +static bool isBuiltinFile(SourceManager &SM, SourceLocation Loc) { + StringRef Filename(SM.getPresumedLoc(Loc).getFilename()); + return Filename.equals(""); +} + +static bool isCommandLineFile(SourceManager &SM, SourceLocation Loc) { + StringRef Filename(SM.getPresumedLoc(Loc).getFilename()); + return Filename.equals(""); +} + +void MacroPPCallbacks::updateStatusToNextScope() { + switch (Status) { + case NoScope: + Status = InitializedScope; + break; + case InitializedScope: + Status = BuiltinScope; + break; + case BuiltinScope: + Status = CommandLineIncludeScope; + break; + case CommandLineIncludeScope: + Status = MainFileScope; + break; + case MainFileScope: + llvm_unreachable("There is no next scope, already in the final scope"); + } +} + +void MacroPPCallbacks::FileEntered(SourceLocation Loc) { + SourceLocation LineLoc = getCorrectLocation(LastHashLoc); + switch (Status) { + default: + llvm_unreachable("Do not expect to enter a file from current scope"); + case NoScope: + updateStatusToNextScope(); + break; + case InitializedScope: + updateStatusToNextScope(); + return; + case BuiltinScope: + if (isCommandLineFile(PP.getSourceManager(), Loc)) + return; + updateStatusToNextScope(); + LLVM_FALLTHROUGH; + case CommandLineIncludeScope: + EnteredCommandLineIncludeFiles++; + break; + case MainFileScope: + break; + } + + Scopes.push_back(Gen->getCGDebugInfo()->CreateTempMacroFile(getCurrentScope(), + LineLoc, Loc)); +} + +void MacroPPCallbacks::FileExited(SourceLocation Loc) { + switch (Status) { + default: + llvm_unreachable("Do not expect to exit a file from current scope"); + case BuiltinScope: + if (!isBuiltinFile(PP.getSourceManager(), Loc)) + // Skip next scope and change status to MainFileScope. + Status = MainFileScope; + return; + case CommandLineIncludeScope: + if (!EnteredCommandLineIncludeFiles) { + updateStatusToNextScope(); + return; + } + EnteredCommandLineIncludeFiles--; + break; + case MainFileScope: + break; + } + + Scopes.pop_back(); +} + +void MacroPPCallbacks::FileChanged(SourceLocation Loc, FileChangeReason Reason, + SrcMgr::CharacteristicKind FileType, + FileID PrevFID) { + // Only care about enter file or exit file changes. + if (Reason == EnterFile) + FileEntered(Loc); + else if (Reason == ExitFile) + FileExited(Loc); +} + +void MacroPPCallbacks::InclusionDirective( + SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, + bool IsAngled, CharSourceRange FilenameRange, const FileEntry *File, + StringRef SearchPath, StringRef RelativePath, const Module *Imported) { + + // Record the line location of the current included file. + LastHashLoc = HashLoc; +} + +void MacroPPCallbacks::MacroDefined(const Token &MacroNameTok, + const MacroDirective *MD) { + IdentifierInfo *Id = MacroNameTok.getIdentifierInfo(); + SourceLocation location = getCorrectLocation(MacroNameTok.getLocation()); + std::string NameBuffer, ValueBuffer; + llvm::raw_string_ostream Name(NameBuffer); + llvm::raw_string_ostream Value(ValueBuffer); + writeMacroDefinition(*Id, *MD->getMacroInfo(), PP, Name, Value); + Gen->getCGDebugInfo()->CreateMacro(getCurrentScope(), + llvm::dwarf::DW_MACINFO_define, location, + Name.str(), Value.str()); +} + +void MacroPPCallbacks::MacroUndefined(const Token &MacroNameTok, + const MacroDefinition &MD) { + IdentifierInfo *Id = MacroNameTok.getIdentifierInfo(); + SourceLocation location = getCorrectLocation(MacroNameTok.getLocation()); + Gen->getCGDebugInfo()->CreateMacro(getCurrentScope(), + llvm::dwarf::DW_MACINFO_undef, location, + Id->getName(), ""); +} diff --git a/clang/lib/CodeGen/MacroPPCallbacks.h b/clang/lib/CodeGen/MacroPPCallbacks.h new file mode 100644 index 000000000000..f02801dc3275 --- /dev/null +++ b/clang/lib/CodeGen/MacroPPCallbacks.h @@ -0,0 +1,118 @@ +//===--- 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" + +namespace llvm { +class DIMacroFile; +class DIMacroNode; +} +namespace clang { +class Preprocessor; +class MacroInfo; +class CodeGenerator; + +class MacroPPCallbacks : public PPCallbacks { + /// A pointer to code generator, where debug info generator can be found. + CodeGenerator *Gen; + + /// Preprocessor. + Preprocessor &PP; + + /// Location of recent included file, used for line number. + SourceLocation LastHashLoc; + + /// Counts current number of command line included files, which were entered + /// and were not exited yet. + int EnteredCommandLineIncludeFiles = 0; + + enum FileScopeStatus { + NoScope = 0, // Scope is not initialized yet. + InitializedScope, // Main file scope is initialized but not set yet. + BuiltinScope, // and file scopes. + CommandLineIncludeScope, // Included file, from file, scope. + MainFileScope // Main file scope. + }; + FileScopeStatus Status; + + /// Parent contains all entered files that were not exited yet according to + /// the inclusion order. + llvm::SmallVector Scopes; + + /// Get current DIMacroFile scope. + /// \return current DIMacroFile scope or nullptr if there is no such scope. + llvm::DIMacroFile *getCurrentScope(); + + /// Get current line location or invalid location. + /// \param Loc current line location. + /// \return current line location \p `Loc`, or invalid location if it's in a + /// skipped file scope. + SourceLocation getCorrectLocation(SourceLocation Loc); + + /// Use the passed preprocessor to write the macro name and value from the + /// given macro info and identifier info into the given \p `Name` and \p + /// `Value` output streams. + /// + /// \param II Identifier info, used to get the Macro name. + /// \param MI Macro info, used to get the Macro argumets and values. + /// \param PP Preprocessor. + /// \param [out] Name Place holder for returned macro name and arguments. + /// \param [out] Value Place holder for returned macro value. + static void writeMacroDefinition(const IdentifierInfo &II, + const MacroInfo &MI, Preprocessor &PP, + raw_ostream &Name, raw_ostream &Value); + + /// Update current file scope status to next file scope. + void updateStatusToNextScope(); + + /// Handle the case when entering a file. + /// + /// \param Loc Indicates the new location. + /// \Return true if file scope status should be updated. + void FileEntered(SourceLocation Loc); + + /// Handle the case when exiting a file. + /// + /// \Return true if file scope status should be updated. + void FileExited(SourceLocation Loc); + +public: + MacroPPCallbacks(CodeGenerator *Gen, Preprocessor &PP); + + /// 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. + void FileChanged(SourceLocation Loc, FileChangeReason Reason, + SrcMgr::CharacteristicKind FileType, + FileID PrevFID = FileID()) override; + + /// Callback invoked whenever a directive (#xxx) is processed. + void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, + StringRef FileName, bool IsAngled, + CharSourceRange FilenameRange, const FileEntry *File, + StringRef SearchPath, StringRef RelativePath, + const Module *Imported) override; + + /// Hook called whenever a macro definition is seen. + void MacroDefined(const Token &MacroNameTok, + const MacroDirective *MD) override; + + /// Hook called whenever a macro \#undef is seen. + /// + /// MD is released immediately following this callback. + void MacroUndefined(const Token &MacroNameTok, + const MacroDefinition &MD) override; +}; + +} // end namespace clang diff --git a/clang/lib/CodeGen/ModuleBuilder.cpp b/clang/lib/CodeGen/ModuleBuilder.cpp index f925c2549175..89090c8b6a1b 100644 --- a/clang/lib/CodeGen/ModuleBuilder.cpp +++ b/clang/lib/CodeGen/ModuleBuilder.cpp @@ -92,6 +92,10 @@ namespace { return M.get(); } + CGDebugInfo *getCGDebugInfo() { + return Builder->getModuleDebugInfo(); + } + llvm::Module *ReleaseModule() { return M.release(); } @@ -299,6 +303,10 @@ llvm::Module *CodeGenerator::ReleaseModule() { return static_cast(this)->ReleaseModule(); } +CGDebugInfo *CodeGenerator::getCGDebugInfo() { + return static_cast(this)->getCGDebugInfo(); +} + const Decl *CodeGenerator::GetDeclForMangledName(llvm::StringRef name) { return static_cast(this)->GetDeclForMangledName(name); } diff --git a/clang/lib/Driver/Tools.cpp b/clang/lib/Driver/Tools.cpp index 7b48e1da9210..0a54418de779 100644 --- a/clang/lib/Driver/Tools.cpp +++ b/clang/lib/Driver/Tools.cpp @@ -5013,6 +5013,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DwarfVersion, DebuggerTuning); + // -fdebug-macro turns on macro debug info generation. + if (Args.hasFlag(options::OPT_fdebug_macro, options::OPT_fno_debug_macro, + false)) + CmdArgs.push_back("-debug-info-macro"); + // -ggnu-pubnames turns on gnu style pubnames in the backend. if (Args.hasArg(options::OPT_ggnu_pubnames)) { CmdArgs.push_back("-backend-option"); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index a6a776619125..3cdefa963683 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -505,6 +505,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.DwarfVersion = getLastArgIntValue(Args, OPT_dwarf_version_EQ, 0, Diags); Opts.DebugColumnInfo = Args.hasArg(OPT_dwarf_column_info); Opts.EmitCodeView = Args.hasArg(OPT_gcodeview); + Opts.MacroDebugInfo = Args.hasArg(OPT_debug_info_macro); Opts.WholeProgramVTables = Args.hasArg(OPT_fwhole_program_vtables); Opts.LTOVisibilityPublicStd = Args.hasArg(OPT_flto_visibility_public_std); Opts.SplitDwarfFile = Args.getLastArgValue(OPT_split_dwarf_file); diff --git a/clang/test/CodeGen/debug-info-macro.c b/clang/test/CodeGen/debug-info-macro.c new file mode 100644 index 000000000000..b98b3ad6a779 --- /dev/null +++ b/clang/test/CodeGen/debug-info-macro.c @@ -0,0 +1,57 @@ +// RUN: %clang_cc1 -emit-llvm -debug-info-kind=line-tables-only -debug-info-macro %s -o - "-DC1(x)=( x + 5 )" -DA -include %S/include/debug-info-macro.h -UC1 | FileCheck -check-prefixes=CHECK,NO_PCH %s +// RUN: %clang_cc1 -emit-llvm -debug-info-kind=limited -debug-info-macro %s -o - "-DC1(x)=( x + 5 )" -DA -include %S/include/debug-info-macro.h -UC1 | FileCheck -check-prefixes=CHECK,NO_PCH %s +// RUN: %clang_cc1 -emit-llvm -debug-info-kind=standalone -debug-info-macro %s -o - "-DC1(x)=( x + 5 )" -DA -include %S/include/debug-info-macro.h -UC1 | FileCheck -check-prefixes=CHECK,NO_PCH %s +// RUN: %clang_cc1 -emit-llvm -debug-info-macro %s -o - "-DC1(x)=( x + 5 )" -DA -include %S/include/debug-info-macro.h -UC1 | FileCheck -check-prefixes=NO_MACRO %s + +// RUN: %clang_cc1 -emit-llvm -debug-info-kind=limited -debug-info-macro %S/include/debug-info-macro.h -emit-pch -o %t.pch -DC3 +// RUN: %clang_cc1 -emit-llvm -debug-info-kind=limited -debug-info-macro %s -o - -include-pch %t.pch "-DC1(x)=( x + 5 )" -DA -include %S/include/debug-info-macro.h -UC1 | FileCheck -check-prefixes=CHECK,PCH %s + +// This test checks that macro Debug info is correctly generated. + +// TODO: Check for an following entry once support macros defined in pch files. +// -PCH: !DIMacro(type: DW_MACINFO_define, name: "C3", value: "1")> + +#line 15 +/*Line 15*/ #define D1 1 +/*Line 16*/ #include "include/debug-info-macro.h" +/*Line 17*/ #undef D1 +/*Line 18*/ #define D2 2 +/*Line 19*/ #include "include/debug-info-macro.h" +/*Line 20*/ #undef D2 + +// NO_MACRO-NOT: macros +// NO_MACRO-NOT: DIMacro +// NO_MACRO-NOT: DIMacroFile + +// CHECK: !DICompileUnit({{.*}} macros: [[Macros:![0-9]+]]) +// CHECK: [[EmptyMD:![0-9]+]] = !{} + +// NO_PCH: [[Macros]] = !{[[MainMacroFile:![0-9]+]], [[BuiltinMacro:![0-9]+]], {{.*}}, [[DefineC1:![0-9]+]], [[DefineA:![0-9]+]], [[UndefC1:![0-9]+]]} +// PCH: [[Macros]] = !{[[MainMacroFile:![0-9]+]], [[DefineC1:![0-9]+]], [[DefineA:![0-9]+]], [[UndefC1:![0-9]+]]} + +// CHECK: [[MainMacroFile]] = !DIMacroFile(file: [[MainFile:![0-9]+]], nodes: [[N1:![0-9]+]]) +// CHECK: [[MainFile]] = !DIFile(filename: "{{.*}}debug-info-macro.c" +// CHECK: [[N1]] = !{[[CommandLineInclude:![0-9]+]], [[DefineD1:![0-9]+]], [[FileInclude1:![0-9]+]], [[UndefD1:![0-9]+]], [[DefineD2:![0-9]+]], [[FileInclude2:![0-9]+]], [[UndefD2:![0-9]+]]} + +// CHECK: [[CommandLineInclude]] = !DIMacroFile(file: [[HeaderFile:![0-9]+]], nodes: [[N2:![0-9]+]]) +// CHECK: [[HeaderFile]] = !DIFile(filename: "{{.*}}debug-info-macro.h" +// CHECK: [[N2]] = !{[[UndefA:![0-9]+]]} +// CHECK: [[UndefA]] = !DIMacro(type: DW_MACINFO_undef, line: 11, name: "A") + +// CHECK: [[DefineD1]] = !DIMacro(type: DW_MACINFO_define, line: 15, name: "D1", value: "1") +// CHECK: [[FileInclude1]] = !DIMacroFile(line: 16, file: [[HeaderFile]], nodes: [[N3:![0-9]+]]) +// CHECK: [[N3]] = !{[[DefineAx:![0-9]+]], [[UndefA]]} +// CHECK: [[DefineAx]] = !DIMacro(type: DW_MACINFO_define, line: 3, name: "A(x,y,z)", value: "(x)") +// CHECK: [[UndefD1]] = !DIMacro(type: DW_MACINFO_undef, line: 17, name: "D1") + +// CHECK: [[DefineD2]] = !DIMacro(type: DW_MACINFO_define, line: 18, name: "D2", value: "2") +// CHECK: [[FileInclude2]] = !DIMacroFile(line: 19, file: [[HeaderFile]], nodes: [[N4:![0-9]+]]) +// CHECK: [[N4]] = !{[[DefineAy:![0-9]+]], [[UndefA]]} +// CHECK: [[DefineAy]] = !DIMacro(type: DW_MACINFO_define, line: 7, name: "A(x,y,z)", value: "(y)") +// CHECK: [[UndefD2]] = !DIMacro(type: DW_MACINFO_undef, line: 20, name: "D2") + +// NO_PCH: [[BuiltinMacro]] = !DIMacro(type: DW_MACINFO_define, name: "__llvm__", value: "1") + +// CHECK: [[DefineC1]] = !DIMacro(type: DW_MACINFO_define, name: "C1(x)", value: "( x + 5 )") +// CHECK: [[DefineA]] = !DIMacro(type: DW_MACINFO_define, name: "A", value: "1") +// CHECK: [[UndefC1]] = !DIMacro(type: DW_MACINFO_undef, name: "C1") diff --git a/clang/test/CodeGen/include/debug-info-macro.h b/clang/test/CodeGen/include/debug-info-macro.h new file mode 100644 index 000000000000..f71d5c3343d2 --- /dev/null +++ b/clang/test/CodeGen/include/debug-info-macro.h @@ -0,0 +1,12 @@ + +#ifdef D1 +/*Line 3*/ #define A(x, y, z) (x) +#endif + +#ifdef D2 +/*Line 7*/ #define A(x, y, z) (y) +#endif + +#ifdef A +/*Line 11*/ #undef A +#endif diff --git a/clang/test/Driver/debug-options.c b/clang/test/Driver/debug-options.c index 94c769fa37d3..be50ee8af701 100644 --- a/clang/test/Driver/debug-options.c +++ b/clang/test/Driver/debug-options.c @@ -214,3 +214,9 @@ // BADSTRING1: error: invalid value 'watkind' in '-debug-info-kind=watkind' // RUN: not %clang -cc1 -debugger-tuning=gmodal 2>&1 | FileCheck -check-prefix=BADSTRING2 %s // BADSTRING2: error: invalid value 'gmodal' in '-debugger-tuning=gmodal' + +// RUN: %clang -### -fdebug-macro %s 2>&1 | FileCheck -check-prefix=MACRO %s +// RUN: %clang -### -fno-debug-macro %s 2>&1 | FileCheck -check-prefix=NOMACRO %s +// RUN: %clang -### %s 2>&1 | FileCheck -check-prefix=NOMACRO %s +// MACRO: "-debug-info-macro" +// NOMACRO-NOT: "-debug-info-macro"