|
11 | 11 | #include "clang/Basic/Version.h"
|
12 | 12 | #include "clang/Driver/Driver.h"
|
13 | 13 | #include "llvm/ADT/DenseSet.h"
|
| 14 | +#include "llvm/ADT/SmallSet.h" |
14 | 15 | #include "llvm/ADT/SmallString.h"
|
15 | 16 | #include "llvm/ADT/StringRef.h"
|
16 | 17 | #include "llvm/Support/Compiler.h"
|
@@ -96,9 +97,83 @@ MultilibSet &MultilibSet::FilterOut(FilterCallback F) {
|
96 | 97 |
|
97 | 98 | void MultilibSet::push_back(const Multilib &M) { Multilibs.push_back(M); }
|
98 | 99 |
|
| 100 | +static void WarnUnclaimedMultilibCustomFlags( |
| 101 | + const Driver &D, const SmallVector<StringRef> &UnclaimedCustomFlagValues, |
| 102 | + const SmallVector<MultilibSet::CustomFlagDeclaration> &CustomFlagDecls, |
| 103 | + const StringRef MultilibFlagOptionStr) { |
| 104 | + struct EditDistanceInfo { |
| 105 | + StringRef FlagValue; |
| 106 | + unsigned EditDistance; |
| 107 | + }; |
| 108 | + |
| 109 | + for (StringRef Unclaimed : UnclaimedCustomFlagValues) { |
| 110 | + std::optional<EditDistanceInfo> BestCandidate; |
| 111 | + for (const auto &Decl : CustomFlagDecls) { |
| 112 | + for (StringRef FlagValue : Decl.Values) { |
| 113 | + unsigned EditDistance = |
| 114 | + Unclaimed.edit_distance(FlagValue, /*AllowReplacements=*/false); |
| 115 | + if (!BestCandidate || EditDistance < BestCandidate->EditDistance) { |
| 116 | + BestCandidate = {std::move(FlagValue), EditDistance}; |
| 117 | + } |
| 118 | + } |
| 119 | + } |
| 120 | + if (!BestCandidate) |
| 121 | + continue; |
| 122 | + D.Diag(clang::diag::warn_drv_unsupported_opt_with_suggestion) |
| 123 | + << (MultilibFlagOptionStr + Unclaimed).str() |
| 124 | + << (MultilibFlagOptionStr + BestCandidate->FlagValue).str(); |
| 125 | + } |
| 126 | +} |
| 127 | + |
| 128 | +Multilib::flags_list |
| 129 | +MultilibSet::processCustomFlags(const Driver &D, |
| 130 | + const Multilib::flags_list &Flags) const { |
| 131 | + Multilib::flags_list Result; |
| 132 | + constexpr StringRef MultilibFlagOptionStr = "-fmultilib-flag="; |
| 133 | + SmallVector<StringRef> CustomFlags; |
| 134 | + |
| 135 | + for (StringRef Flag : Flags) { |
| 136 | + if (Flag.starts_with(MultilibFlagOptionStr)) |
| 137 | + CustomFlags.push_back(std::move(Flag)); |
| 138 | + else |
| 139 | + Result.push_back(Flag.str()); |
| 140 | + } |
| 141 | + |
| 142 | + SmallVector<StringRef> UnclaimedCustomFlagValues; |
| 143 | + llvm::SmallSet<StringRef, 8> TriggeredCustomFlagDecls; |
| 144 | + |
| 145 | + for (StringRef Flag : llvm::reverse(CustomFlags)) { |
| 146 | + StringRef CustomFlagValue = Flag.drop_front(MultilibFlagOptionStr.size()); |
| 147 | + bool Claimed = false; |
| 148 | + for (const CustomFlagDeclaration &Decl : CustomFlagDecls) { |
| 149 | + if (llvm::is_contained(Decl.Values, CustomFlagValue)) { |
| 150 | + Result.push_back(Flag.str()); |
| 151 | + TriggeredCustomFlagDecls.insert(Decl.Name); |
| 152 | + Claimed = true; |
| 153 | + break; |
| 154 | + } |
| 155 | + } |
| 156 | + if (!Claimed) { |
| 157 | + UnclaimedCustomFlagValues.push_back(std::move(CustomFlagValue)); |
| 158 | + } |
| 159 | + } |
| 160 | + |
| 161 | + for (const CustomFlagDeclaration &Decl : CustomFlagDecls) { |
| 162 | + if (TriggeredCustomFlagDecls.contains(Decl.Name)) |
| 163 | + continue; |
| 164 | + Result.push_back(MultilibFlagOptionStr.str() + Decl.DefaultValue); |
| 165 | + } |
| 166 | + |
| 167 | + WarnUnclaimedMultilibCustomFlags(D, UnclaimedCustomFlagValues, |
| 168 | + CustomFlagDecls, MultilibFlagOptionStr); |
| 169 | + |
| 170 | + return Result; |
| 171 | +} |
| 172 | + |
99 | 173 | bool MultilibSet::select(const Driver &D, const Multilib::flags_list &Flags,
|
100 | 174 | llvm::SmallVectorImpl<Multilib> &Selected) const {
|
101 |
| - llvm::StringSet<> FlagSet(expandFlags(Flags)); |
| 175 | + Multilib::flags_list FlagsWithCustom = processCustomFlags(D, Flags); |
| 176 | + llvm::StringSet<> FlagSet(expandFlags(FlagsWithCustom)); |
102 | 177 | Selected.clear();
|
103 | 178 |
|
104 | 179 | // Decide which multilibs we're going to select at all.
|
|
0 commit comments