diff --git a/clang-tools-extra/clangd/CompileCommands.cpp b/clang-tools-extra/clangd/CompileCommands.cpp --- a/clang-tools-extra/clangd/CompileCommands.cpp +++ b/clang-tools-extra/clangd/CompileCommands.cpp @@ -494,7 +494,7 @@ static constexpr llvm::ArrayRef NAME( \ NAME##_init, std::size(NAME##_init) - 1); #define OPTION(PREFIX, PREFIXED_NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, \ - FLAGS, PARAM, HELP, METAVAR, VALUES) \ + FLAGS, VISIBILITY, PARAM, HELP, METAVAR, VALUES) \ Prefixes[DriverID::OPT_##ID] = PREFIX; #include "clang/Driver/Options.inc" #undef OPTION @@ -506,7 +506,7 @@ const void *AliasArgs; } AliasTable[] = { #define OPTION(PREFIX, PREFIXED_NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, \ - FLAGS, PARAM, HELP, METAVAR, VALUES) \ + FLAGS, VISIBILITY, PARAM, HELP, METAVAR, VALUES) \ {DriverID::OPT_##ID, DriverID::OPT_##ALIAS, ALIASARGS}, #include "clang/Driver/Options.inc" #undef OPTION diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -423,9 +423,9 @@ #define PARSE_OPTION_WITH_MARSHALLING( \ ARGS, DIAGS, PREFIX_TYPE, SPELLING, ID, KIND, GROUP, ALIAS, ALIASARGS, \ - FLAGS, PARAM, HELPTEXT, METAVAR, VALUES, SHOULD_PARSE, ALWAYS_EMIT, \ - KEYPATH, DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, \ - DENORMALIZER, MERGER, EXTRACTOR, TABLE_INDEX) \ + FLAGS, VISIBILITY, PARAM, HELPTEXT, METAVAR, VALUES, SHOULD_PARSE, \ + ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, \ + NORMALIZER, DENORMALIZER, MERGER, EXTRACTOR, TABLE_INDEX) \ if ((FLAGS)&options::CC1Option) { \ KEYPATH = MERGER(KEYPATH, DEFAULT_VALUE); \ if (IMPLIED_CHECK) \ @@ -440,9 +440,9 @@ // with lifetime extension of the reference. #define GENERATE_OPTION_WITH_MARSHALLING( \ CONSUMER, PREFIX_TYPE, SPELLING, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, \ - PARAM, HELPTEXT, METAVAR, VALUES, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \ - DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \ - MERGER, EXTRACTOR, TABLE_INDEX) \ + VISIBILKITY, PARAM, HELPTEXT, METAVAR, VALUES, SHOULD_PARSE, ALWAYS_EMIT, \ + KEYPATH, DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, \ + DENORMALIZER, MERGER, EXTRACTOR, TABLE_INDEX) \ if ((FLAGS)&options::CC1Option) { \ [&](const auto &Extracted) { \ if (ALWAYS_EMIT || \ diff --git a/lld/MachO/DriverUtils.cpp b/lld/MachO/DriverUtils.cpp --- a/lld/MachO/DriverUtils.cpp +++ b/lld/MachO/DriverUtils.cpp @@ -44,9 +44,13 @@ // Create table mapping all options defined in Options.td static constexpr OptTable::Info optInfo[] = { -#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \ - {X1, X2, X10, X11, OPT_##ID, Option::KIND##Class, \ - X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12}, +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, \ + VISIBILITY, PARAM, HELPTEXT, METAVAR, VALUES) \ + {PREFIX, NAME, HELPTEXT, \ + METAVAR, OPT_##ID, opt::Option::KIND##Class, \ + PARAM, FLAGS, VISIBILITY, \ + OPT_##GROUP, OPT_##ALIAS, ALIASARGS, \ + VALUES}, #include "Options.inc" #undef OPTION }; diff --git a/lld/MinGW/Driver.cpp b/lld/MinGW/Driver.cpp --- a/lld/MinGW/Driver.cpp +++ b/lld/MinGW/Driver.cpp @@ -71,9 +71,13 @@ // Create table mapping all options defined in Options.td static constexpr opt::OptTable::Info infoTable[] = { -#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \ - {X1, X2, X10, X11, OPT_##ID, opt::Option::KIND##Class, \ - X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12}, +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, \ + VISIBILITY, PARAM, HELPTEXT, METAVAR, VALUES) \ + {PREFIX, NAME, HELPTEXT, \ + METAVAR, OPT_##ID, opt::Option::KIND##Class, \ + PARAM, FLAGS, VISIBILITY, \ + OPT_##GROUP, OPT_##ALIAS, ALIASARGS, \ + VALUES}, #include "Options.inc" #undef OPTION }; diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -111,9 +111,13 @@ // Create table mapping all options defined in Options.td static constexpr opt::OptTable::Info optInfo[] = { -#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \ - {X1, X2, X10, X11, OPT_##ID, opt::Option::KIND##Class, \ - X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12}, +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, \ + VISIBILITY, PARAM, HELPTEXT, METAVAR, VALUES) \ + {PREFIX, NAME, HELPTEXT, \ + METAVAR, OPT_##ID, opt::Option::KIND##Class, \ + PARAM, FLAGS, VISIBILITY, \ + OPT_##GROUP, OPT_##ALIAS, ALIASARGS, \ + VALUES}, #include "Options.inc" #undef OPTION }; diff --git a/llvm/include/llvm/Option/OptParser.td b/llvm/include/llvm/Option/OptParser.td --- a/llvm/include/llvm/Option/OptParser.td +++ b/llvm/include/llvm/Option/OptParser.td @@ -73,6 +73,13 @@ // (only sensible on joined options). def RenderSeparate : OptionFlag; +// Define Visibility categories + +class OptionVisibility {} + +// Explicit specifier for default visibility +def Default : OptionVisibility; + // Define the option group class. class OptionGroup { @@ -81,6 +88,7 @@ string HelpText = ?; OptionGroup Group = ?; list Flags = []; + list Vis = []; } // Define the option class. @@ -97,6 +105,7 @@ string Values = ?; code ValuesCode = ?; list Flags = []; + list Vis = [Default]; OptionGroup Group = ?; Option Alias = ?; list AliasArgs = []; @@ -141,6 +150,7 @@ class AliasArgs aliasargs> { list AliasArgs = aliasargs; } class EnumName { string EnumName = name; } class Flags flags> { list Flags = flags; } +class Vis vis> { list Vis = vis; } class Group { OptionGroup Group = group; } class HelpText { string HelpText = text; } class MetaVarName { string MetaVarName = name; } diff --git a/llvm/include/llvm/Option/OptTable.h b/llvm/include/llvm/Option/OptTable.h --- a/llvm/include/llvm/Option/OptTable.h +++ b/llvm/include/llvm/Option/OptTable.h @@ -30,6 +30,18 @@ class InputArgList; class Option; +/// Helper for overload resolution while transitioning from +/// FlagsToInclude/FlagsToExclude APIs to VisibilityMask APIs. +class Visibility { + unsigned Mask = ~0U; + +public: + explicit Visibility(unsigned Mask) : Mask(Mask) {} + Visibility() = default; + + operator unsigned() const { return Mask; } +}; + /// Provide access to the Option info table. /// /// The OptTable class provides a layer of indirection which allows Option @@ -51,6 +63,7 @@ unsigned char Kind; unsigned char Param; unsigned int Flags; + unsigned int Visibility; unsigned short GroupID; unsigned short AliasID; const char *AliasArgs; @@ -180,10 +193,8 @@ /// string includes prefix dashes "-" as well as values "=l". /// \param [out] NearestString - The nearest option string found in the /// OptTable. - /// \param [in] FlagsToInclude - Only find options with any of these flags. - /// Zero is the default, which includes all flags. - /// \param [in] FlagsToExclude - Don't find options with this flag. Zero - /// is the default, and means exclude nothing. + /// \param [in] VisibilityMask - Only include options with any of these + /// visibility flags set. /// \param [in] MinimumLength - Don't find options shorter than this length. /// For example, a minimum length of 3 prevents "-x" from being considered /// near to "-S". @@ -192,13 +203,29 @@ /// /// \return The edit distance of the nearest string found. unsigned findNearest(StringRef Option, std::string &NearestString, - unsigned FlagsToInclude = 0, unsigned FlagsToExclude = 0, + Visibility VisibilityMask = Visibility(), unsigned MinimumLength = 4, unsigned MaximumDistance = UINT_MAX) const; + unsigned findNearest(StringRef Option, std::string &NearestString, + unsigned FlagsToInclude, unsigned FlagsToExclude = 0, + unsigned MinimumLength = 4, + unsigned MaximumDistance = UINT_MAX) const; + +private: + unsigned + internalFindNearest(StringRef Option, std::string &NearestString, + unsigned MinimumLength, unsigned MaximumDistance, + std::function ExcludeOption) const; + +public: + bool findExact(StringRef Option, std::string &ExactString, + Visibility VisibilityMask = Visibility()) const { + return findNearest(Option, ExactString, VisibilityMask, 4, 0) == 0; + } + bool findExact(StringRef Option, std::string &ExactString, - unsigned FlagsToInclude = 0, - unsigned FlagsToExclude = 0) const { + unsigned FlagsToInclude, unsigned FlagsToExclude = 0) const { return findNearest(Option, ExactString, FlagsToInclude, FlagsToExclude, 4, 0) == 0; } @@ -209,18 +236,26 @@ /// \param [in,out] Index - The current parsing position in the argument /// string list; on return this will be the index of the next argument /// string to parse. - /// \param [in] FlagsToInclude - Only parse options with any of these flags. - /// Zero is the default which includes all flags. - /// \param [in] FlagsToExclude - Don't parse options with this flag. Zero - /// is the default and means exclude nothing. + /// \param [in] VisibilityMask - Only include options with any of these + /// visibility flags set. /// /// \return The parsed argument, or 0 if the argument is missing values /// (in which case Index still points at the conceptual next argument string /// to parse). + std::unique_ptr + ParseOneArg(const ArgList &Args, unsigned &Index, + Visibility VisibilityMask = Visibility()) const; + std::unique_ptr ParseOneArg(const ArgList &Args, unsigned &Index, - unsigned FlagsToInclude = 0, - unsigned FlagsToExclude = 0) const; + unsigned FlagsToInclude, + unsigned FlagsToExclude) const; + +private: + std::unique_ptr + internalParseOneArg(const ArgList &Args, unsigned &Index, + std::function ExcludeOption) const; +public: /// Parse an list of arguments into an InputArgList. /// /// The resulting InputArgList will reference the strings in [\p ArgBegin, @@ -233,16 +268,25 @@ /// \param MissingArgIndex - On error, the index of the option which could /// not be parsed. /// \param MissingArgCount - On error, the number of missing options. - /// \param FlagsToInclude - Only parse options with any of these flags. - /// Zero is the default which includes all flags. - /// \param FlagsToExclude - Don't parse options with this flag. Zero - /// is the default and means exclude nothing. + /// \param VisibilityMask - Only include options with any of these + /// visibility flags set. /// \return An InputArgList; on error this will contain all the options /// which could be parsed. InputArgList ParseArgs(ArrayRef Args, unsigned &MissingArgIndex, - unsigned &MissingArgCount, unsigned FlagsToInclude = 0, + unsigned &MissingArgCount, + Visibility VisibilityMask = Visibility()) const; + + InputArgList ParseArgs(ArrayRef Args, unsigned &MissingArgIndex, + unsigned &MissingArgCount, unsigned FlagsToInclude, unsigned FlagsToExclude = 0) const; +private: + InputArgList + internalParseArgs(ArrayRef Args, unsigned &MissingArgIndex, + unsigned &MissingArgCount, + std::function ExcludeOption) const; + +public: /// A convenience helper which handles optional initial options populated from /// an environment variable, expands response files recursively and parses /// options. @@ -253,26 +297,32 @@ /// could be parsed. InputArgList parseArgs(int Argc, char *const *Argv, OptSpecifier Unknown, StringSaver &Saver, - function_ref ErrorFn) const; + std::function ErrorFn) const; /// Render the help text for an option table. /// /// \param OS - The stream to write the help text to. /// \param Usage - USAGE: Usage /// \param Title - OVERVIEW: Title - /// \param FlagsToInclude - If non-zero, only include options with any - /// of these flags set. - /// \param FlagsToExclude - Exclude options with any of these flags set. + /// \param VisibilityMask - Only in Visibility VisibilityMask,clude options with any of these + /// visibility flags set. + /// \param ShowHidden - If true, display options marked as HelpHidden /// \param ShowAllAliases - If true, display all options including aliases /// that don't have help texts. By default, we display /// only options that are not hidden and have help /// texts. + void printHelp(raw_ostream &OS, const char *Usage, const char *Title, + bool ShowHidden = false, bool ShowAllAliases = false, + Visibility VisibilityMask = Visibility()) const; + void printHelp(raw_ostream &OS, const char *Usage, const char *Title, unsigned FlagsToInclude, unsigned FlagsToExclude, bool ShowAllAliases) const; - void printHelp(raw_ostream &OS, const char *Usage, const char *Title, - bool ShowHidden = false, bool ShowAllAliases = false) const; +private: + void internalPrintHelp(raw_ostream &OS, const char *Usage, const char *Title, + bool ShowHidden, bool ShowAllAliases, + std::function ExcludeOption) const; }; /// Specialization of OptTable @@ -305,31 +355,32 @@ } // end namespace llvm -#define LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(ID_PREFIX, PREFIX, PREFIXED_NAME, ID, \ - KIND, GROUP, ALIAS, ALIASARGS, FLAGS, \ - PARAM, HELPTEXT, METAVAR, VALUES) \ +#define LLVM_MAKE_OPT_ID_WITH_ID_PREFIX( \ + ID_PREFIX, PREFIX, PREFIXED_NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, \ + FLAGS, VISIBILITY, PARAM, HELPTEXT, METAVAR, VALUES) \ ID_PREFIX##ID #define LLVM_MAKE_OPT_ID(PREFIX, PREFIXED_NAME, ID, KIND, GROUP, ALIAS, \ - ALIASARGS, FLAGS, PARAM, HELPTEXT, METAVAR, VALUES) \ + ALIASARGS, FLAGS, VISIBILITY, PARAM, HELPTEXT, \ + METAVAR, VALUES) \ LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(OPT_, PREFIX, PREFIXED_NAME, ID, KIND, \ - GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR, VALUE) + GROUP, ALIAS, ALIASARGS, FLAGS, VISIBILITY, \ + PARAM, HELPTEXT, METAVAR, VALUE) #define LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX( \ ID_PREFIX, PREFIX, PREFIXED_NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, \ - FLAGS, PARAM, HELPTEXT, METAVAR, VALUES) \ + FLAGS, VISIBILITY, PARAM, HELPTEXT, METAVAR, VALUES) \ llvm::opt::OptTable::Info { \ PREFIX, PREFIXED_NAME, HELPTEXT, METAVAR, ID_PREFIX##ID, \ - llvm::opt::Option::KIND##Class, PARAM, FLAGS, ID_PREFIX##GROUP, \ - ID_PREFIX##ALIAS, ALIASARGS, VALUES \ + llvm::opt::Option::KIND##Class, PARAM, FLAGS, VISIBILITY, \ + ID_PREFIX##GROUP, ID_PREFIX##ALIAS, ALIASARGS, VALUES \ } #define LLVM_CONSTRUCT_OPT_INFO(PREFIX, PREFIXED_NAME, ID, KIND, GROUP, ALIAS, \ - ALIASARGS, FLAGS, PARAM, HELPTEXT, METAVAR, \ - VALUES) \ - LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(OPT_, PREFIX, PREFIXED_NAME, ID, \ - KIND, GROUP, ALIAS, ALIASARGS, FLAGS, \ - PARAM, HELPTEXT, METAVAR, VALUES) + ALIASARGS, FLAGS, VISIBILITY, PARAM, HELPTEXT, \ + METAVAR, VALUES) \ + LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX( \ + OPT_, PREFIX, PREFIXED_NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, \ + VISIBILITY, PARAM, HELPTEXT, METAVAR, VALUES) #endif // LLVM_OPTION_OPTTABLE_H diff --git a/llvm/include/llvm/Option/Option.h b/llvm/include/llvm/Option/Option.h --- a/llvm/include/llvm/Option/Option.h +++ b/llvm/include/llvm/Option/Option.h @@ -37,6 +37,10 @@ RenderSeparate = (1 << 3) }; +enum DriverVisibility { + Default = (1 << 0), +}; + /// Option - Abstract representation for a single form of driver /// argument. /// @@ -183,6 +187,11 @@ return Info->Flags & Val; } + /// Test if this option has the visibility flag \a Val. + bool hasVisibilityFlag(unsigned Val) const { + return Info->Visibility & Val; + } + /// getUnaliasedOption - Return the final option this option /// aliases (itself, if the option has no alias). const Option getUnaliasedOption() const { diff --git a/llvm/lib/ExecutionEngine/JITLink/COFFDirectiveParser.cpp b/llvm/lib/ExecutionEngine/JITLink/COFFDirectiveParser.cpp --- a/llvm/lib/ExecutionEngine/JITLink/COFFDirectiveParser.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/COFFDirectiveParser.cpp @@ -36,6 +36,7 @@ PrefixTable(PrefixTable_init, std::size(PrefixTable_init) - 1); // Create table mapping all options defined in COFFOptions.td +using namespace llvm::opt; static constexpr opt::OptTable::Info infoTable[] = { #define OPTION(...) \ LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(COFF_OPT_, __VA_ARGS__), diff --git a/llvm/lib/Option/OptTable.cpp b/llvm/lib/Option/OptTable.cpp --- a/llvm/lib/Option/OptTable.cpp +++ b/llvm/lib/Option/OptTable.cpp @@ -225,10 +225,36 @@ return Ret; } +unsigned OptTable::findNearest(StringRef Option, std::string &NearestString, + Visibility VisibilityMask, + unsigned MinimumLength, + unsigned MaximumDistance) const { + return internalFindNearest( + Option, NearestString, MinimumLength, MaximumDistance, + [VisibilityMask](const Info &CandidateInfo) { + return (CandidateInfo.Visibility & VisibilityMask) == 0; + }); +} + unsigned OptTable::findNearest(StringRef Option, std::string &NearestString, unsigned FlagsToInclude, unsigned FlagsToExclude, unsigned MinimumLength, unsigned MaximumDistance) const { + return internalFindNearest( + Option, NearestString, MinimumLength, MaximumDistance, + [FlagsToInclude, FlagsToExclude](const Info &CandidateInfo) { + if (FlagsToInclude && !(CandidateInfo.Flags & FlagsToInclude)) + return true; + if (CandidateInfo.Flags & FlagsToExclude) + return true; + return false; + }); +} + +unsigned OptTable::internalFindNearest( + StringRef Option, std::string &NearestString, unsigned MinimumLength, + unsigned MaximumDistance, + std::function ExcludeOption) const { assert(!Option.empty()); // Consider each [option prefix + option name] pair as a candidate, finding @@ -248,12 +274,8 @@ if (CandidateName.size() < MinimumLength) continue; - // * If FlagsToInclude were specified, ignore options that don't include - // those flags. - if (FlagsToInclude && !(CandidateInfo.Flags & FlagsToInclude)) - continue; - // * Ignore options that contain the FlagsToExclude. - if (CandidateInfo.Flags & FlagsToExclude) + // Ignore options that are excluded via masks + if (ExcludeOption(CandidateInfo)) continue; // * Ignore positional argument option candidates (which do not @@ -315,8 +337,8 @@ // Parse a single argument, return the new argument, and update Index. If // GroupedShortOptions is true, -a matches "-abc" and the argument in Args will -// be updated to "-bc". This overload does not support -// FlagsToInclude/FlagsToExclude or case insensitive options. +// be updated to "-bc". This overload does not support VisibilityMask or case +// insensitive options. std::unique_ptr OptTable::parseOneArgGrouped(InputArgList &Args, unsigned &Index) const { // Anything that doesn't start with PrefixesUnion is an input, as is '-' @@ -380,9 +402,29 @@ return std::make_unique(getOption(UnknownOptionID), Str, Index++, CStr); } +std::unique_ptr OptTable::ParseOneArg(const ArgList &Args, unsigned &Index, + Visibility VisibilityMask) const { + return internalParseOneArg(Args, Index, [VisibilityMask](const Option &Opt) { + return !Opt.hasVisibilityFlag(VisibilityMask); + }); +} + std::unique_ptr OptTable::ParseOneArg(const ArgList &Args, unsigned &Index, unsigned FlagsToInclude, unsigned FlagsToExclude) const { + return internalParseOneArg( + Args, Index, [FlagsToInclude, FlagsToExclude](const Option &Opt) { + if (FlagsToInclude && !Opt.hasFlag(FlagsToInclude)) + return true; + if (Opt.hasFlag(FlagsToExclude)) + return true; + return false; + }); +} + +std::unique_ptr OptTable::internalParseOneArg( + const ArgList &Args, unsigned &Index, + std::function ExcludeOption) const { unsigned Prev = Index; StringRef Str = Args.getArgString(Index); @@ -418,9 +460,7 @@ Option Opt(Start, this); - if (FlagsToInclude && !Opt.hasFlag(FlagsToInclude)) - continue; - if (Opt.hasFlag(FlagsToExclude)) + if (ExcludeOption(Opt)) continue; // See if this option matches. @@ -444,11 +484,37 @@ Str.data()); } -InputArgList OptTable::ParseArgs(ArrayRef ArgArr, +InputArgList OptTable::ParseArgs(ArrayRef Args, + unsigned &MissingArgIndex, + unsigned &MissingArgCount, + Visibility VisibilityMask) const { + return internalParseArgs( + Args, MissingArgIndex, MissingArgCount, + [VisibilityMask](const Option &Opt) { + return !Opt.hasVisibilityFlag(VisibilityMask); + }); +} + +InputArgList OptTable::ParseArgs(ArrayRef Args, unsigned &MissingArgIndex, unsigned &MissingArgCount, unsigned FlagsToInclude, unsigned FlagsToExclude) const { + return internalParseArgs( + Args, MissingArgIndex, MissingArgCount, + [FlagsToInclude, FlagsToExclude](const Option &Opt) { + if (FlagsToInclude && !Opt.hasFlag(FlagsToInclude)) + return true; + if (Opt.hasFlag(FlagsToExclude)) + return true; + return false; + }); +} + +InputArgList OptTable::internalParseArgs( + ArrayRef ArgArr, unsigned &MissingArgIndex, + unsigned &MissingArgCount, + std::function ExcludeOption) const { InputArgList Args(ArgArr.begin(), ArgArr.end()); // FIXME: Handle '@' args (or at least error on them). @@ -481,7 +547,7 @@ unsigned Prev = Index; std::unique_ptr A = GroupedShortOptions ? parseOneArgGrouped(Args, Index) - : ParseOneArg(Args, Index, FlagsToInclude, FlagsToExclude); + : internalParseOneArg(Args, Index, ExcludeOption); assert((Index > Prev || GroupedShortOptions) && "Parser failed to consume argument."); @@ -502,7 +568,7 @@ InputArgList OptTable::parseArgs(int Argc, char *const *Argv, OptSpecifier Unknown, StringSaver &Saver, - function_ref ErrorFn) const { + std::function ErrorFn) const { SmallVector NewArgv; // The environment variable specifies initial options which can be overridden // by commnad line options. @@ -626,14 +692,35 @@ } void OptTable::printHelp(raw_ostream &OS, const char *Usage, const char *Title, - bool ShowHidden, bool ShowAllAliases) const { - printHelp(OS, Usage, Title, /*Include*/ 0, /*Exclude*/ - (ShowHidden ? 0 : HelpHidden), ShowAllAliases); + bool ShowHidden, bool ShowAllAliases, + Visibility VisibilityMask) const { + return internalPrintHelp( + OS, Usage, Title, ShowHidden, ShowAllAliases, + [VisibilityMask](const Info &CandidateInfo) -> bool { + return (CandidateInfo.Visibility & VisibilityMask) == 0; + }); } void OptTable::printHelp(raw_ostream &OS, const char *Usage, const char *Title, unsigned FlagsToInclude, unsigned FlagsToExclude, bool ShowAllAliases) const { + bool ShowHidden = !(FlagsToExclude & HelpHidden); + FlagsToExclude &= ~HelpHidden; + return internalPrintHelp( + OS, Usage, Title, ShowHidden, ShowAllAliases, + [FlagsToInclude, FlagsToExclude](const Info &CandidateInfo) { + if (FlagsToInclude && !(CandidateInfo.Flags & FlagsToInclude)) + return true; + if (CandidateInfo.Flags & FlagsToExclude) + return true; + return false; + }); +} + +void OptTable::internalPrintHelp( + raw_ostream &OS, const char *Usage, const char *Title, bool ShowHidden, + bool ShowAllAliases, + std::function ExcludeOption) const { OS << "OVERVIEW: " << Title << "\n\n"; OS << "USAGE: " << Usage << "\n\n"; @@ -646,10 +733,11 @@ if (getOptionKind(Id) == Option::GroupClass) continue; - unsigned Flags = getInfo(Id).Flags; - if (FlagsToInclude && !(Flags & FlagsToInclude)) + const Info &CandidateInfo = getInfo(Id); + if (!ShowHidden && (CandidateInfo.Flags & opt::HelpHidden)) continue; - if (Flags & FlagsToExclude) + + if (ExcludeOption(CandidateInfo)) continue; // If an alias doesn't have a help text, show a help text for the aliased diff --git a/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp b/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp --- a/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp +++ b/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp @@ -45,6 +45,7 @@ #include "Options.inc" #undef PREFIX +using namespace llvm::opt; static constexpr opt::OptTable::Info InfoTable[] = { #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__), #include "Options.inc" diff --git a/llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp b/llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp --- a/llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp +++ b/llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp @@ -51,6 +51,7 @@ #include "Options.inc" #undef PREFIX +using namespace llvm::opt; static constexpr opt::OptTable::Info InfoTable[] = { #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__), #include "Options.inc" diff --git a/llvm/tools/dsymutil/dsymutil.cpp b/llvm/tools/dsymutil/dsymutil.cpp --- a/llvm/tools/dsymutil/dsymutil.cpp +++ b/llvm/tools/dsymutil/dsymutil.cpp @@ -71,6 +71,7 @@ #include "Options.inc" #undef PREFIX +using namespace llvm::opt; static constexpr opt::OptTable::Info InfoTable[] = { #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__), #include "Options.inc" diff --git a/llvm/tools/llvm-cvtres/llvm-cvtres.cpp b/llvm/tools/llvm-cvtres/llvm-cvtres.cpp --- a/llvm/tools/llvm-cvtres/llvm-cvtres.cpp +++ b/llvm/tools/llvm-cvtres/llvm-cvtres.cpp @@ -49,6 +49,7 @@ #include "Opts.inc" #undef PREFIX +using namespace llvm::opt; static constexpr opt::OptTable::Info InfoTable[] = { #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__), #include "Opts.inc" diff --git a/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp b/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp --- a/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp +++ b/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp @@ -39,6 +39,7 @@ #include "Opts.inc" #undef PREFIX +using namespace llvm::opt; static constexpr opt::OptTable::Info InfoTable[] = { #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__), #include "Opts.inc" diff --git a/llvm/tools/llvm-debuginfod/llvm-debuginfod.cpp b/llvm/tools/llvm-debuginfod/llvm-debuginfod.cpp --- a/llvm/tools/llvm-debuginfod/llvm-debuginfod.cpp +++ b/llvm/tools/llvm-debuginfod/llvm-debuginfod.cpp @@ -43,6 +43,7 @@ #include "Opts.inc" #undef PREFIX +using namespace llvm::opt; static constexpr opt::OptTable::Info InfoTable[] = { #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__), #include "Opts.inc" diff --git a/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp b/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp --- a/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp +++ b/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp @@ -45,6 +45,7 @@ #include "Options.inc" #undef PREFIX +using namespace llvm::opt; static constexpr opt::OptTable::Info InfoTable[] = { #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__), #include "Options.inc" diff --git a/llvm/tools/llvm-dwp/llvm-dwp.cpp b/llvm/tools/llvm-dwp/llvm-dwp.cpp --- a/llvm/tools/llvm-dwp/llvm-dwp.cpp +++ b/llvm/tools/llvm-dwp/llvm-dwp.cpp @@ -55,6 +55,7 @@ #include "Opts.inc" #undef PREFIX +using namespace llvm::opt; static constexpr opt::OptTable::Info InfoTable[] = { #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__), #include "Opts.inc" diff --git a/llvm/tools/llvm-lipo/llvm-lipo.cpp b/llvm/tools/llvm-lipo/llvm-lipo.cpp --- a/llvm/tools/llvm-lipo/llvm-lipo.cpp +++ b/llvm/tools/llvm-lipo/llvm-lipo.cpp @@ -80,6 +80,7 @@ #include "LipoOpts.inc" #undef PREFIX +using namespace llvm::opt; static constexpr opt::OptTable::Info LipoInfoTable[] = { #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(LIPO_, __VA_ARGS__), #include "LipoOpts.inc" diff --git a/llvm/tools/llvm-mt/llvm-mt.cpp b/llvm/tools/llvm-mt/llvm-mt.cpp --- a/llvm/tools/llvm-mt/llvm-mt.cpp +++ b/llvm/tools/llvm-mt/llvm-mt.cpp @@ -47,6 +47,7 @@ #include "Opts.inc" #undef PREFIX +using namespace llvm::opt; static constexpr opt::OptTable::Info InfoTable[] = { #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__), #include "Opts.inc" diff --git a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp --- a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp +++ b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp @@ -26,6 +26,7 @@ using namespace llvm; using namespace llvm::objcopy; +using namespace llvm::opt; namespace { enum ObjcopyID { diff --git a/llvm/tools/llvm-rc/llvm-rc.cpp b/llvm/tools/llvm-rc/llvm-rc.cpp --- a/llvm/tools/llvm-rc/llvm-rc.cpp +++ b/llvm/tools/llvm-rc/llvm-rc.cpp @@ -44,6 +44,7 @@ using namespace llvm; using namespace llvm::rc; +using namespace llvm::opt; namespace { diff --git a/llvm/tools/llvm-strings/llvm-strings.cpp b/llvm/tools/llvm-strings/llvm-strings.cpp --- a/llvm/tools/llvm-strings/llvm-strings.cpp +++ b/llvm/tools/llvm-strings/llvm-strings.cpp @@ -45,6 +45,7 @@ #include "Opts.inc" #undef PREFIX +using namespace llvm::opt; static constexpr opt::OptTable::Info InfoTable[] = { #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__), #include "Opts.inc" diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp --- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp +++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp @@ -62,6 +62,7 @@ #include "Opts.inc" #undef PREFIX +using namespace llvm::opt; static constexpr opt::OptTable::Info InfoTable[] = { #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__), #include "Opts.inc" diff --git a/llvm/tools/llvm-tli-checker/llvm-tli-checker.cpp b/llvm/tools/llvm-tli-checker/llvm-tli-checker.cpp --- a/llvm/tools/llvm-tli-checker/llvm-tli-checker.cpp +++ b/llvm/tools/llvm-tli-checker/llvm-tli-checker.cpp @@ -40,6 +40,7 @@ #include "Opts.inc" #undef PREFIX +using namespace llvm::opt; static constexpr opt::OptTable::Info InfoTable[] = { #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__), #include "Opts.inc" diff --git a/llvm/unittests/Option/OptionMarshallingTest.cpp b/llvm/unittests/Option/OptionMarshallingTest.cpp --- a/llvm/unittests/Option/OptionMarshallingTest.cpp +++ b/llvm/unittests/Option/OptionMarshallingTest.cpp @@ -19,9 +19,9 @@ static const OptionWithMarshallingInfo MarshallingTable[] = { #define OPTION_WITH_MARSHALLING( \ PREFIX_TYPE, PREFIXED_NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, \ - PARAM, HELPTEXT, METAVAR, VALUES, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \ - DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \ - MERGER, EXTRACTOR, TABLE_INDEX) \ + VISIBILITY, PARAM, HELPTEXT, METAVAR, VALUES, SHOULD_PARSE, ALWAYS_EMIT, \ + KEYPATH, DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, \ + DENORMALIZER, MERGER, EXTRACTOR, TABLE_INDEX) \ {PREFIXED_NAME, #KEYPATH, #IMPLIED_CHECK, #IMPLIED_VALUE}, #include "Opts.inc" #undef OPTION_WITH_MARSHALLING diff --git a/llvm/unittests/Option/OptionParsingTest.cpp b/llvm/unittests/Option/OptionParsingTest.cpp --- a/llvm/unittests/Option/OptionParsingTest.cpp +++ b/llvm/unittests/Option/OptionParsingTest.cpp @@ -44,6 +44,10 @@ OptFlag3 = (1 << 6) }; +enum OptionVisibility { + SubtoolVis = (1 << 2), +}; + static constexpr OptTable::Info InfoTable[] = { #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__), #include "Opts.inc" @@ -163,6 +167,43 @@ EXPECT_EQ("bar", AL.getLastArgValue(OPT_C)); } +TYPED_TEST(OptTableTest, ParseWithVisibility) { + TypeParam T; + unsigned MAI, MAC; + + const char *STArgs[] = {"-A", "-Q", "-R"}; + + // With no visibility specified, we find all of the arguments. + InputArgList AL = T.ParseArgs(STArgs, MAI, MAC); + EXPECT_TRUE(AL.hasArg(OPT_A)); + EXPECT_TRUE(AL.hasArg(OPT_Q)); + EXPECT_TRUE(AL.hasArg(OPT_R)); + + // Default visibility omits SubtoolVis. + AL = T.ParseArgs(STArgs, MAI, MAC, Visibility(Default)); + EXPECT_TRUE(AL.hasArg(OPT_A)); + EXPECT_FALSE(AL.hasArg(OPT_Q)); + EXPECT_TRUE(AL.hasArg(OPT_R)); + + // ~SubtoolVis still finds arguments that are visible in Default. + AL = T.ParseArgs(STArgs, MAI, MAC, Visibility(~SubtoolVis)); + EXPECT_TRUE(AL.hasArg(OPT_A)); + EXPECT_FALSE(AL.hasArg(OPT_Q)); + EXPECT_TRUE(AL.hasArg(OPT_R)); + + // Only SubtoolVis. + AL = T.ParseArgs(STArgs, MAI, MAC, Visibility(SubtoolVis)); + EXPECT_FALSE(AL.hasArg(OPT_A)); + EXPECT_TRUE(AL.hasArg(OPT_Q)); + EXPECT_TRUE(AL.hasArg(OPT_R)); + + // Both Default and SubtoolVis are found. + AL = T.ParseArgs(STArgs, MAI, MAC, Visibility(Default | SubtoolVis)); + EXPECT_TRUE(AL.hasArg(OPT_A)); + EXPECT_TRUE(AL.hasArg(OPT_Q)); + EXPECT_TRUE(AL.hasArg(OPT_R)); +} + TYPED_TEST(OptTableTest, ParseAliasInGroup) { TypeParam T; unsigned MAI, MAC; @@ -345,6 +386,12 @@ /*FlagsToInclude=*/0, /*FlagsToExclude=*/OptFlag2)); EXPECT_EQ(Nearest, "-doopf1"); + + // Spelling should respect visibility. + EXPECT_EQ(1U, T.findNearest("-xyzzy", Nearest, Visibility(Default))); + EXPECT_EQ(Nearest, "-xyzzy2"); + EXPECT_EQ(1U, T.findNearest("-xyzzy", Nearest, Visibility(SubtoolVis))); + EXPECT_EQ(Nearest, "-xyzzy1"); } TYPED_TEST(DISABLED_OptTableTest, FindNearestFIXME) { diff --git a/llvm/unittests/Option/Opts.td b/llvm/unittests/Option/Opts.td --- a/llvm/unittests/Option/Opts.td +++ b/llvm/unittests/Option/Opts.td @@ -4,6 +4,8 @@ def OptFlag2 : OptionFlag; def OptFlag3 : OptionFlag; +def SubtoolVis : OptionVisibility; + def A : Flag<["-"], "A">, HelpText<"The A option">, Flags<[OptFlag1]>; def AB : Flag<["-"], "AB">; def B : Joined<["-"], "B">, HelpText<"The B option">, MetaVarName<"B">, Flags<[OptFlag2]>; @@ -35,6 +37,8 @@ def Cramb : Joined<["/"], "cramb:">, HelpText<"The cramb option">, MetaVarName<"CRAMB">, Flags<[OptFlag1]>; def Doopf1 : Flag<["-"], "doopf1">, HelpText<"The doopf1 option">, Flags<[OptFlag1]>; def Doopf2 : Flag<["-"], "doopf2">, HelpText<"The doopf2 option">, Flags<[OptFlag2]>; +def Xyzzy1 : Flag<["-"], "xyzzy1">, HelpText<"The xyzzy1 option">, Vis<[SubtoolVis]>; +def Xyzzy2 : Flag<["-"], "xyzzy2">, HelpText<"The xyzzy2 option">, Vis<[Default]>; def Ermgh : Joined<["--"], "ermgh">, HelpText<"The ermgh option">, MetaVarName<"ERMGH">, Flags<[OptFlag1]>; def Fjormp : Flag<["--"], "fjormp">, HelpText<"The fjormp option">, Flags<[OptFlag1]>; @@ -43,6 +47,9 @@ def Blurmpq : Flag<["--"], "blurmp">; def Blurmpq_eq : Flag<["--"], "blurmp=">; +def Q : Flag<["-"], "Q">, Vis<[SubtoolVis]>; +def R : Flag<["-"], "R">, Vis<[Default, SubtoolVis]>; + class XOpts : KeyPathAndMacro<"X->", base> {} def marshalled_flag_d : Flag<["-"], "marshalled-flag-d">, diff --git a/llvm/utils/TableGen/OptParserEmitter.cpp b/llvm/utils/TableGen/OptParserEmitter.cpp --- a/llvm/utils/TableGen/OptParserEmitter.cpp +++ b/llvm/utils/TableGen/OptParserEmitter.cpp @@ -302,7 +302,7 @@ OS << "INVALID"; // The other option arguments (unused for groups). - OS << ", INVALID, nullptr, 0, 0"; + OS << ", INVALID, nullptr, 0, 0, 0"; // The option help text. if (!isa(R.getValueInit("HelpText"))) { @@ -340,8 +340,10 @@ // The containing option group (if any). OS << ", "; const ListInit *GroupFlags = nullptr; + const ListInit *GroupVis = nullptr; if (const DefInit *DI = dyn_cast(R.getValueInit("Group"))) { GroupFlags = DI->getDef()->getValueAsListInit("Flags"); + GroupVis = DI->getDef()->getValueAsListInit("Vis"); OS << getOptionName(*DI->getDef()); } else OS << "INVALID"; @@ -382,6 +384,21 @@ if (NumFlags == 0) OS << '0'; + // The option visibility flags. + OS << ", "; + int NumVisFlags = 0; + LI = R.getValueAsListInit("Vis"); + for (Init *I : *LI) + OS << (NumVisFlags++ ? " | " : "") + << cast(I)->getDef()->getName(); + if (GroupVis) { + for (Init *I : *GroupVis) + OS << (NumVisFlags++ ? " | " : "") + << cast(I)->getDef()->getName(); + } + if (NumVisFlags == 0) + OS << '0'; + // The option parameter field. OS << ", " << R.getValueAsInt("NumArgs");