Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -989,7 +989,8 @@ HelpText<"Emit full debug info for all types used by the program">; def fno_standalone_debug : Flag<["-"], "fno-standalone-debug">, Group, Flags<[CC1Option]>, HelpText<"Limit debug information produced to reduce size of debug binary">; -def flimit_debug_info : Flag<["-"], "flimit-debug-info">, Alias; +def flimit_debug_info : Flag<["-"], "flimit-debug-info">, Alias, + Flags<[CC1Option]>; def fno_limit_debug_info : Flag<["-"], "fno-limit-debug-info">, Alias; def fstrict_aliasing : Flag<["-"], "fstrict-aliasing">, Group, Flags<[DriverOption, CoreOption]>; Index: include/clang/Driver/ToolChain.h =================================================================== --- include/clang/Driver/ToolChain.h +++ include/clang/Driver/ToolChain.h @@ -279,6 +279,16 @@ /// compile unit information. virtual bool UseDwarfDebugFlags() const { return false; } + // Return the DWARF version to emit, in the absence of arguments + // to the contrary. + virtual unsigned GetDefaultDwarfVersion() const { return 4; } + + // True if the driver should assume "-fstandalone-debug" + // in the absence of an option specifying otherwise, + // provided that debugging was requested in the first place. + // i.e. a value of 'true' does not imply that debugging is wanted. + virtual bool GetDefaultStandaloneDebug() const { return false; } + /// UseSjLjExceptions - Does this tool chain use SjLj exceptions. virtual bool UseSjLjExceptions() const { return false; } Index: lib/Driver/ToolChains.h =================================================================== --- lib/Driver/ToolChains.h +++ lib/Driver/ToolChains.h @@ -508,6 +508,12 @@ void AddLinkARCArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; + + unsigned GetDefaultDwarfVersion() const override { return 2; } + // Until dtrace (via CTF) and LLDB can deal with distributed debug info, + // Darwin defaults to standalone/full debug info. + bool GetDefaultStandaloneDebug() const override { return true; } + /// } private: @@ -564,6 +570,8 @@ const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + unsigned GetDefaultDwarfVersion() const override { return 2; } + protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; @@ -615,6 +623,7 @@ unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const override { return 2; } + unsigned GetDefaultDwarfVersion() const override { return 2; } protected: Tool *buildAssembler() const override; @@ -661,6 +670,10 @@ bool UseSjLjExceptions() const override; bool isPIEDefault() const override; SanitizerMask getSupportedSanitizers() const override; + unsigned GetDefaultDwarfVersion() const override { return 2; } + // Until dtrace (via CTF) and LLDB can deal with distributed debug info, + // FreeBSD defaults to standalone/full debug info. + bool GetDefaultStandaloneDebug() const override { return true; } protected: Tool *buildAssembler() const override; Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -24,6 +24,7 @@ #include "clang/Driver/SanitizerArgs.h" #include "clang/Driver/ToolChain.h" #include "clang/Driver/Util.h" +#include "clang/Frontend/CodeGenOptions.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" @@ -3797,43 +3798,70 @@ : "-"); } - // Use the last option from "-g" group. "-gline-tables-only" and "-gdwarf-x" - // are preserved, all other debug options are substituted with "-g". + // The 'g' groups options involve a somewhat intricate sequence of decisions + // about what to pass from the driver to the frontend, but by the time they + // reach cc1 they've been factored into two well-defined orthogonal choices: + // * what level of debug info to generate + // * what dwarf version to write + // This avoids having to monkey around further in cc1 other than to disable + // codeview if not running in a Windows environment. Perhaps even that + // decision should be made in the driver as well though. + enum CodeGenOptions::DebugInfoKind DebugInfoKind = + CodeGenOptions::NoDebugInfo; + unsigned DwarfVersion = 0; + Args.ClaimAllArgs(options::OPT_g_Group); Arg *SplitDwarfArg = Args.getLastArg(options::OPT_gsplit_dwarf); if (Arg *A = Args.getLastArg(options::OPT_g_Group)) { + // 'g1' and 'line tables' are synonymous, but not specified as aliases + // in Options.td - perhaps they should be. if ((A->getOption().matches(options::OPT_gline_tables_only) || A->getOption().matches(options::OPT_g1)) && + // If you say "-gline-tables-only -gsplit-dwarf", the split-dwarf wins. + // It is not a g_Group option, hence this extra test. (!SplitDwarfArg || A->getIndex() > SplitDwarfArg->getIndex())) { + DebugInfoKind = CodeGenOptions::DebugLineTablesOnly; // FIXME: we should support specifying dwarf version with // -gline-tables-only. - CmdArgs.push_back("-gline-tables-only"); - // Default is dwarf-2 for Darwin, OpenBSD, FreeBSD and Solaris. - const llvm::Triple &Triple = getToolChain().getTriple(); - if (Triple.isOSDarwin() || Triple.getOS() == llvm::Triple::OpenBSD || - Triple.getOS() == llvm::Triple::FreeBSD || - Triple.getOS() == llvm::Triple::Solaris) - CmdArgs.push_back("-gdwarf-2"); + // But: Does the preceding FIXME mean that only the option parser + // was busted, or that the emitter can't handle it? This is not clear. + // At any rate, the new logic should have a much better time + // at fixing this, if in fact it is fundamentally non-broken. + DwarfVersion = getToolChain().GetDefaultDwarfVersion(); SplitDwarfArg = nullptr; } else if (A->getOption().matches(options::OPT_gdwarf_2) || A->getOption().matches(options::OPT_gdwarf_3) || A->getOption().matches(options::OPT_gdwarf_4)) { - A->render(Args, CmdArgs); + DebugInfoKind = CodeGenOptions::LimitedDebugInfo; + switch (A->getOption().getID()) { + case options::OPT_gdwarf_2: + DwarfVersion = 2; + break; + case options::OPT_gdwarf_3: + DwarfVersion = 3; + break; + default: + DwarfVersion = 4; + break; + } } else if (!A->getOption().matches(options::OPT_g0) && !A->getOption().matches(options::OPT_ggdb0)) { - // Default is dwarf-2 for Darwin, OpenBSD, FreeBSD and Solaris. - const llvm::Triple &Triple = getToolChain().getTriple(); - if (Triple.isOSDarwin() || Triple.getOS() == llvm::Triple::OpenBSD || - Triple.getOS() == llvm::Triple::FreeBSD || - Triple.getOS() == llvm::Triple::Solaris) - CmdArgs.push_back("-gdwarf-2"); - else - CmdArgs.push_back("-g"); + // Some 'g' group option other than one expressly disabling debug info + // must have been the final (winning) one. They're all equivalent. + DebugInfoKind = CodeGenOptions::LimitedDebugInfo; + DwarfVersion = getToolChain().GetDefaultDwarfVersion(); } } // Forward -gcodeview. - Args.AddLastArg(CmdArgs, options::OPT_gcodeview); + if (Args.hasArg(options::OPT_gcodeview)) { + CmdArgs.push_back("-gcodeview"); + // With codeview, if an explicit choice of gdwarf was not made, then + // DwarfVersion is reset to 0 so that both kinds of info are not emitted. + if (!Args.getLastArg(options::OPT_gdwarf_2, options::OPT_gdwarf_3, + options::OPT_gdwarf_4)) + DwarfVersion = 0; + } // We ignore flags -gstrict-dwarf and -grecord-gcc-switches for now. Args.ClaimAllArgs(options::OPT_g_flags_Group); @@ -3843,7 +3871,7 @@ // FIXME: Move backend command line options to the module. if (Args.hasArg(options::OPT_gmodules)) { - CmdArgs.push_back("-g"); + DebugInfoKind = CodeGenOptions::LimitedDebugInfo; CmdArgs.push_back("-dwarf-ext-refs"); CmdArgs.push_back("-fmodule-format=obj"); } @@ -3852,11 +3880,50 @@ // splitting and extraction. // FIXME: Currently only works on Linux. if (getToolChain().getTriple().isOSLinux() && SplitDwarfArg) { - CmdArgs.push_back("-g"); + DebugInfoKind = CodeGenOptions::LimitedDebugInfo; CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-split-dwarf=Enable"); } + // After we've dealt with all combinations of things that could + // make DebugInfoKind be other than None or DebugLineTablesOnly, + // figure out if we need to "upgrade" it to standalone debug info. + // We parse these two '-f' options whether or not they will be used, + // to claim them even if you wrote "-fstandalone-debug -gline-tables-only" + bool NeedFullDebug = Args.hasFlag(options::OPT_fstandalone_debug, + options::OPT_fno_standalone_debug, + getToolChain().GetDefaultStandaloneDebug()); + if (DebugInfoKind == CodeGenOptions::LimitedDebugInfo && NeedFullDebug) + DebugInfoKind = CodeGenOptions::FullDebugInfo; + + // Now, if DebugInfoKind is not None, emit the CC1 option for it. + switch (DebugInfoKind) { + case CodeGenOptions::DebugLineTablesOnly: + CmdArgs.push_back("-gline-tables-only"); + break; + case CodeGenOptions::LimitedDebugInfo: + CmdArgs.push_back("-flimit-debug-info"); + break; + case CodeGenOptions::FullDebugInfo: + CmdArgs.push_back("-fstandalone-debug"); + break; + default: + break; + } + switch (DwarfVersion) { + case 2: + CmdArgs.push_back("-gdwarf-2"); + break; + case 3: + CmdArgs.push_back("-gdwarf-3"); + break; + case 4: + CmdArgs.push_back("-gdwarf-4"); + break; + default: + break; + } + // -ggnu-pubnames turns on gnu style pubnames in the backend. if (Args.hasArg(options::OPT_ggnu_pubnames)) { CmdArgs.push_back("-backend-option"); @@ -4219,8 +4286,6 @@ // Forward -f (flag) options which we can pass directly. Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls); Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions); - Args.AddLastArg(CmdArgs, options::OPT_fstandalone_debug); - Args.AddLastArg(CmdArgs, options::OPT_fno_standalone_debug); Args.AddLastArg(CmdArgs, options::OPT_fno_operator_names); // Emulated TLS is enabled by default on Android, and can be enabled manually // with -femulated-tls. Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -393,37 +393,47 @@ Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name; } - if (Args.hasArg(OPT_gline_tables_only)) { - Opts.setDebugInfo(CodeGenOptions::DebugLineTablesOnly); - } else if (Args.hasArg(OPT_g_Flag) || Args.hasArg(OPT_gdwarf_2) || - Args.hasArg(OPT_gdwarf_3) || Args.hasArg(OPT_gdwarf_4)) { - bool Default = false; - // Until dtrace (via CTF) and LLDB can deal with distributed debug info, - // Darwin and FreeBSD default to standalone/full debug info. - if (llvm::Triple(TargetOpts.Triple).isOSDarwin() || - llvm::Triple(TargetOpts.Triple).isOSFreeBSD()) - Default = true; - - if (Args.hasFlag(OPT_fstandalone_debug, OPT_fno_standalone_debug, Default)) - Opts.setDebugInfo(CodeGenOptions::FullDebugInfo); - else - Opts.setDebugInfo(CodeGenOptions::LimitedDebugInfo); + // There are three levels of user-requestable debug info (aside from "none", + // and not counting "location tracking only" which isn't user-requested). + // Use the last of the flags that set any of the three interesting levels. + // In the Driver, "limit-debug-info" is synonymous with "no-standalone-debug", + // but the "no" option name is very confusing as part of a multiway switch. + // Read "limit_debug_info" as "LimitedDebugInfo" and it makes perfect sense. + if (Arg *A = Args.getLastArg(OPT_fstandalone_debug, OPT_flimit_debug_info, + OPT_gline_tables_only)) { + enum CodeGenOptions::DebugInfoKind Kind; + switch (A->getOption().getID()) { + case OPT_fstandalone_debug: + Kind = CodeGenOptions::FullDebugInfo; + break; + case OPT_flimit_debug_info: + Kind = CodeGenOptions::LimitedDebugInfo; + break; + default: + Kind = CodeGenOptions::DebugLineTablesOnly; + break; + } + Opts.setDebugInfo(Kind); } - Opts.DebugColumnInfo = Args.hasArg(OPT_dwarf_column_info); - if (Args.hasArg(OPT_gcodeview)) { - Opts.EmitCodeView = true; - Opts.DwarfVersion = 0; - } else if (Opts.getDebugInfo() != CodeGenOptions::NoDebugInfo) { - // Default Dwarf version is 4 if we are generating debug information. - Opts.DwarfVersion = 4; + // Dwarf Version is one of {0,2,3,4}. There is no explicit flag for 0. + // It is the assumed default regardless of whether debug info was requested, + // so the driver had better pick one if debug info is to be produced. + if (Arg *A = Args.getLastArg(OPT_gdwarf_4, OPT_gdwarf_3, OPT_gdwarf_2)) { + switch (A->getOption().getID()) { + case OPT_gdwarf_2: + Opts.DwarfVersion = 2; + break; + case OPT_gdwarf_3: + Opts.DwarfVersion = 3; + break; + default: + Opts.DwarfVersion = 4; + break; + } } + Opts.DebugColumnInfo = Args.hasArg(OPT_dwarf_column_info); + Opts.EmitCodeView = Args.hasArg(OPT_gcodeview); Opts.SplitDwarfFile = Args.getLastArgValue(OPT_split_dwarf_file); - if (Args.hasArg(OPT_gdwarf_2)) - Opts.DwarfVersion = 2; - else if (Args.hasArg(OPT_gdwarf_3)) - Opts.DwarfVersion = 3; - else if (Args.hasArg(OPT_gdwarf_4)) - Opts.DwarfVersion = 4; Opts.DebugTypeExtRefs = Args.hasArg(OPT_dwarf_ext_refs); if (const Arg *A =