1 | //===- Multilib.cpp - Multilib Implementation -----------------------------===// |
---|---|
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "clang/Driver/Multilib.h" |
10 | #include "clang/Basic/LLVM.h" |
11 | #include "clang/Driver/Driver.h" |
12 | #include "llvm/ADT/DenseSet.h" |
13 | #include "llvm/ADT/SmallSet.h" |
14 | #include "llvm/ADT/StringRef.h" |
15 | #include "llvm/Support/Compiler.h" |
16 | #include "llvm/Support/ErrorHandling.h" |
17 | #include "llvm/Support/Regex.h" |
18 | #include "llvm/Support/VersionTuple.h" |
19 | #include "llvm/Support/YAMLParser.h" |
20 | #include "llvm/Support/YAMLTraits.h" |
21 | #include "llvm/Support/raw_ostream.h" |
22 | #include <algorithm> |
23 | #include <cassert> |
24 | #include <string> |
25 | |
26 | using namespace clang; |
27 | using namespace driver; |
28 | using namespace llvm::sys; |
29 | |
30 | Multilib::Multilib(StringRef GCCSuffix, StringRef OSSuffix, |
31 | StringRef IncludeSuffix, const flags_list &Flags, |
32 | StringRef ExclusiveGroup, std::optional<StringRef> Error) |
33 | : GCCSuffix(GCCSuffix), OSSuffix(OSSuffix), IncludeSuffix(IncludeSuffix), |
34 | Flags(Flags), ExclusiveGroup(ExclusiveGroup), Error(Error) { |
35 | assert(GCCSuffix.empty() || |
36 | (StringRef(GCCSuffix).front() == '/' && GCCSuffix.size() > 1)); |
37 | assert(OSSuffix.empty() || |
38 | (StringRef(OSSuffix).front() == '/' && OSSuffix.size() > 1)); |
39 | assert(IncludeSuffix.empty() || |
40 | (StringRef(IncludeSuffix).front() == '/' && IncludeSuffix.size() > 1)); |
41 | } |
42 | |
43 | LLVM_DUMP_METHOD void Multilib::dump() const { |
44 | print(OS&: llvm::errs()); |
45 | } |
46 | |
47 | void Multilib::print(raw_ostream &OS) const { |
48 | if (GCCSuffix.empty()) |
49 | OS << "."; |
50 | else { |
51 | OS << StringRef(GCCSuffix).drop_front(); |
52 | } |
53 | OS << ";"; |
54 | for (StringRef Flag : Flags) { |
55 | if (Flag.front() == '-') |
56 | OS << "@"<< Flag.substr(Start: 1); |
57 | } |
58 | } |
59 | |
60 | bool Multilib::operator==(const Multilib &Other) const { |
61 | // Check whether the flags sets match |
62 | // allowing for the match to be order invariant |
63 | llvm::StringSet<> MyFlags(llvm::from_range, Flags); |
64 | |
65 | for (const auto &Flag : Other.Flags) |
66 | if (!MyFlags.contains(key: Flag)) |
67 | return false; |
68 | |
69 | if (osSuffix() != Other.osSuffix()) |
70 | return false; |
71 | |
72 | if (gccSuffix() != Other.gccSuffix()) |
73 | return false; |
74 | |
75 | if (includeSuffix() != Other.includeSuffix()) |
76 | return false; |
77 | |
78 | return true; |
79 | } |
80 | |
81 | raw_ostream &clang::driver::operator<<(raw_ostream &OS, const Multilib &M) { |
82 | M.print(OS); |
83 | return OS; |
84 | } |
85 | |
86 | MultilibSet &MultilibSet::FilterOut(FilterCallback F) { |
87 | llvm::erase_if(C&: Multilibs, P: F); |
88 | return *this; |
89 | } |
90 | |
91 | void MultilibSet::push_back(const Multilib &M) { Multilibs.push_back(x: M); } |
92 | |
93 | static void DiagnoseUnclaimedMultilibCustomFlags( |
94 | const Driver &D, const SmallVector<StringRef> &UnclaimedCustomFlagValues, |
95 | const SmallVector<custom_flag::Declaration> &CustomFlagDecls) { |
96 | struct EditDistanceInfo { |
97 | StringRef FlagValue; |
98 | unsigned EditDistance; |
99 | }; |
100 | const unsigned MaxEditDistance = 5; |
101 | |
102 | for (StringRef Unclaimed : UnclaimedCustomFlagValues) { |
103 | std::optional<EditDistanceInfo> BestCandidate; |
104 | for (const auto &Decl : CustomFlagDecls) { |
105 | for (const auto &Value : Decl.ValueList) { |
106 | const std::string &FlagValueName = Value.Name; |
107 | unsigned EditDistance = |
108 | Unclaimed.edit_distance(Other: FlagValueName, /*AllowReplacements=*/true, |
109 | /*MaxEditDistance=*/MaxEditDistance); |
110 | if (!BestCandidate || (EditDistance <= MaxEditDistance && |
111 | EditDistance < BestCandidate->EditDistance)) { |
112 | BestCandidate = {.FlagValue: FlagValueName, .EditDistance: EditDistance}; |
113 | } |
114 | } |
115 | } |
116 | if (!BestCandidate) |
117 | D.Diag(clang::diag::DiagID: err_drv_unsupported_opt) |
118 | << (custom_flag::Prefix + Unclaimed).str(); |
119 | else |
120 | D.Diag(clang::diag::DiagID: err_drv_unsupported_opt_with_suggestion) |
121 | << (custom_flag::Prefix + Unclaimed).str() |
122 | << (custom_flag::Prefix + BestCandidate->FlagValue).str(); |
123 | } |
124 | } |
125 | |
126 | namespace clang::driver::custom_flag { |
127 | // Map implemented using linear searches as the expected size is too small for |
128 | // the overhead of a search tree or a hash table. |
129 | class ValueNameToDetailMap { |
130 | SmallVector<std::pair<StringRef, const ValueDetail *>> Mapping; |
131 | |
132 | public: |
133 | template <typename It> |
134 | ValueNameToDetailMap(It FlagDeclsBegin, It FlagDeclsEnd) { |
135 | for (auto DeclIt = FlagDeclsBegin; DeclIt != FlagDeclsEnd; ++DeclIt) { |
136 | const Declaration &Decl = *DeclIt; |
137 | for (const auto &Value : Decl.ValueList) |
138 | Mapping.emplace_back(Args: Value.Name, Args: &Value); |
139 | } |
140 | } |
141 | |
142 | const ValueDetail *get(StringRef Key) const { |
143 | auto Iter = llvm::find_if( |
144 | Range: Mapping, P: [&](const auto &Pair) { return Pair.first == Key; }); |
145 | return Iter != Mapping.end() ? Iter->second : nullptr; |
146 | } |
147 | }; |
148 | } // namespace clang::driver::custom_flag |
149 | |
150 | std::pair<Multilib::flags_list, SmallVector<StringRef>> |
151 | MultilibSet::processCustomFlags(const Driver &D, |
152 | const Multilib::flags_list &Flags) const { |
153 | Multilib::flags_list Result; |
154 | SmallVector<StringRef> MacroDefines; |
155 | |
156 | // Custom flag values detected in the flags list |
157 | SmallVector<const custom_flag::ValueDetail *> ClaimedCustomFlagValues; |
158 | |
159 | // Arguments to -fmultilib-flag=<arg> that don't correspond to any valid |
160 | // custom flag value. An error will be printed out for each of these. |
161 | SmallVector<StringRef> UnclaimedCustomFlagValueStrs; |
162 | |
163 | const auto ValueNameToValueDetail = custom_flag::ValueNameToDetailMap( |
164 | CustomFlagDecls.begin(), CustomFlagDecls.end()); |
165 | |
166 | for (StringRef Flag : Flags) { |
167 | if (!Flag.starts_with(Prefix: custom_flag::Prefix)) { |
168 | Result.push_back(x: Flag.str()); |
169 | continue; |
170 | } |
171 | |
172 | StringRef CustomFlagValueStr = Flag.substr(Start: custom_flag::Prefix.size()); |
173 | const custom_flag::ValueDetail *Detail = |
174 | ValueNameToValueDetail.get(Key: CustomFlagValueStr); |
175 | if (Detail) |
176 | ClaimedCustomFlagValues.push_back(Elt: Detail); |
177 | else |
178 | UnclaimedCustomFlagValueStrs.push_back(Elt: CustomFlagValueStr); |
179 | } |
180 | |
181 | // Set of custom flag declarations for which a value was passed in the flags |
182 | // list. This is used to, firstly, detect multiple values for the same flag |
183 | // declaration (in this case, the last one wins), and secondly, to detect |
184 | // which declarations had no value passed in (in this case, the default value |
185 | // is selected). |
186 | llvm::SmallPtrSet<custom_flag::Declaration *, 32> TriggeredCustomFlagDecls; |
187 | |
188 | // Detect multiple values for the same flag declaration. Last one wins. |
189 | for (auto *CustomFlagValue : llvm::reverse(C&: ClaimedCustomFlagValues)) { |
190 | if (!TriggeredCustomFlagDecls.insert(Ptr: CustomFlagValue->Decl).second) |
191 | continue; |
192 | Result.push_back(x: std::string(custom_flag::Prefix) + CustomFlagValue->Name); |
193 | if (CustomFlagValue->MacroDefines) |
194 | MacroDefines.append(in_start: CustomFlagValue->MacroDefines->begin(), |
195 | in_end: CustomFlagValue->MacroDefines->end()); |
196 | } |
197 | |
198 | // Detect flag declarations with no value passed in. Select default value. |
199 | for (const auto &Decl : CustomFlagDecls) { |
200 | if (TriggeredCustomFlagDecls.contains(Ptr: &Decl)) |
201 | continue; |
202 | const custom_flag::ValueDetail &CustomFlagValue = |
203 | Decl.ValueList[*Decl.DefaultValueIdx]; |
204 | Result.push_back(x: std::string(custom_flag::Prefix) + CustomFlagValue.Name); |
205 | if (CustomFlagValue.MacroDefines) |
206 | MacroDefines.append(in_start: CustomFlagValue.MacroDefines->begin(), |
207 | in_end: CustomFlagValue.MacroDefines->end()); |
208 | } |
209 | |
210 | DiagnoseUnclaimedMultilibCustomFlags(D, UnclaimedCustomFlagValues: UnclaimedCustomFlagValueStrs, |
211 | CustomFlagDecls); |
212 | |
213 | return {Result, MacroDefines}; |
214 | } |
215 | |
216 | bool MultilibSet::select( |
217 | const Driver &D, const Multilib::flags_list &Flags, |
218 | llvm::SmallVectorImpl<Multilib> &Selected, |
219 | llvm::SmallVector<StringRef> *CustomFlagMacroDefines) const { |
220 | auto [FlagsWithCustom, CFMacroDefines] = processCustomFlags(D, Flags); |
221 | llvm::StringSet<> FlagSet(expandFlags(FlagsWithCustom)); |
222 | Selected.clear(); |
223 | bool AnyErrors = false; |
224 | |
225 | // Determining the list of macro defines depends only on the custom flags |
226 | // passed in. The library variants actually selected are not relevant in |
227 | // this. Therefore this assignment can take place before the selection |
228 | // happens. |
229 | if (CustomFlagMacroDefines) |
230 | *CustomFlagMacroDefines = std::move(CFMacroDefines); |
231 | |
232 | // Decide which multilibs we're going to select at all. |
233 | llvm::DenseSet<StringRef> ExclusiveGroupsSelected; |
234 | for (const Multilib &M : llvm::reverse(C: Multilibs)) { |
235 | // If this multilib doesn't match all our flags, don't select it. |
236 | if (!llvm::all_of(Range: M.flags(), P: [&FlagSet](const std::string &F) { |
237 | return FlagSet.contains(key: F); |
238 | })) |
239 | continue; |
240 | |
241 | const std::string &group = M.exclusiveGroup(); |
242 | if (!group.empty()) { |
243 | // If this multilib has the same ExclusiveGroup as one we've already |
244 | // selected, skip it. We're iterating in reverse order, so the group |
245 | // member we've selected already is preferred. |
246 | // |
247 | // Otherwise, add the group name to the set of groups we've already |
248 | // selected a member of. |
249 | auto [It, Inserted] = ExclusiveGroupsSelected.insert(V: group); |
250 | if (!Inserted) |
251 | continue; |
252 | } |
253 | |
254 | // If this multilib is actually a placeholder containing an error message |
255 | // written by the multilib.yaml author, then set a flag that will cause a |
256 | // failure return. Our caller will display the error message. |
257 | if (M.isError()) |
258 | AnyErrors = true; |
259 | |
260 | // Select this multilib. |
261 | Selected.push_back(Elt: M); |
262 | } |
263 | |
264 | // We iterated in reverse order, so now put Selected back the right way |
265 | // round. |
266 | std::reverse(first: Selected.begin(), last: Selected.end()); |
267 | |
268 | return !AnyErrors && !Selected.empty(); |
269 | } |
270 | |
271 | llvm::StringSet<> |
272 | MultilibSet::expandFlags(const Multilib::flags_list &InFlags) const { |
273 | llvm::StringSet<> Result(llvm::from_range, InFlags); |
274 | for (const FlagMatcher &M : FlagMatchers) { |
275 | std::string RegexString(M.Match); |
276 | |
277 | // Make the regular expression match the whole string. |
278 | if (!StringRef(M.Match).starts_with(Prefix: "^")) |
279 | RegexString.insert(p: RegexString.begin(), c: '^'); |
280 | if (!StringRef(M.Match).ends_with(Suffix: "$")) |
281 | RegexString.push_back(c: '$'); |
282 | |
283 | const llvm::Regex Regex(RegexString); |
284 | assert(Regex.isValid()); |
285 | if (llvm::any_of(Range: InFlags, |
286 | P: [&Regex](StringRef F) { return Regex.match(String: F); })) { |
287 | Result.insert_range(R: M.Flags); |
288 | } |
289 | } |
290 | return Result; |
291 | } |
292 | |
293 | namespace { |
294 | |
295 | // When updating this also update MULTILIB_VERSION in MultilibTest.cpp |
296 | static const VersionTuple MultilibVersionCurrent(1, 0); |
297 | |
298 | struct MultilibSerialization { |
299 | std::string Dir; // if this record successfully selects a library dir |
300 | std::string Error; // if this record reports a fatal error message |
301 | std::vector<std::string> Flags; |
302 | std::string Group; |
303 | }; |
304 | |
305 | enum class MultilibGroupType { |
306 | /* |
307 | * The only group type currently supported is 'Exclusive', which indicates a |
308 | * group of multilibs of which at most one may be selected. |
309 | */ |
310 | Exclusive, |
311 | |
312 | /* |
313 | * Future possibility: a second group type indicating a set of library |
314 | * directories that are mutually _dependent_ rather than mutually exclusive: |
315 | * if you include one you must include them all. |
316 | * |
317 | * It might also be useful to allow groups to be members of other groups, so |
318 | * that a mutually exclusive group could contain a mutually dependent set of |
319 | * library directories, or vice versa. |
320 | * |
321 | * These additional features would need changes in the implementation, but |
322 | * the YAML schema is set up so they can be added without requiring changes |
323 | * in existing users' multilib.yaml files. |
324 | */ |
325 | }; |
326 | |
327 | struct MultilibGroupSerialization { |
328 | std::string Name; |
329 | MultilibGroupType Type; |
330 | }; |
331 | |
332 | struct MultilibSetSerialization { |
333 | llvm::VersionTuple MultilibVersion; |
334 | SmallVector<MultilibGroupSerialization> Groups; |
335 | SmallVector<MultilibSerialization> Multilibs; |
336 | SmallVector<MultilibSet::FlagMatcher> FlagMatchers; |
337 | SmallVector<custom_flag::Declaration> CustomFlagDeclarations; |
338 | }; |
339 | |
340 | } // end anonymous namespace |
341 | |
342 | LLVM_YAML_IS_SEQUENCE_VECTOR(MultilibSerialization) |
343 | LLVM_YAML_IS_SEQUENCE_VECTOR(MultilibGroupSerialization) |
344 | LLVM_YAML_IS_SEQUENCE_VECTOR(MultilibSet::FlagMatcher) |
345 | LLVM_YAML_IS_SEQUENCE_VECTOR(custom_flag::ValueDetail) |
346 | LLVM_YAML_IS_SEQUENCE_VECTOR(custom_flag::Declaration) |
347 | |
348 | template <> struct llvm::yaml::MappingTraits<MultilibSerialization> { |
349 | static void mapping(llvm::yaml::IO &io, MultilibSerialization &V) { |
350 | io.mapOptional(Key: "Dir", Val&: V.Dir); |
351 | io.mapOptional(Key: "Error", Val&: V.Error); |
352 | io.mapRequired(Key: "Flags", Val&: V.Flags); |
353 | io.mapOptional(Key: "Group", Val&: V.Group); |
354 | } |
355 | static std::string validate(IO &io, MultilibSerialization &V) { |
356 | if (V.Dir.empty() && V.Error.empty()) |
357 | return "one of the 'Dir' and 'Error' keys must be specified"; |
358 | if (!V.Dir.empty() && !V.Error.empty()) |
359 | return "the 'Dir' and 'Error' keys may not both be specified"; |
360 | if (StringRef(V.Dir).starts_with(Prefix: "/")) |
361 | return "paths must be relative but \""+ V.Dir + "\" starts with \"/\""; |
362 | return std::string{}; |
363 | } |
364 | }; |
365 | |
366 | template <> struct llvm::yaml::ScalarEnumerationTraits<MultilibGroupType> { |
367 | static void enumeration(IO &io, MultilibGroupType &Val) { |
368 | io.enumCase(Val, Str: "Exclusive", ConstVal: MultilibGroupType::Exclusive); |
369 | } |
370 | }; |
371 | |
372 | template <> struct llvm::yaml::MappingTraits<MultilibGroupSerialization> { |
373 | static void mapping(llvm::yaml::IO &io, MultilibGroupSerialization &V) { |
374 | io.mapRequired(Key: "Name", Val&: V.Name); |
375 | io.mapRequired(Key: "Type", Val&: V.Type); |
376 | } |
377 | }; |
378 | |
379 | template <> struct llvm::yaml::MappingTraits<MultilibSet::FlagMatcher> { |
380 | static void mapping(llvm::yaml::IO &io, MultilibSet::FlagMatcher &M) { |
381 | io.mapRequired(Key: "Match", Val&: M.Match); |
382 | io.mapRequired(Key: "Flags", Val&: M.Flags); |
383 | } |
384 | static std::string validate(IO &io, MultilibSet::FlagMatcher &M) { |
385 | llvm::Regex Regex(M.Match); |
386 | std::string RegexError; |
387 | if (!Regex.isValid(Error&: RegexError)) |
388 | return RegexError; |
389 | if (M.Flags.empty()) |
390 | return "value required for 'Flags'"; |
391 | return std::string{}; |
392 | } |
393 | }; |
394 | |
395 | template <> |
396 | struct llvm::yaml::MappingContextTraits<custom_flag::ValueDetail, |
397 | llvm::SmallSet<std::string, 32>> { |
398 | static void mapping(llvm::yaml::IO &io, custom_flag::ValueDetail &V, |
399 | llvm::SmallSet<std::string, 32> &) { |
400 | io.mapRequired(Key: "Name", Val&: V.Name); |
401 | io.mapOptional(Key: "MacroDefines", Val&: V.MacroDefines); |
402 | } |
403 | static std::string validate(IO &io, custom_flag::ValueDetail &V, |
404 | llvm::SmallSet<std::string, 32> &NameSet) { |
405 | if (V.Name.empty()) |
406 | return "custom flag value requires a name"; |
407 | if (!NameSet.insert(V: V.Name).second) |
408 | return "duplicate custom flag value name: \""+ V.Name + "\""; |
409 | return {}; |
410 | } |
411 | }; |
412 | |
413 | template <> |
414 | struct llvm::yaml::MappingContextTraits<custom_flag::Declaration, |
415 | llvm::SmallSet<std::string, 32>> { |
416 | static void mapping(llvm::yaml::IO &io, custom_flag::Declaration &V, |
417 | llvm::SmallSet<std::string, 32> &NameSet) { |
418 | io.mapRequired(Key: "Name", Val&: V.Name); |
419 | io.mapRequired(Key: "Values", Val&: V.ValueList, Ctx&: NameSet); |
420 | std::string DefaultValueName; |
421 | io.mapRequired(Key: "Default", Val&: DefaultValueName); |
422 | |
423 | for (auto [Idx, Value] : llvm::enumerate(First&: V.ValueList)) { |
424 | Value.Decl = &V; |
425 | if (Value.Name == DefaultValueName) { |
426 | assert(!V.DefaultValueIdx); |
427 | V.DefaultValueIdx = Idx; |
428 | } |
429 | } |
430 | } |
431 | static std::string validate(IO &io, custom_flag::Declaration &V, |
432 | llvm::SmallSet<std::string, 32> &) { |
433 | if (V.Name.empty()) |
434 | return "custom flag requires a name"; |
435 | if (V.ValueList.empty()) |
436 | return "custom flag must have at least one value"; |
437 | if (!V.DefaultValueIdx) |
438 | return "custom flag must have a default value"; |
439 | return {}; |
440 | } |
441 | }; |
442 | |
443 | template <> struct llvm::yaml::MappingTraits<MultilibSetSerialization> { |
444 | static void mapping(llvm::yaml::IO &io, MultilibSetSerialization &M) { |
445 | io.mapRequired(Key: "MultilibVersion", Val&: M.MultilibVersion); |
446 | io.mapRequired(Key: "Variants", Val&: M.Multilibs); |
447 | io.mapOptional(Key: "Groups", Val&: M.Groups); |
448 | llvm::SmallSet<std::string, 32> NameSet; |
449 | io.mapOptionalWithContext(Key: "Flags", Val&: M.CustomFlagDeclarations, Ctx&: NameSet); |
450 | io.mapOptional(Key: "Mappings", Val&: M.FlagMatchers); |
451 | } |
452 | static std::string validate(IO &io, MultilibSetSerialization &M) { |
453 | if (M.MultilibVersion.empty()) |
454 | return "missing required key 'MultilibVersion'"; |
455 | if (M.MultilibVersion.getMajor() != MultilibVersionCurrent.getMajor()) |
456 | return "multilib version "+ M.MultilibVersion.getAsString() + |
457 | " is unsupported"; |
458 | if (M.MultilibVersion.getMinor() > MultilibVersionCurrent.getMinor()) |
459 | return "multilib version "+ M.MultilibVersion.getAsString() + |
460 | " is unsupported"; |
461 | for (const MultilibSerialization &Lib : M.Multilibs) { |
462 | if (!Lib.Group.empty()) { |
463 | bool Found = false; |
464 | for (const MultilibGroupSerialization &Group : M.Groups) |
465 | if (Group.Name == Lib.Group) { |
466 | Found = true; |
467 | break; |
468 | } |
469 | if (!Found) |
470 | return "multilib \""+ Lib.Dir + |
471 | "\" specifies undefined group name \""+ Lib.Group + "\""; |
472 | } |
473 | } |
474 | return std::string{}; |
475 | } |
476 | }; |
477 | |
478 | llvm::ErrorOr<MultilibSet> |
479 | MultilibSet::parseYaml(llvm::MemoryBufferRef Input, |
480 | llvm::SourceMgr::DiagHandlerTy DiagHandler, |
481 | void *DiagHandlerCtxt) { |
482 | MultilibSetSerialization MS; |
483 | llvm::yaml::Input YamlInput(Input, nullptr, DiagHandler, DiagHandlerCtxt); |
484 | YamlInput >> MS; |
485 | if (YamlInput.error()) |
486 | return YamlInput.error(); |
487 | |
488 | multilib_list Multilibs; |
489 | Multilibs.reserve(n: MS.Multilibs.size()); |
490 | for (const auto &M : MS.Multilibs) { |
491 | if (!M.Error.empty()) { |
492 | Multilibs.emplace_back(args: "", args: "", args: "", args: M.Flags, args: M.Group, args: M.Error); |
493 | } else { |
494 | std::string Dir; |
495 | if (M.Dir != ".") |
496 | Dir = "/"+ M.Dir; |
497 | // We transfer M.Group straight into the ExclusiveGroup parameter for the |
498 | // Multilib constructor. If we later support more than one type of group, |
499 | // we'll have to look up the group name in MS.Groups, check its type, and |
500 | // decide what to do here. |
501 | Multilibs.emplace_back(args&: Dir, args&: Dir, args&: Dir, args: M.Flags, args: M.Group); |
502 | } |
503 | } |
504 | |
505 | return MultilibSet(std::move(Multilibs), std::move(MS.FlagMatchers), |
506 | std::move(MS.CustomFlagDeclarations)); |
507 | } |
508 | |
509 | LLVM_DUMP_METHOD void MultilibSet::dump() const { |
510 | print(OS&: llvm::errs()); |
511 | } |
512 | |
513 | void MultilibSet::print(raw_ostream &OS) const { |
514 | for (const auto &M : *this) |
515 | OS << M << "\n"; |
516 | } |
517 | |
518 | raw_ostream &clang::driver::operator<<(raw_ostream &OS, const MultilibSet &MS) { |
519 | MS.print(OS); |
520 | return OS; |
521 | } |
522 | |
523 | namespace clang::driver::custom_flag { |
524 | Declaration::Declaration(const Declaration &Other) |
525 | : Name(Other.Name), ValueList(Other.ValueList), |
526 | DefaultValueIdx(Other.DefaultValueIdx) { |
527 | for (ValueDetail &Detail : ValueList) |
528 | Detail.Decl = this; |
529 | } |
530 | |
531 | Declaration::Declaration(Declaration &&Other) |
532 | : Name(std::move(Other.Name)), ValueList(std::move(Other.ValueList)), |
533 | DefaultValueIdx(std::move(Other.DefaultValueIdx)) { |
534 | for (ValueDetail &Detail : ValueList) |
535 | Detail.Decl = this; |
536 | } |
537 | |
538 | Declaration &Declaration::operator=(const Declaration &Other) { |
539 | if (this == &Other) |
540 | return *this; |
541 | Name = Other.Name; |
542 | ValueList = Other.ValueList; |
543 | DefaultValueIdx = Other.DefaultValueIdx; |
544 | for (ValueDetail &Detail : ValueList) |
545 | Detail.Decl = this; |
546 | return *this; |
547 | } |
548 | |
549 | Declaration &Declaration::operator=(Declaration &&Other) { |
550 | if (this == &Other) |
551 | return *this; |
552 | Name = std::move(Other.Name); |
553 | ValueList = std::move(Other.ValueList); |
554 | DefaultValueIdx = std::move(Other.DefaultValueIdx); |
555 | for (ValueDetail &Detail : ValueList) |
556 | Detail.Decl = this; |
557 | return *this; |
558 | } |
559 | } // namespace clang::driver::custom_flag |
560 |
Definitions
- Multilib
- dump
- operator==
- operator<<
- FilterOut
- push_back
- DiagnoseUnclaimedMultilibCustomFlags
- ValueNameToDetailMap
- ValueNameToDetailMap
- get
- processCustomFlags
- select
- expandFlags
- MultilibVersionCurrent
- MultilibSerialization
- MultilibGroupType
- MultilibGroupSerialization
- MultilibSetSerialization
- MappingTraits
- mapping
- validate
- ScalarEnumerationTraits
- enumeration
- MappingTraits
- mapping
- MappingTraits
- mapping
- validate
- MappingContextTraits
- mapping
- validate
- MappingContextTraits
- mapping
- validate
- MappingTraits
- mapping
- validate
- parseYaml
- dump
- operator<<
- Declaration
- Declaration
- operator=
Improve your Profiling and Debugging skills
Find out more