1// FormatString.cpp - Common stuff for handling printf/scanf formats -*- C++ -*-
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// Shared details for processing format strings of printf and scanf
10// (and friends).
11//
12//===----------------------------------------------------------------------===//
13
14#include "FormatStringParsing.h"
15#include "clang/Basic/LangOptions.h"
16#include "clang/Basic/TargetInfo.h"
17#include "llvm/ADT/StringExtras.h"
18#include "llvm/Support/ConvertUTF.h"
19#include <optional>
20
21using clang::analyze_format_string::ArgType;
22using clang::analyze_format_string::ConversionSpecifier;
23using clang::analyze_format_string::FormatSpecifier;
24using clang::analyze_format_string::FormatStringHandler;
25using clang::analyze_format_string::LengthModifier;
26using clang::analyze_format_string::OptionalAmount;
27using namespace clang;
28
29// Key function to FormatStringHandler.
30FormatStringHandler::~FormatStringHandler() {}
31
32//===----------------------------------------------------------------------===//
33// Functions for parsing format strings components in both printf and
34// scanf format strings.
35//===----------------------------------------------------------------------===//
36
37OptionalAmount clang::analyze_format_string::ParseAmount(const char *&Beg,
38 const char *E) {
39 const char *I = Beg;
40 UpdateOnReturn<const char *> UpdateBeg(Beg, I);
41
42 unsigned accumulator = 0;
43 bool hasDigits = false;
44
45 for (; I != E; ++I) {
46 char c = *I;
47 if (c >= '0' && c <= '9') {
48 hasDigits = true;
49 accumulator = (accumulator * 10) + (c - '0');
50 continue;
51 }
52
53 if (hasDigits)
54 return OptionalAmount(OptionalAmount::Constant, accumulator, Beg, I - Beg,
55 false);
56
57 break;
58 }
59
60 return OptionalAmount();
61}
62
63static bool ParseWidthModifier(const char *&I, const char *E,
64 unsigned &BitWidth, unsigned &ModifierLength) {
65 StringRef W = StringRef(I, E - I).take_while(F: llvm::isDigit);
66 if (W.empty() || W.front() == '0')
67 return false;
68
69 if (W.getAsInteger(Radix: 10, Result&: BitWidth))
70 return false;
71
72 I = W.end();
73 ModifierLength += W.size();
74
75 return true;
76}
77
78OptionalAmount clang::analyze_format_string::ParseNonPositionAmount(
79 const char *&Beg, const char *E, unsigned &argIndex) {
80 if (*Beg == '*') {
81 ++Beg;
82 return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg, 0, false);
83 }
84
85 return ParseAmount(Beg, E);
86}
87
88OptionalAmount clang::analyze_format_string::ParsePositionAmount(
89 FormatStringHandler &H, const char *Start, const char *&Beg, const char *E,
90 PositionContext p) {
91 if (*Beg == '*') {
92 const char *I = Beg + 1;
93 const OptionalAmount &Amt = ParseAmount(Beg&: I, E);
94
95 if (Amt.getHowSpecified() == OptionalAmount::NotSpecified) {
96 H.HandleInvalidPosition(startPos: Beg, posLen: I - Beg, p);
97 return OptionalAmount(false);
98 }
99
100 if (I == E) {
101 // No more characters left?
102 H.HandleIncompleteSpecifier(startSpecifier: Start, specifierLen: E - Start);
103 return OptionalAmount(false);
104 }
105
106 assert(Amt.getHowSpecified() == OptionalAmount::Constant);
107
108 if (*I == '$') {
109 // Handle positional arguments
110
111 // Special case: '*0$', since this is an easy mistake.
112 if (Amt.getConstantAmount() == 0) {
113 H.HandleZeroPosition(startPos: Beg, posLen: I - Beg + 1);
114 return OptionalAmount(false);
115 }
116
117 const char *Tmp = Beg;
118 Beg = ++I;
119
120 return OptionalAmount(OptionalAmount::Arg, Amt.getConstantAmount() - 1,
121 Tmp, 0, true);
122 }
123
124 H.HandleInvalidPosition(startPos: Beg, posLen: I - Beg, p);
125 return OptionalAmount(false);
126 }
127
128 return ParseAmount(Beg, E);
129}
130
131bool clang::analyze_format_string::ParseFieldWidth(
132 FormatStringHandler &H, FormatSpecifier &CS, const char *Start,
133 const char *&Beg, const char *E, unsigned *argIndex) {
134 // FIXME: Support negative field widths.
135 if (argIndex) {
136 CS.setFieldWidth(ParseNonPositionAmount(Beg, E, argIndex&: *argIndex));
137 } else {
138 const OptionalAmount Amt = ParsePositionAmount(
139 H, Start, Beg, E, p: analyze_format_string::FieldWidthPos);
140
141 if (Amt.isInvalid())
142 return true;
143 CS.setFieldWidth(Amt);
144 }
145 return false;
146}
147
148bool clang::analyze_format_string::ParseArgPosition(FormatStringHandler &H,
149 FormatSpecifier &FS,
150 const char *Start,
151 const char *&Beg,
152 const char *E) {
153 const char *I = Beg;
154
155 const OptionalAmount &Amt = ParseAmount(Beg&: I, E);
156
157 if (I == E) {
158 // No more characters left?
159 H.HandleIncompleteSpecifier(startSpecifier: Start, specifierLen: E - Start);
160 return true;
161 }
162
163 if (Amt.getHowSpecified() == OptionalAmount::Constant && *(I++) == '$') {
164 // Warn that positional arguments are non-standard.
165 H.HandlePosition(startPos: Start, posLen: I - Start);
166
167 // Special case: '%0$', since this is an easy mistake.
168 if (Amt.getConstantAmount() == 0) {
169 H.HandleZeroPosition(startPos: Start, posLen: I - Start);
170 return true;
171 }
172
173 FS.setArgIndex(Amt.getConstantAmount() - 1);
174 FS.setUsesPositionalArg();
175 // Update the caller's pointer if we decided to consume
176 // these characters.
177 Beg = I;
178 return false;
179 }
180
181 return false;
182}
183
184bool clang::analyze_format_string::ParseVectorModifier(FormatStringHandler &H,
185 FormatSpecifier &FS,
186 const char *&I,
187 const char *E,
188 const LangOptions &LO) {
189 if (!LO.OpenCL)
190 return false;
191
192 const char *Start = I;
193 if (*I == 'v') {
194 ++I;
195
196 if (I == E) {
197 H.HandleIncompleteSpecifier(startSpecifier: Start, specifierLen: E - Start);
198 return true;
199 }
200
201 OptionalAmount NumElts = ParseAmount(Beg&: I, E);
202 if (NumElts.getHowSpecified() != OptionalAmount::Constant) {
203 H.HandleIncompleteSpecifier(startSpecifier: Start, specifierLen: E - Start);
204 return true;
205 }
206
207 FS.setVectorNumElts(NumElts);
208 }
209
210 return false;
211}
212
213bool clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,
214 const char *&I,
215 const char *E,
216 const LangOptions &LO,
217 bool IsScanf) {
218 LengthModifier::Kind lmKind = LengthModifier::None;
219 const char *lmPosition = I;
220 switch (*I) {
221 default:
222 return false;
223 case 'h':
224 ++I;
225 if (I != E && *I == 'h') {
226 ++I;
227 lmKind = LengthModifier::AsChar;
228 } else if (I != E && *I == 'l' && LO.OpenCL) {
229 ++I;
230 lmKind = LengthModifier::AsShortLong;
231 } else {
232 lmKind = LengthModifier::AsShort;
233 }
234 break;
235 case 'l':
236 ++I;
237 if (I != E && *I == 'l') {
238 ++I;
239 lmKind = LengthModifier::AsLongLong;
240 } else {
241 lmKind = LengthModifier::AsLong;
242 }
243 break;
244 case 'j':
245 lmKind = LengthModifier::AsIntMax;
246 ++I;
247 break;
248 case 'z':
249 lmKind = LengthModifier::AsSizeT;
250 ++I;
251 break;
252 case 't':
253 lmKind = LengthModifier::AsPtrDiff;
254 ++I;
255 break;
256 case 'L':
257 lmKind = LengthModifier::AsLongDouble;
258 ++I;
259 break;
260 case 'q':
261 lmKind = LengthModifier::AsQuad;
262 ++I;
263 break;
264 case 'a':
265 if (IsScanf && !LO.C99 && !LO.CPlusPlus11) {
266 // For scanf in C90, look at the next character to see if this should
267 // be parsed as the GNU extension 'a' length modifier. If not, this
268 // will be parsed as a conversion specifier.
269 ++I;
270 if (I != E && (*I == 's' || *I == 'S' || *I == '[')) {
271 lmKind = LengthModifier::AsAllocate;
272 break;
273 }
274 --I;
275 }
276 return false;
277 case 'm':
278 if (IsScanf) {
279 lmKind = LengthModifier::AsMAllocate;
280 ++I;
281 break;
282 }
283 return false;
284 // printf: AsInt64, AsInt32, AsInt3264
285 // scanf: AsInt64
286 case 'I':
287 if (I + 1 != E && I + 2 != E) {
288 if (I[1] == '6' && I[2] == '4') {
289 I += 3;
290 lmKind = LengthModifier::AsInt64;
291 break;
292 }
293 if (IsScanf)
294 return false;
295
296 if (I[1] == '3' && I[2] == '2') {
297 I += 3;
298 lmKind = LengthModifier::AsInt32;
299 break;
300 }
301 }
302 ++I;
303 lmKind = LengthModifier::AsInt3264;
304 break;
305 case 'H':
306 if (LO.C23) {
307 lmKind = LengthModifier::AsDecimal32;
308 ++I;
309 break;
310 }
311 return false;
312 case 'D':
313 if (LO.C23) {
314 ++I;
315 if (I != E && *I == 'D') {
316 ++I;
317 lmKind = LengthModifier::AsDecimal128;
318 } else {
319 lmKind = LengthModifier::AsDecimal64;
320 }
321 break;
322 }
323 return false;
324 case 'w':
325 if (LO.C23) {
326 const char *WidthModifier = I + 1;
327 unsigned BitWidth = 0;
328 unsigned ModifierLength = 1;
329
330 LengthModifier::Kind WidthKind = LengthModifier::AsIntN;
331 if (WidthModifier != E && *WidthModifier == 'f') {
332 WidthModifier = I + 2;
333 ModifierLength = 2;
334 WidthKind = LengthModifier::AsFastIntN;
335 }
336
337 if (ParseWidthModifier(I&: WidthModifier, E, BitWidth, ModifierLength)) {
338 I = WidthModifier;
339 FS.setLengthModifier(
340 LengthModifier(lmPosition, WidthKind, BitWidth, ModifierLength));
341 return true;
342 }
343 }
344 lmKind = LengthModifier::AsWide;
345 ++I;
346 break;
347 }
348 LengthModifier lm(lmPosition, lmKind);
349 FS.setLengthModifier(lm);
350 return true;
351}
352
353bool clang::analyze_format_string::ParseUTF8InvalidSpecifier(
354 const char *SpecifierBegin, const char *FmtStrEnd, unsigned &Len) {
355 if (SpecifierBegin + 1 >= FmtStrEnd)
356 return false;
357
358 const llvm::UTF8 *SB =
359 reinterpret_cast<const llvm::UTF8 *>(SpecifierBegin + 1);
360 const llvm::UTF8 *SE = reinterpret_cast<const llvm::UTF8 *>(FmtStrEnd);
361 const char FirstByte = *SB;
362
363 // If the invalid specifier is a multibyte UTF-8 string, return the
364 // total length accordingly so that the conversion specifier can be
365 // properly updated to reflect a complete UTF-8 specifier.
366 unsigned NumBytes = llvm::getNumBytesForUTF8(firstByte: FirstByte);
367 if (NumBytes == 1)
368 return false;
369 if (SB + NumBytes > SE)
370 return false;
371
372 Len = NumBytes + 1;
373 return true;
374}
375
376//===----------------------------------------------------------------------===//
377// Methods on ArgType.
378//===----------------------------------------------------------------------===//
379
380static bool namedTypeToLengthModifierKind(ASTContext &Ctx, QualType QT,
381 LengthModifier::Kind &K) {
382 if (!Ctx.getLangOpts().C99 && !Ctx.getLangOpts().CPlusPlus)
383 return false;
384 for (/**/; const auto *TT = QT->getAs<TypedefType>(); QT = TT->desugar()) {
385 const auto *TD = TT->getDecl();
386 const auto *DC = TT->getDecl()->getDeclContext();
387 if (DC->isTranslationUnit() || DC->isStdNamespace()) {
388 StringRef Name = TD->getIdentifier()->getName();
389 if (Name == "size_t") {
390 K = LengthModifier::AsSizeT;
391 return true;
392 } else if (Name == "ssize_t" /*Not C99, but common in Unix.*/) {
393 K = LengthModifier::AsSizeT;
394 return true;
395 } else if (Name == "ptrdiff_t") {
396 K = LengthModifier::AsPtrDiff;
397 return true;
398 } else if (Name == "intmax_t") {
399 K = LengthModifier::AsIntMax;
400 return true;
401 } else if (Name == "uintmax_t") {
402 K = LengthModifier::AsIntMax;
403 return true;
404 }
405 }
406 }
407 if (const auto *PST = QT->getAs<PredefinedSugarType>()) {
408 using Kind = PredefinedSugarType::Kind;
409 switch (PST->getKind()) {
410 case Kind::SizeT:
411 case Kind::SignedSizeT:
412 K = LengthModifier::AsSizeT;
413 return true;
414 case Kind::PtrdiffT:
415 K = LengthModifier::AsPtrDiff;
416 return true;
417 }
418 llvm_unreachable("unexpected kind");
419 }
420 return false;
421}
422
423// Check whether T and E are compatible size_t/ptrdiff_t types. E must be
424// consistent with LE.
425// T is the type of the actual expression in the code to be checked, and E is
426// the expected type parsed from the format string.
427static clang::analyze_format_string::ArgType::MatchKind
428matchesSizeTPtrdiffT(ASTContext &C, QualType T, QualType E) {
429 using MatchKind = clang::analyze_format_string::ArgType::MatchKind;
430
431 if (!T->isIntegerType() || T->isBooleanType())
432 return MatchKind::NoMatch;
433
434 if (C.hasSameType(T1: T, T2: E))
435 return MatchKind::Match;
436
437 if (C.getCorrespondingSignedType(T: T.getCanonicalType()) !=
438 C.getCorrespondingSignedType(T: E.getCanonicalType()))
439 return MatchKind::NoMatch;
440
441 return MatchKind::NoMatchSignedness;
442}
443
444clang::analyze_format_string::ArgType::MatchKind
445ArgType::matchesType(ASTContext &C, QualType argTy) const {
446 // When using the format attribute in C++, you can receive a function or an
447 // array that will necessarily decay to a pointer when passed to the final
448 // format consumer. Apply decay before type comparison.
449 if (argTy->canDecayToPointerType())
450 argTy = C.getDecayedType(T: argTy);
451
452 if (Ptr) {
453 // It has to be a pointer.
454 const PointerType *PT = argTy->getAs<PointerType>();
455 if (!PT)
456 return NoMatch;
457
458 // We cannot write through a const qualified pointer.
459 if (PT->getPointeeType().isConstQualified())
460 return NoMatch;
461
462 argTy = PT->getPointeeType();
463 }
464
465 if (const auto *OBT = argTy->getAs<OverflowBehaviorType>())
466 argTy = OBT->getUnderlyingType();
467
468 switch (K) {
469 case InvalidTy:
470 llvm_unreachable("ArgType must be valid");
471
472 case UnsupportedTy:
473 return NoMatch;
474
475 case UnknownTy:
476 return Match;
477
478 case AnyCharTy: {
479 if (const auto *ED = argTy->getAsEnumDecl()) {
480 // If the enum is incomplete we know nothing about the underlying type.
481 // Assume that it's 'int'. Do not use the underlying type for a scoped
482 // enumeration.
483 if (!ED->isComplete())
484 return NoMatch;
485 if (!ED->isScoped())
486 argTy = ED->getIntegerType();
487 }
488
489 if (const auto *BT = argTy->getAs<BuiltinType>()) {
490 // The types are perfectly matched?
491 switch (BT->getKind()) {
492 default:
493 break;
494 case BuiltinType::Char_S:
495 case BuiltinType::SChar:
496 case BuiltinType::UChar:
497 case BuiltinType::Char_U:
498 return Match;
499 case BuiltinType::Bool:
500 if (!Ptr)
501 return Match;
502 break;
503 }
504 // "Partially matched" because of promotions?
505 if (!Ptr) {
506 switch (BT->getKind()) {
507 default:
508 break;
509 case BuiltinType::Int:
510 case BuiltinType::UInt:
511 return MatchPromotion;
512 case BuiltinType::Short:
513 case BuiltinType::UShort:
514 case BuiltinType::WChar_S:
515 case BuiltinType::WChar_U:
516 return NoMatchPromotionTypeConfusion;
517 }
518 }
519 }
520 return NoMatch;
521 }
522
523 case SpecificTy: {
524 if (TK == TypeKind::SizeT || TK == TypeKind::PtrdiffT) {
525 return matchesSizeTPtrdiffT(C, T: argTy, E: T);
526 }
527
528 if (const auto *ED = argTy->getAsEnumDecl()) {
529 // If the enum is incomplete we know nothing about the underlying type.
530 // Assume that it's 'int'. Do not use the underlying type for a scoped
531 // enumeration as that needs an exact match.
532 if (!ED->isComplete())
533 argTy = C.IntTy;
534 else if (!ED->isScoped())
535 argTy = ED->getIntegerType();
536 }
537
538 if (argTy->isSaturatedFixedPointType())
539 argTy = C.getCorrespondingUnsaturatedType(Ty: argTy);
540
541 argTy = C.getCanonicalType(T: argTy).getUnqualifiedType();
542
543 if (T == argTy)
544 return Match;
545 if (const auto *BT = argTy->getAs<BuiltinType>()) {
546 // Check if the only difference between them is signed vs unsigned
547 // if true, return match signedness.
548 switch (BT->getKind()) {
549 default:
550 break;
551 case BuiltinType::Bool:
552 if (Ptr && (T == C.UnsignedCharTy || T == C.SignedCharTy))
553 return NoMatch;
554 [[fallthrough]];
555 case BuiltinType::Char_S:
556 case BuiltinType::SChar:
557 if (T == C.UnsignedShortTy || T == C.ShortTy)
558 return NoMatchTypeConfusion;
559 if (T == C.UnsignedCharTy)
560 return NoMatchSignedness;
561 if (T == C.SignedCharTy)
562 return Match;
563 break;
564 case BuiltinType::Char_U:
565 case BuiltinType::UChar:
566 if (T == C.UnsignedShortTy || T == C.ShortTy)
567 return NoMatchTypeConfusion;
568 if (T == C.UnsignedCharTy)
569 return Match;
570 if (T == C.SignedCharTy)
571 return NoMatchSignedness;
572 break;
573 case BuiltinType::Short:
574 if (T == C.UnsignedShortTy)
575 return NoMatchSignedness;
576 break;
577 case BuiltinType::UShort:
578 if (T == C.ShortTy)
579 return NoMatchSignedness;
580 break;
581 case BuiltinType::Int:
582 if (T == C.UnsignedIntTy)
583 return NoMatchSignedness;
584 break;
585 case BuiltinType::UInt:
586 if (T == C.IntTy)
587 return NoMatchSignedness;
588 break;
589 case BuiltinType::Long:
590 if (T == C.UnsignedLongTy)
591 return NoMatchSignedness;
592 break;
593 case BuiltinType::ULong:
594 if (T == C.LongTy)
595 return NoMatchSignedness;
596 break;
597 case BuiltinType::LongLong:
598 if (T == C.UnsignedLongLongTy)
599 return NoMatchSignedness;
600 break;
601 case BuiltinType::ULongLong:
602 if (T == C.LongLongTy)
603 return NoMatchSignedness;
604 break;
605 }
606 // "Partially matched" because of promotions?
607 if (!Ptr) {
608 switch (BT->getKind()) {
609 default:
610 break;
611 case BuiltinType::Bool:
612 if (T == C.IntTy || T == C.UnsignedIntTy)
613 return MatchPromotion;
614 break;
615 case BuiltinType::Int:
616 case BuiltinType::UInt:
617 if (T == C.SignedCharTy || T == C.UnsignedCharTy || T == C.ShortTy ||
618 T == C.UnsignedShortTy || T == C.WCharTy || T == C.WideCharTy)
619 return MatchPromotion;
620 break;
621 case BuiltinType::Char_U:
622 if (T == C.UnsignedIntTy)
623 return MatchPromotion;
624 if (T == C.UnsignedShortTy)
625 return NoMatchPromotionTypeConfusion;
626 break;
627 case BuiltinType::Char_S:
628 if (T == C.IntTy)
629 return MatchPromotion;
630 if (T == C.ShortTy)
631 return NoMatchPromotionTypeConfusion;
632 break;
633 case BuiltinType::Half:
634 case BuiltinType::Float:
635 if (T == C.DoubleTy)
636 return MatchPromotion;
637 break;
638 case BuiltinType::Short:
639 case BuiltinType::UShort:
640 if (T == C.SignedCharTy || T == C.UnsignedCharTy)
641 return NoMatchPromotionTypeConfusion;
642 break;
643 case BuiltinType::WChar_U:
644 case BuiltinType::WChar_S:
645 if (T != C.WCharTy && T != C.WideCharTy)
646 return NoMatchPromotionTypeConfusion;
647 }
648 }
649 }
650 return NoMatch;
651 }
652
653 case CStrTy:
654 if (const auto *PT = argTy->getAs<PointerType>();
655 PT && PT->getPointeeType()->isCharType())
656 return Match;
657 return NoMatch;
658
659 case WCStrTy:
660 if (const auto *PT = argTy->getAs<PointerType>();
661 PT &&
662 C.hasSameUnqualifiedType(T1: PT->getPointeeType(), T2: C.getWideCharType()))
663 return Match;
664 return NoMatch;
665
666 case WIntTy: {
667 QualType WInt = C.getCanonicalType(T: C.getWIntType()).getUnqualifiedType();
668
669 if (C.getCanonicalType(T: argTy).getUnqualifiedType() == WInt)
670 return Match;
671
672 QualType PromoArg = C.isPromotableIntegerType(T: argTy)
673 ? C.getPromotedIntegerType(PromotableType: argTy)
674 : argTy;
675 PromoArg = C.getCanonicalType(T: PromoArg).getUnqualifiedType();
676
677 // If the promoted argument is the corresponding signed type of the
678 // wint_t type, then it should match.
679 if (PromoArg->hasSignedIntegerRepresentation() &&
680 C.getCorrespondingUnsignedType(T: PromoArg) == WInt)
681 return Match;
682
683 return WInt == PromoArg ? Match : NoMatch;
684 }
685
686 case CPointerTy:
687 if (const auto *PT = argTy->getAs<PointerType>()) {
688 QualType PointeeTy = PT->getPointeeType();
689 if (PointeeTy->isVoidType() || (!Ptr && PointeeTy->isCharType()))
690 return Match;
691 return NoMatchPedantic;
692 }
693
694 // nullptr_t* is not a double pointer, so reject when something like
695 // void** is expected.
696 // In C++, nullptr is promoted to void*. In C23, va_arg(ap, void*) is not
697 // undefined when the next argument is of type nullptr_t.
698 if (!Ptr && argTy->isNullPtrType())
699 return C.getLangOpts().CPlusPlus ? MatchPromotion : Match;
700
701 if (argTy->isObjCObjectPointerType() || argTy->isBlockPointerType())
702 return NoMatchPedantic;
703
704 return NoMatch;
705
706 case ObjCPointerTy: {
707 if (argTy->getAs<ObjCObjectPointerType>() ||
708 argTy->getAs<BlockPointerType>())
709 return Match;
710
711 // Handle implicit toll-free bridging.
712 if (const PointerType *PT = argTy->getAs<PointerType>()) {
713 // Things such as CFTypeRef are really just opaque pointers
714 // to C structs representing CF types that can often be bridged
715 // to Objective-C objects. Since the compiler doesn't know which
716 // structs can be toll-free bridged, we just accept them all.
717 QualType pointee = PT->getPointeeType();
718 if (pointee->isStructureType() || pointee->isVoidType())
719 return Match;
720 }
721 return NoMatch;
722 }
723 }
724
725 llvm_unreachable("Invalid ArgType Kind!");
726}
727
728static analyze_format_string::ArgType::MatchKind
729integerTypeMatch(ASTContext &C, QualType A, QualType B, bool CheckSign) {
730 using MK = analyze_format_string::ArgType::MatchKind;
731
732 uint64_t IntSize = C.getTypeSize(T: C.IntTy);
733 uint64_t ASize = C.getTypeSize(T: A);
734 uint64_t BSize = C.getTypeSize(T: B);
735 if (std::max(a: ASize, b: IntSize) != std::max(a: BSize, b: IntSize))
736 return MK::NoMatch;
737 if (CheckSign && A->isSignedIntegerType() != B->isSignedIntegerType())
738 return MK::NoMatchSignedness;
739 if (ASize != BSize)
740 return MK::MatchPromotion;
741 return MK::Match;
742}
743
744analyze_format_string::ArgType::MatchKind
745ArgType::matchesArgType(ASTContext &C, const ArgType &Other) const {
746 using AK = analyze_format_string::ArgType::Kind;
747
748 // Per matchesType.
749 if (K == AK::InvalidTy || Other.K == AK::InvalidTy)
750 return NoMatch;
751 if (K == AK::UnsupportedTy || Other.K == AK::UnsupportedTy)
752 return NoMatch;
753 if (K == AK::UnknownTy || Other.K == AK::UnknownTy)
754 return Match;
755
756 // Handle whether either (or both, or neither) sides has Ptr set,
757 // in addition to whether either (or both, or neither) sides is a SpecificTy
758 // that is a pointer.
759 ArgType Left = *this;
760 bool LeftWasPointer = false;
761 ArgType Right = Other;
762 bool RightWasPointer = false;
763 if (Left.Ptr) {
764 Left.Ptr = false;
765 LeftWasPointer = true;
766 } else if (Left.K == AK::SpecificTy && Left.T->isPointerType()) {
767 Left.T = Left.T->getPointeeType();
768 LeftWasPointer = true;
769 }
770 if (Right.Ptr) {
771 Right.Ptr = false;
772 RightWasPointer = true;
773 } else if (Right.K == AK::SpecificTy && Right.T->isPointerType()) {
774 Right.T = Right.T->getPointeeType();
775 RightWasPointer = true;
776 }
777
778 if (LeftWasPointer != RightWasPointer)
779 return NoMatch;
780
781 // Ensure that if at least one side is a SpecificTy, then Left is a
782 // SpecificTy.
783 if (Right.K == AK::SpecificTy)
784 std::swap(a&: Left, b&: Right);
785
786 if (Left.K == AK::SpecificTy) {
787 if (Right.K == AK::SpecificTy) {
788 if (Left.TK != TypeKind::DontCare) {
789 return matchesSizeTPtrdiffT(C, T: Right.T, E: Left.T);
790 } else if (Right.TK != TypeKind::DontCare) {
791 return matchesSizeTPtrdiffT(C, T: Left.T, E: Right.T);
792 }
793
794 auto Canon1 = C.getCanonicalType(T: Left.T);
795 auto Canon2 = C.getCanonicalType(T: Right.T);
796 if (Canon1 == Canon2)
797 return Match;
798
799 auto *BT1 = QualType(Canon1)->getAs<BuiltinType>();
800 auto *BT2 = QualType(Canon2)->getAs<BuiltinType>();
801 if (BT1 == nullptr || BT2 == nullptr)
802 return NoMatch;
803 if (BT1 == BT2)
804 return Match;
805
806 if (!LeftWasPointer && BT1->isInteger() && BT2->isInteger())
807 return integerTypeMatch(C, A: Canon1, B: Canon2, CheckSign: true);
808 return NoMatch;
809 } else if (Right.K == AK::AnyCharTy) {
810 if (!LeftWasPointer && Left.T->isIntegerType())
811 return integerTypeMatch(C, A: Left.T, B: C.CharTy, CheckSign: false);
812 return NoMatch;
813 } else if (Right.K == AK::WIntTy) {
814 if (!LeftWasPointer && Left.T->isIntegerType())
815 return integerTypeMatch(C, A: Left.T, B: C.WIntTy, CheckSign: true);
816 return NoMatch;
817 }
818 // It's hypothetically possible to create an AK::SpecificTy ArgType
819 // that matches another kind of ArgType, but in practice Clang doesn't
820 // do that, so ignore that case.
821 return NoMatch;
822 }
823
824 return Left.K == Right.K ? Match : NoMatch;
825}
826
827ArgType ArgType::makeVectorType(ASTContext &C, unsigned NumElts) const {
828 // Check for valid vector element types.
829 if (T.isNull())
830 return ArgType::Invalid();
831
832 QualType Vec = C.getExtVectorType(VectorType: T, NumElts);
833 return ArgType(Vec, Name);
834}
835
836ArgType ArgType::makeIntNType(ASTContext &Ctx, const LengthModifier &LengthMod,
837 bool Signed) {
838 bool IsFast = LengthMod.getKind() == LengthModifier::AsFastIntN;
839 QualType Ty =
840 IsFast ? Ctx.getLeastIntTypeForBitwidth(DestWidth: LengthMod.getBitWidth(), Signed)
841 : Ctx.getIntTypeForBitwidth(DestWidth: LengthMod.getBitWidth(), Signed);
842 if (Ty.isNull())
843 return ArgType::Invalid();
844
845 ArgType Res(Ty);
846 Res.TK = IsFast ? (Signed ? TypeKind::FastIntN : TypeKind::FastUIntN)
847 : (Signed ? TypeKind::IntN : TypeKind::UIntN);
848 Res.BitWidth = LengthMod.getBitWidth();
849 return Res;
850}
851
852QualType ArgType::getRepresentativeType(ASTContext &C) const {
853 QualType Res;
854 switch (K) {
855 case InvalidTy:
856 llvm_unreachable("No representative type for Invalid ArgType");
857 case UnknownTy:
858 llvm_unreachable("No representative type for Unknown ArgType");
859 case UnsupportedTy:
860 llvm_unreachable("No representative type for Unsupported ArgType");
861 case AnyCharTy:
862 Res = C.CharTy;
863 break;
864 case SpecificTy:
865 if (TK == TypeKind::PtrdiffT || TK == TypeKind::SizeT)
866 // Using Name as name, so no need to show the uglified name.
867 Res = T->getCanonicalTypeInternal();
868 else
869 Res = T;
870 break;
871 case CStrTy:
872 Res = C.getPointerType(T: C.CharTy);
873 break;
874 case WCStrTy:
875 Res = C.getPointerType(T: C.getWideCharType());
876 break;
877 case ObjCPointerTy:
878 Res = C.ObjCBuiltinIdTy;
879 break;
880 case CPointerTy:
881 Res = C.VoidPtrTy;
882 break;
883 case WIntTy: {
884 Res = C.getWIntType();
885 break;
886 }
887 }
888
889 if (Ptr)
890 Res = C.getPointerType(T: Res);
891 return Res;
892}
893
894std::string ArgType::getRepresentativeTypeName(ASTContext &C) const {
895 std::string S;
896 if (K != UnsupportedTy)
897 S = getRepresentativeType(C).getAsString(Policy: C.getPrintingPolicy());
898
899 std::string Alias;
900 if (Name) {
901 // Use a specific name for this type, e.g. "size_t".
902 Alias = Name;
903 } else {
904 const char *Prefix = nullptr;
905 switch (TK) {
906 case TypeKind::IntN:
907 Prefix = "int";
908 break;
909 case TypeKind::UIntN:
910 Prefix = "uint";
911 break;
912 case TypeKind::FastIntN:
913 Prefix = "int_fast";
914 break;
915 case TypeKind::FastUIntN:
916 Prefix = "uint_fast";
917 break;
918 case TypeKind::DontCare:
919 case TypeKind::SizeT:
920 case TypeKind::PtrdiffT:
921 break;
922 }
923 if (Prefix) {
924 Alias = Prefix;
925 Alias += std::to_string(val: BitWidth);
926 Alias += "_t";
927 }
928 }
929 if (!Alias.empty()) {
930 if (Ptr) {
931 // If ArgType is actually a pointer to T, append an asterisk.
932 Alias += (Alias[Alias.size() - 1] == '*') ? "*" : " *";
933 }
934 // If Alias is the same as the underlying type, e.g. wchar_t, then drop it.
935 if (S == Alias)
936 Alias.clear();
937 }
938
939 if (Alias.empty())
940 return std::string("'") + S + "'";
941
942 return std::string("'") + Alias + "'" +
943 (K == UnsupportedTy ? "" : " (aka '" + S + "')");
944}
945
946//===----------------------------------------------------------------------===//
947// Methods on OptionalAmount.
948//===----------------------------------------------------------------------===//
949
950ArgType
951analyze_format_string::OptionalAmount::getArgType(ASTContext &Ctx) const {
952 return Ctx.IntTy;
953}
954
955//===----------------------------------------------------------------------===//
956// Methods on LengthModifier.
957//===----------------------------------------------------------------------===//
958
959StringRef analyze_format_string::LengthModifier::toString() const {
960 switch (kind) {
961 case AsChar:
962 return "hh";
963 case AsShort:
964 return "h";
965 case AsShortLong:
966 return "hl";
967 case AsLong: // or AsWideChar
968 return "l";
969 case AsLongLong:
970 return "ll";
971 case AsQuad:
972 return "q";
973 case AsIntMax:
974 return "j";
975 case AsSizeT:
976 return "z";
977 case AsPtrDiff:
978 return "t";
979 case AsInt32:
980 return "I32";
981 case AsInt3264:
982 return "I";
983 case AsInt64:
984 return "I64";
985 case AsLongDouble:
986 return "L";
987 case AsDecimal32:
988 return "H";
989 case AsDecimal64:
990 return "D";
991 case AsDecimal128:
992 return "DD";
993 case AsIntN:
994 case AsFastIntN:
995 return StringRef(Position, getLength());
996 case AsAllocate:
997 return "a";
998 case AsMAllocate:
999 return "m";
1000 case AsWide:
1001 return "w";
1002 case None:
1003 return "";
1004 }
1005 llvm_unreachable("Invalid LengthModifier Kind!");
1006}
1007
1008//===----------------------------------------------------------------------===//
1009// Methods on ConversionSpecifier.
1010//===----------------------------------------------------------------------===//
1011
1012const char *ConversionSpecifier::toString() const {
1013 switch (kind) {
1014 case bArg:
1015 return "b";
1016 case BArg:
1017 return "B";
1018 case dArg:
1019 return "d";
1020 case DArg:
1021 return "D";
1022 case iArg:
1023 return "i";
1024 case oArg:
1025 return "o";
1026 case OArg:
1027 return "O";
1028 case uArg:
1029 return "u";
1030 case UArg:
1031 return "U";
1032 case xArg:
1033 return "x";
1034 case XArg:
1035 return "X";
1036 case fArg:
1037 return "f";
1038 case FArg:
1039 return "F";
1040 case eArg:
1041 return "e";
1042 case EArg:
1043 return "E";
1044 case gArg:
1045 return "g";
1046 case GArg:
1047 return "G";
1048 case aArg:
1049 return "a";
1050 case AArg:
1051 return "A";
1052 case cArg:
1053 return "c";
1054 case sArg:
1055 return "s";
1056 case pArg:
1057 return "p";
1058 case PArg:
1059 return "P";
1060 case nArg:
1061 return "n";
1062 case PercentArg:
1063 return "%";
1064 case ScanListArg:
1065 return "[";
1066 case InvalidSpecifier:
1067 return nullptr;
1068
1069 // POSIX unicode extensions.
1070 case CArg:
1071 return "C";
1072 case SArg:
1073 return "S";
1074
1075 // Objective-C specific specifiers.
1076 case ObjCObjArg:
1077 return "@";
1078
1079 // FreeBSD kernel specific specifiers.
1080 case FreeBSDbArg:
1081 return "b";
1082 case FreeBSDDArg:
1083 return "D";
1084 case FreeBSDrArg:
1085 return "r";
1086 case FreeBSDyArg:
1087 return "y";
1088
1089 // GlibC specific specifiers.
1090 case PrintErrno:
1091 return "m";
1092
1093 // MS specific specifiers.
1094 case ZArg:
1095 return "Z";
1096
1097 // ISO/IEC TR 18037 (fixed-point) specific specifiers.
1098 case rArg:
1099 return "r";
1100 case RArg:
1101 return "R";
1102 case kArg:
1103 return "k";
1104 case KArg:
1105 return "K";
1106 }
1107 return nullptr;
1108}
1109
1110std::optional<ConversionSpecifier>
1111ConversionSpecifier::getStandardSpecifier() const {
1112 ConversionSpecifier::Kind NewKind;
1113
1114 switch (getKind()) {
1115 default:
1116 return std::nullopt;
1117 case DArg:
1118 NewKind = dArg;
1119 break;
1120 case UArg:
1121 NewKind = uArg;
1122 break;
1123 case OArg:
1124 NewKind = oArg;
1125 break;
1126 }
1127
1128 ConversionSpecifier FixedCS(*this);
1129 FixedCS.setKind(NewKind);
1130 return FixedCS;
1131}
1132
1133//===----------------------------------------------------------------------===//
1134// Methods on OptionalAmount.
1135//===----------------------------------------------------------------------===//
1136
1137void OptionalAmount::toString(raw_ostream &os) const {
1138 switch (hs) {
1139 case Invalid:
1140 case NotSpecified:
1141 return;
1142 case Arg:
1143 if (UsesDotPrefix)
1144 os << ".";
1145 if (usesPositionalArg())
1146 os << "*" << getPositionalArgIndex() << "$";
1147 else
1148 os << "*";
1149 break;
1150 case Constant:
1151 if (UsesDotPrefix)
1152 os << ".";
1153 os << amt;
1154 break;
1155 }
1156}
1157
1158bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target,
1159 const LangOptions &LO) const {
1160 switch (LM.getKind()) {
1161 case LengthModifier::None:
1162 return true;
1163
1164 // Handle most integer flags
1165 case LengthModifier::AsShort:
1166 // Length modifier only applies to FP vectors.
1167 if (LO.OpenCL && CS.isDoubleArg())
1168 return !VectorNumElts.isInvalid();
1169
1170 if (CS.isFixedPointArg())
1171 return true;
1172
1173 if (Target.getTriple().isOSMSVCRT()) {
1174 switch (CS.getKind()) {
1175 case ConversionSpecifier::cArg:
1176 case ConversionSpecifier::CArg:
1177 case ConversionSpecifier::sArg:
1178 case ConversionSpecifier::SArg:
1179 case ConversionSpecifier::ZArg:
1180 return true;
1181 default:
1182 break;
1183 }
1184 }
1185 [[fallthrough]];
1186 case LengthModifier::AsChar:
1187 case LengthModifier::AsLongLong:
1188 case LengthModifier::AsQuad:
1189 case LengthModifier::AsIntMax:
1190 case LengthModifier::AsSizeT:
1191 case LengthModifier::AsPtrDiff:
1192 switch (CS.getKind()) {
1193 case ConversionSpecifier::bArg:
1194 case ConversionSpecifier::BArg:
1195 case ConversionSpecifier::dArg:
1196 case ConversionSpecifier::DArg:
1197 case ConversionSpecifier::iArg:
1198 case ConversionSpecifier::oArg:
1199 case ConversionSpecifier::OArg:
1200 case ConversionSpecifier::uArg:
1201 case ConversionSpecifier::UArg:
1202 case ConversionSpecifier::xArg:
1203 case ConversionSpecifier::XArg:
1204 case ConversionSpecifier::nArg:
1205 return true;
1206 case ConversionSpecifier::FreeBSDrArg:
1207 case ConversionSpecifier::FreeBSDyArg:
1208 return Target.getTriple().isOSFreeBSD() || Target.getTriple().isPS();
1209 default:
1210 return false;
1211 }
1212
1213 case LengthModifier::AsShortLong:
1214 return LO.OpenCL && !VectorNumElts.isInvalid();
1215
1216 // Handle 'l' flag
1217 case LengthModifier::AsLong: // or AsWideChar
1218 if (CS.isDoubleArg()) {
1219 // Invalid for OpenCL FP scalars.
1220 if (LO.OpenCL && VectorNumElts.isInvalid())
1221 return false;
1222 return true;
1223 }
1224
1225 if (CS.isFixedPointArg())
1226 return true;
1227
1228 switch (CS.getKind()) {
1229 case ConversionSpecifier::bArg:
1230 case ConversionSpecifier::BArg:
1231 case ConversionSpecifier::dArg:
1232 case ConversionSpecifier::DArg:
1233 case ConversionSpecifier::iArg:
1234 case ConversionSpecifier::oArg:
1235 case ConversionSpecifier::OArg:
1236 case ConversionSpecifier::uArg:
1237 case ConversionSpecifier::UArg:
1238 case ConversionSpecifier::xArg:
1239 case ConversionSpecifier::XArg:
1240 case ConversionSpecifier::nArg:
1241 case ConversionSpecifier::cArg:
1242 case ConversionSpecifier::sArg:
1243 case ConversionSpecifier::ScanListArg:
1244 case ConversionSpecifier::ZArg:
1245 return true;
1246 case ConversionSpecifier::FreeBSDrArg:
1247 case ConversionSpecifier::FreeBSDyArg:
1248 return Target.getTriple().isOSFreeBSD() || Target.getTriple().isPS();
1249 default:
1250 return false;
1251 }
1252
1253 case LengthModifier::AsLongDouble:
1254 switch (CS.getKind()) {
1255 case ConversionSpecifier::aArg:
1256 case ConversionSpecifier::AArg:
1257 case ConversionSpecifier::fArg:
1258 case ConversionSpecifier::FArg:
1259 case ConversionSpecifier::eArg:
1260 case ConversionSpecifier::EArg:
1261 case ConversionSpecifier::gArg:
1262 case ConversionSpecifier::GArg:
1263 return true;
1264 // GNU libc extension.
1265 case ConversionSpecifier::dArg:
1266 case ConversionSpecifier::iArg:
1267 case ConversionSpecifier::oArg:
1268 case ConversionSpecifier::uArg:
1269 case ConversionSpecifier::xArg:
1270 case ConversionSpecifier::XArg:
1271 return !Target.getTriple().isOSDarwin() &&
1272 !Target.getTriple().isOSWindows();
1273 default:
1274 return false;
1275 }
1276
1277 case LengthModifier::AsIntN:
1278 case LengthModifier::AsFastIntN: {
1279 if (!LO.C23)
1280 return false;
1281
1282 TargetInfo::IntType TargetType =
1283 LM.getKind() == LengthModifier::AsIntN
1284 ? Target.getIntTypeByWidth(BitWidth: LM.getBitWidth(), /*IsSigned=*/true)
1285 : Target.getLeastIntTypeByWidth(BitWidth: LM.getBitWidth(),
1286 /*IsSigned=*/true);
1287 if (TargetType == TargetInfo::NoInt)
1288 return false;
1289
1290 switch (CS.getKind()) {
1291 case ConversionSpecifier::bArg:
1292 case ConversionSpecifier::BArg:
1293 case ConversionSpecifier::dArg:
1294 case ConversionSpecifier::iArg:
1295 case ConversionSpecifier::oArg:
1296 case ConversionSpecifier::uArg:
1297 case ConversionSpecifier::xArg:
1298 case ConversionSpecifier::XArg:
1299 case ConversionSpecifier::nArg:
1300 return true;
1301 default:
1302 return false;
1303 }
1304 }
1305
1306 case LengthModifier::AsAllocate:
1307 switch (CS.getKind()) {
1308 case ConversionSpecifier::sArg:
1309 case ConversionSpecifier::SArg:
1310 case ConversionSpecifier::ScanListArg:
1311 return true;
1312 default:
1313 return false;
1314 }
1315
1316 case LengthModifier::AsMAllocate:
1317 switch (CS.getKind()) {
1318 case ConversionSpecifier::cArg:
1319 case ConversionSpecifier::CArg:
1320 case ConversionSpecifier::sArg:
1321 case ConversionSpecifier::SArg:
1322 case ConversionSpecifier::ScanListArg:
1323 return true;
1324 default:
1325 return false;
1326 }
1327 case LengthModifier::AsInt32:
1328 case LengthModifier::AsInt3264:
1329 case LengthModifier::AsInt64:
1330 switch (CS.getKind()) {
1331 case ConversionSpecifier::dArg:
1332 case ConversionSpecifier::iArg:
1333 case ConversionSpecifier::oArg:
1334 case ConversionSpecifier::uArg:
1335 case ConversionSpecifier::xArg:
1336 case ConversionSpecifier::XArg:
1337 return Target.getTriple().isOSMSVCRT();
1338 default:
1339 return false;
1340 }
1341 case LengthModifier::AsWide:
1342 switch (CS.getKind()) {
1343 case ConversionSpecifier::cArg:
1344 case ConversionSpecifier::CArg:
1345 case ConversionSpecifier::sArg:
1346 case ConversionSpecifier::SArg:
1347 case ConversionSpecifier::ZArg:
1348 return Target.getTriple().isOSMSVCRT();
1349 default:
1350 return false;
1351 }
1352
1353 case LengthModifier::AsDecimal32:
1354 case LengthModifier::AsDecimal64:
1355 case LengthModifier::AsDecimal128:
1356 switch (CS.getKind()) {
1357 case ConversionSpecifier::aArg:
1358 case ConversionSpecifier::AArg:
1359 case ConversionSpecifier::eArg:
1360 case ConversionSpecifier::EArg:
1361 case ConversionSpecifier::fArg:
1362 case ConversionSpecifier::FArg:
1363 case ConversionSpecifier::gArg:
1364 case ConversionSpecifier::GArg:
1365 return LO.C23;
1366 default:
1367 return false;
1368 }
1369 }
1370 llvm_unreachable("Invalid LengthModifier Kind!");
1371}
1372
1373bool FormatSpecifier::hasStandardLengthModifier() const {
1374 switch (LM.getKind()) {
1375 case LengthModifier::None:
1376 case LengthModifier::AsChar:
1377 case LengthModifier::AsShort:
1378 case LengthModifier::AsLong:
1379 case LengthModifier::AsLongLong:
1380 case LengthModifier::AsIntMax:
1381 case LengthModifier::AsSizeT:
1382 case LengthModifier::AsPtrDiff:
1383 case LengthModifier::AsLongDouble:
1384 case LengthModifier::AsDecimal32:
1385 case LengthModifier::AsDecimal64:
1386 case LengthModifier::AsDecimal128:
1387 case LengthModifier::AsIntN:
1388 case LengthModifier::AsFastIntN:
1389 return true;
1390 case LengthModifier::AsAllocate:
1391 case LengthModifier::AsMAllocate:
1392 case LengthModifier::AsQuad:
1393 case LengthModifier::AsInt32:
1394 case LengthModifier::AsInt3264:
1395 case LengthModifier::AsInt64:
1396 case LengthModifier::AsWide:
1397 case LengthModifier::AsShortLong: // ???
1398 return false;
1399 }
1400 llvm_unreachable("Invalid LengthModifier Kind!");
1401}
1402
1403bool FormatSpecifier::hasStandardConversionSpecifier(
1404 const LangOptions &LangOpt) const {
1405 switch (CS.getKind()) {
1406 case ConversionSpecifier::bArg:
1407 case ConversionSpecifier::BArg:
1408 case ConversionSpecifier::cArg:
1409 case ConversionSpecifier::dArg:
1410 case ConversionSpecifier::iArg:
1411 case ConversionSpecifier::oArg:
1412 case ConversionSpecifier::uArg:
1413 case ConversionSpecifier::xArg:
1414 case ConversionSpecifier::XArg:
1415 case ConversionSpecifier::fArg:
1416 case ConversionSpecifier::FArg:
1417 case ConversionSpecifier::eArg:
1418 case ConversionSpecifier::EArg:
1419 case ConversionSpecifier::gArg:
1420 case ConversionSpecifier::GArg:
1421 case ConversionSpecifier::aArg:
1422 case ConversionSpecifier::AArg:
1423 case ConversionSpecifier::sArg:
1424 case ConversionSpecifier::pArg:
1425 case ConversionSpecifier::nArg:
1426 case ConversionSpecifier::ObjCObjArg:
1427 case ConversionSpecifier::ScanListArg:
1428 case ConversionSpecifier::PercentArg:
1429 case ConversionSpecifier::PArg:
1430 return true;
1431 case ConversionSpecifier::CArg:
1432 case ConversionSpecifier::SArg:
1433 return LangOpt.ObjC;
1434 case ConversionSpecifier::InvalidSpecifier:
1435 case ConversionSpecifier::FreeBSDbArg:
1436 case ConversionSpecifier::FreeBSDDArg:
1437 case ConversionSpecifier::FreeBSDrArg:
1438 case ConversionSpecifier::FreeBSDyArg:
1439 case ConversionSpecifier::PrintErrno:
1440 case ConversionSpecifier::DArg:
1441 case ConversionSpecifier::OArg:
1442 case ConversionSpecifier::UArg:
1443 case ConversionSpecifier::ZArg:
1444 return false;
1445 case ConversionSpecifier::rArg:
1446 case ConversionSpecifier::RArg:
1447 case ConversionSpecifier::kArg:
1448 case ConversionSpecifier::KArg:
1449 return LangOpt.FixedPoint;
1450 }
1451 llvm_unreachable("Invalid ConversionSpecifier Kind!");
1452}
1453
1454bool FormatSpecifier::hasStandardLengthConversionCombination() const {
1455 if (LM.getKind() == LengthModifier::AsLongDouble) {
1456 switch (CS.getKind()) {
1457 case ConversionSpecifier::dArg:
1458 case ConversionSpecifier::iArg:
1459 case ConversionSpecifier::oArg:
1460 case ConversionSpecifier::uArg:
1461 case ConversionSpecifier::xArg:
1462 case ConversionSpecifier::XArg:
1463 return false;
1464 default:
1465 return true;
1466 }
1467 }
1468 return true;
1469}
1470
1471std::optional<LengthModifier>
1472FormatSpecifier::getCorrectedLengthModifier() const {
1473 if (CS.isAnyIntArg() || CS.getKind() == ConversionSpecifier::nArg) {
1474 if (LM.getKind() == LengthModifier::AsLongDouble ||
1475 LM.getKind() == LengthModifier::AsQuad) {
1476 LengthModifier FixedLM(LM);
1477 FixedLM.setKind(LengthModifier::AsLongLong);
1478 return FixedLM;
1479 }
1480 }
1481
1482 return std::nullopt;
1483}
1484
1485bool FormatSpecifier::namedTypeToLengthModifier(ASTContext &Ctx, QualType QT,
1486 LengthModifier &LM) {
1487 if (LengthModifier::Kind Out = LengthModifier::Kind::None;
1488 namedTypeToLengthModifierKind(Ctx, QT, K&: Out)) {
1489 LM.setKind(Out);
1490 return true;
1491 }
1492 return false;
1493}
1494