diff --git a/clang/lib/Driver/DriverOptions.cpp b/clang/lib/Driver/DriverOptions.cpp index 67d4198d222aa..6c972fa89c71d 100644 --- a/clang/lib/Driver/DriverOptions.cpp +++ b/clang/lib/Driver/DriverOptions.cpp @@ -29,12 +29,23 @@ static const OptTable::Info InfoTable[] = { #undef OPTION }; +// 2 options with different mutually exclusive flags will not happen at same +// time. +static const unsigned MutuallyExclusiveFlags[] = { + clang::driver::options::ClangFlags::CC1Option, + clang::driver::options::ClangFlags::CLOption, + clang::driver::options::ClangFlags::CoreOption, + clang::driver::options::ClangFlags::DXCOption, + clang::driver::options::ClangFlags::FlangOnlyOption | + clang::driver::options::ClangFlags::FlangOption, +}; + namespace { class DriverOptTable : public OptTable { public: DriverOptTable() - : OptTable(InfoTable) {} + : OptTable(InfoTable, /*IgnoreCase*/ false, MutuallyExclusiveFlags) {} }; } diff --git a/llvm/include/llvm/Option/OptTable.h b/llvm/include/llvm/Option/OptTable.h index 07d9870f71b33..a0a232d20ae05 100644 --- a/llvm/include/llvm/Option/OptTable.h +++ b/llvm/include/llvm/Option/OptTable.h @@ -87,7 +87,8 @@ class OptTable { unsigned &Index) const; protected: - OptTable(ArrayRef OptionInfos, bool IgnoreCase = false); + OptTable(ArrayRef OptionInfos, bool IgnoreCase = false, + ArrayRef MutuallyExclusiveFlags = {}); public: ~OptTable(); diff --git a/llvm/lib/Option/OptTable.cpp b/llvm/lib/Option/OptTable.cpp index c93b7ad7f5fa8..b86baddd4d38d 100644 --- a/llvm/lib/Option/OptTable.cpp +++ b/llvm/lib/Option/OptTable.cpp @@ -63,7 +63,9 @@ static int StrCmpOptionName(const char *A, const char *B) { return strcmp(A, B); } -static inline bool operator<(const OptTable::Info &A, const OptTable::Info &B) { +static inline bool +OptInfoCmpLessThan(const OptTable::Info &A, const OptTable::Info &B, + ArrayRef MutuallyExclusiveFlags) { if (&A == &B) return false; @@ -77,6 +79,23 @@ static inline bool operator<(const OptTable::Info &A, const OptTable::Info &B) { return N < 0; } + if (!MutuallyExclusiveFlags.empty()) { + // For Infos with different MutuallyExclusiveFlag, it is OK to not in order, + // they'll not active at same time. + unsigned MutuallyExclusiveFlagsA = 0; + unsigned MutuallyExclusiveFlagsB = 0; + for (auto Flag : MutuallyExclusiveFlags) { + if (A.Flags & Flag) + MutuallyExclusiveFlagsA |= Flag; + if (B.Flags & Flag) + MutuallyExclusiveFlagsB |= Flag; + } + + if (MutuallyExclusiveFlagsA != 0 && MutuallyExclusiveFlagsB != 0 && + (MutuallyExclusiveFlagsA & MutuallyExclusiveFlagsB) == 0) + return true; + } + // Names are the same, check that classes are in order; exactly one // should be joined, and it should succeed the other. assert(((A.Kind == Option::JoinedClass) ^ (B.Kind == Option::JoinedClass)) && @@ -95,7 +114,8 @@ static inline bool operator<(const OptTable::Info &I, const char *Name) { OptSpecifier::OptSpecifier(const Option *Opt) : ID(Opt->getID()) {} -OptTable::OptTable(ArrayRef OptionInfos, bool IgnoreCase) +OptTable::OptTable(ArrayRef OptionInfos, bool IgnoreCase, + ArrayRef MutuallyExclusiveFlags) : OptionInfos(OptionInfos), IgnoreCase(IgnoreCase) { // Explicitly zero initialize the error to work around a bug in array // value-initialization on MinGW with gcc 4.3.5. @@ -128,7 +148,7 @@ OptTable::OptTable(ArrayRef OptionInfos, bool IgnoreCase) // Check that options are in order. for (unsigned i = FirstSearchableIndex + 1, e = getNumOptions(); i != e; ++i){ - if (!(getInfo(i) < getInfo(i + 1))) { + if (!OptInfoCmpLessThan(getInfo(i), getInfo(i + 1), MutuallyExclusiveFlags)) { getOption(i).dump(); getOption(i + 1).dump(); llvm_unreachable("Options are not in order!");