1//== PrintfFormatString.cpp - Analysis of printf format strings --*- 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// Handling of format string in printf and friends. The structure of format
10// strings for fprintf() are described in C99 7.19.6.1.
11//
12//===----------------------------------------------------------------------===//
13
14#include "FormatStringParsing.h"
15#include "clang/AST/FormatString.h"
16#include "clang/AST/OSLog.h"
17#include "clang/Basic/TargetInfo.h"
18#include "llvm/Support/Regex.h"
19
20using clang::analyze_format_string::ArgType;
21using clang::analyze_format_string::ConversionSpecifier;
22using clang::analyze_format_string::FormatStringHandler;
23using clang::analyze_format_string::LengthModifier;
24using clang::analyze_format_string::OptionalAmount;
25using clang::analyze_printf::PrintfSpecifier;
26
27using namespace clang;
28
29typedef clang::analyze_format_string::SpecifierResult<PrintfSpecifier>
30 PrintfSpecifierResult;
31
32//===----------------------------------------------------------------------===//
33// Methods for parsing format strings.
34//===----------------------------------------------------------------------===//
35
36using analyze_format_string::ParseNonPositionAmount;
37
38static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS,
39 const char *Start, const char *&Beg, const char *E,
40 unsigned *argIndex) {
41 if (argIndex) {
42 FS.setPrecision(ParseNonPositionAmount(Beg, E, argIndex&: *argIndex));
43 } else {
44 const OptionalAmount Amt = ParsePositionAmount(
45 H, Start, Beg, E, p: analyze_format_string::PrecisionPos);
46 if (Amt.isInvalid())
47 return true;
48 FS.setPrecision(Amt);
49 }
50 return false;
51}
52
53static bool ParseObjCFlags(FormatStringHandler &H, PrintfSpecifier &FS,
54 const char *FlagBeg, const char *E, bool Warn) {
55 StringRef Flag(FlagBeg, E - FlagBeg);
56 // Currently there is only one flag.
57 if (Flag == "tt") {
58 FS.setHasObjCTechnicalTerm(FlagBeg);
59 return false;
60 }
61 // Handle either the case of no flag or an invalid flag.
62 if (Warn) {
63 if (Flag == "")
64 H.HandleEmptyObjCModifierFlag(startFlags: FlagBeg, flagsLen: E - FlagBeg);
65 else
66 H.HandleInvalidObjCModifierFlag(startFlag: FlagBeg, flagLen: E - FlagBeg);
67 }
68 return true;
69}
70
71static PrintfSpecifierResult
72ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
73 unsigned &argIndex, const LangOptions &LO,
74 const TargetInfo &Target, bool Warn,
75 bool isFreeBSDKPrintf) {
76
77 using namespace clang::analyze_format_string;
78 using namespace clang::analyze_printf;
79
80 const char *I = Beg;
81 const char *Start = nullptr;
82 UpdateOnReturn<const char *> UpdateBeg(Beg, I);
83
84 // Look for a '%' character that indicates the start of a format specifier.
85 for (; I != E; ++I) {
86 char c = *I;
87 if (c == '\0') {
88 // Detect spurious null characters, which are likely errors.
89 H.HandleNullChar(nullCharacter: I);
90 return true;
91 }
92 if (c == '%') {
93 Start = I++; // Record the start of the format specifier.
94 break;
95 }
96 }
97
98 // No format specifier found?
99 if (!Start)
100 return false;
101
102 if (I == E) {
103 // No more characters left?
104 if (Warn)
105 H.HandleIncompleteSpecifier(startSpecifier: Start, specifierLen: E - Start);
106 return true;
107 }
108
109 PrintfSpecifier FS;
110 if (ParseArgPosition(H, CS&: FS, Start, Beg&: I, E))
111 return true;
112
113 if (I == E) {
114 // No more characters left?
115 if (Warn)
116 H.HandleIncompleteSpecifier(startSpecifier: Start, specifierLen: E - Start);
117 return true;
118 }
119
120 if (*I == '{') {
121 ++I;
122 unsigned char PrivacyFlags = 0;
123 StringRef MatchedStr;
124
125 do {
126 StringRef Str(I, E - I);
127 std::string Match = "^[[:space:]]*"
128 "(private|public|sensitive|mask\\.[^[:space:],}]*)"
129 "[[:space:]]*(,|})";
130 llvm::Regex R(Match);
131 SmallVector<StringRef, 2> Matches;
132
133 if (R.match(String: Str, Matches: &Matches)) {
134 MatchedStr = Matches[1];
135 I += Matches[0].size();
136
137 // Set the privacy flag if the privacy annotation in the
138 // comma-delimited segment is at least as strict as the privacy
139 // annotations in previous comma-delimited segments.
140 if (MatchedStr.starts_with(Prefix: "mask")) {
141 StringRef MaskType = MatchedStr.substr(Start: sizeof("mask.") - 1);
142 unsigned Size = MaskType.size();
143 if (Warn && (Size == 0 || Size > 8))
144 H.handleInvalidMaskType(MaskType);
145 FS.setMaskType(MaskType);
146 } else if (MatchedStr == "sensitive")
147 PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsSensitive;
148 else if (PrivacyFlags !=
149 clang::analyze_os_log::OSLogBufferItem::IsSensitive &&
150 MatchedStr == "private")
151 PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPrivate;
152 else if (PrivacyFlags == 0 && MatchedStr == "public")
153 PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPublic;
154 } else {
155 size_t CommaOrBracePos =
156 Str.find_if(F: [](char c) { return c == ',' || c == '}'; });
157
158 if (CommaOrBracePos == StringRef::npos) {
159 // Neither a comma nor the closing brace was found.
160 if (Warn)
161 H.HandleIncompleteSpecifier(startSpecifier: Start, specifierLen: E - Start);
162 return true;
163 }
164
165 I += CommaOrBracePos + 1;
166 }
167 // Continue until the closing brace is found.
168 } while (*(I - 1) == ',');
169
170 // Set the privacy flag.
171 switch (PrivacyFlags) {
172 case 0:
173 break;
174 case clang::analyze_os_log::OSLogBufferItem::IsPrivate:
175 FS.setIsPrivate(MatchedStr.data());
176 break;
177 case clang::analyze_os_log::OSLogBufferItem::IsPublic:
178 FS.setIsPublic(MatchedStr.data());
179 break;
180 case clang::analyze_os_log::OSLogBufferItem::IsSensitive:
181 FS.setIsSensitive(MatchedStr.data());
182 break;
183 default:
184 llvm_unreachable("Unexpected privacy flag value");
185 }
186 }
187
188 // Look for flags (if any).
189 bool hasMore = true;
190 for (; I != E; ++I) {
191 switch (*I) {
192 default:
193 hasMore = false;
194 break;
195 case '\'':
196 // FIXME: POSIX specific. Always accept?
197 FS.setHasThousandsGrouping(I);
198 break;
199 case '-':
200 FS.setIsLeftJustified(I);
201 break;
202 case '+':
203 FS.setHasPlusPrefix(I);
204 break;
205 case ' ':
206 FS.setHasSpacePrefix(I);
207 break;
208 case '#':
209 FS.setHasAlternativeForm(I);
210 break;
211 case '0':
212 FS.setHasLeadingZeros(I);
213 break;
214 }
215 if (!hasMore)
216 break;
217 }
218
219 if (I == E) {
220 // No more characters left?
221 if (Warn)
222 H.HandleIncompleteSpecifier(startSpecifier: Start, specifierLen: E - Start);
223 return true;
224 }
225
226 // Look for the field width (if any).
227 if (ParseFieldWidth(H, CS&: FS, Start, Beg&: I, E,
228 argIndex: FS.usesPositionalArg() ? nullptr : &argIndex))
229 return true;
230
231 if (I == E) {
232 // No more characters left?
233 if (Warn)
234 H.HandleIncompleteSpecifier(startSpecifier: Start, specifierLen: E - Start);
235 return true;
236 }
237
238 // Look for the precision (if any).
239 if (*I == '.') {
240 ++I;
241 if (I == E) {
242 if (Warn)
243 H.HandleIncompleteSpecifier(startSpecifier: Start, specifierLen: E - Start);
244 return true;
245 }
246
247 if (ParsePrecision(H, FS, Start, Beg&: I, E,
248 argIndex: FS.usesPositionalArg() ? nullptr : &argIndex))
249 return true;
250
251 if (I == E) {
252 // No more characters left?
253 if (Warn)
254 H.HandleIncompleteSpecifier(startSpecifier: Start, specifierLen: E - Start);
255 return true;
256 }
257 }
258
259 if (ParseVectorModifier(H, FS, Beg&: I, E, LO))
260 return true;
261
262 // Look for the length modifier.
263 if (ParseLengthModifier(FS, Beg&: I, E, LO) && I == E) {
264 // No more characters left?
265 if (Warn)
266 H.HandleIncompleteSpecifier(startSpecifier: Start, specifierLen: E - Start);
267 return true;
268 }
269
270 // Look for the Objective-C modifier flags, if any.
271 // We parse these here, even if they don't apply to
272 // the conversion specifier, and then emit an error
273 // later if the conversion specifier isn't '@'. This
274 // enables better recovery, and we don't know if
275 // these flags are applicable until later.
276 const char *ObjCModifierFlagsStart = nullptr, *ObjCModifierFlagsEnd = nullptr;
277 if (*I == '[') {
278 ObjCModifierFlagsStart = I;
279 ++I;
280 auto flagStart = I;
281 for (;; ++I) {
282 ObjCModifierFlagsEnd = I;
283 if (I == E) {
284 if (Warn)
285 H.HandleIncompleteSpecifier(startSpecifier: Start, specifierLen: E - Start);
286 return true;
287 }
288 // Did we find the closing ']'?
289 if (*I == ']') {
290 if (ParseObjCFlags(H, FS, FlagBeg: flagStart, E: I, Warn))
291 return true;
292 ++I;
293 break;
294 }
295 // There are no separators defined yet for multiple
296 // Objective-C modifier flags. When those are
297 // defined, this is the place to check.
298 }
299 }
300
301 if (*I == '\0') {
302 // Detect spurious null characters, which are likely errors.
303 H.HandleNullChar(nullCharacter: I);
304 return true;
305 }
306
307 // Finally, look for the conversion specifier.
308 const char *conversionPosition = I++;
309 ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier;
310 switch (*conversionPosition) {
311 default:
312 break;
313 // C99: 7.19.6.1 (section 8).
314 case '%':
315 k = ConversionSpecifier::PercentArg;
316 break;
317 case 'A':
318 k = ConversionSpecifier::AArg;
319 break;
320 case 'E':
321 k = ConversionSpecifier::EArg;
322 break;
323 case 'F':
324 k = ConversionSpecifier::FArg;
325 break;
326 case 'G':
327 k = ConversionSpecifier::GArg;
328 break;
329 case 'X':
330 k = ConversionSpecifier::XArg;
331 break;
332 case 'a':
333 k = ConversionSpecifier::aArg;
334 break;
335 case 'c':
336 k = ConversionSpecifier::cArg;
337 break;
338 case 'd':
339 k = ConversionSpecifier::dArg;
340 break;
341 case 'e':
342 k = ConversionSpecifier::eArg;
343 break;
344 case 'f':
345 k = ConversionSpecifier::fArg;
346 break;
347 case 'g':
348 k = ConversionSpecifier::gArg;
349 break;
350 case 'i':
351 k = ConversionSpecifier::iArg;
352 break;
353 case 'n':
354 // Not handled, but reserved in OpenCL.
355 if (!LO.OpenCL)
356 k = ConversionSpecifier::nArg;
357 break;
358 case 'o':
359 k = ConversionSpecifier::oArg;
360 break;
361 case 'p':
362 k = ConversionSpecifier::pArg;
363 break;
364 case 's':
365 k = ConversionSpecifier::sArg;
366 break;
367 case 'u':
368 k = ConversionSpecifier::uArg;
369 break;
370 case 'x':
371 k = ConversionSpecifier::xArg;
372 break;
373 // C23.
374 case 'b':
375 if (isFreeBSDKPrintf)
376 k = ConversionSpecifier::FreeBSDbArg; // int followed by char *
377 else
378 k = ConversionSpecifier::bArg;
379 break;
380 case 'B':
381 k = ConversionSpecifier::BArg;
382 break;
383 // POSIX specific.
384 case 'C':
385 k = ConversionSpecifier::CArg;
386 break;
387 case 'S':
388 k = ConversionSpecifier::SArg;
389 break;
390 // Apple extension for os_log
391 case 'P':
392 k = ConversionSpecifier::PArg;
393 break;
394 // Objective-C.
395 case '@':
396 k = ConversionSpecifier::ObjCObjArg;
397 break;
398 // Glibc specific.
399 case 'm':
400 k = ConversionSpecifier::PrintErrno;
401 break;
402 case 'r':
403 if (isFreeBSDKPrintf)
404 k = ConversionSpecifier::FreeBSDrArg; // int
405 else if (LO.FixedPoint)
406 k = ConversionSpecifier::rArg;
407 break;
408 case 'y':
409 if (isFreeBSDKPrintf)
410 k = ConversionSpecifier::FreeBSDyArg; // int
411 break;
412 // Apple-specific.
413 case 'D':
414 if (isFreeBSDKPrintf)
415 k = ConversionSpecifier::FreeBSDDArg; // void * followed by char *
416 else if (Target.getTriple().isOSDarwin())
417 k = ConversionSpecifier::DArg;
418 break;
419 case 'O':
420 if (Target.getTriple().isOSDarwin())
421 k = ConversionSpecifier::OArg;
422 break;
423 case 'U':
424 if (Target.getTriple().isOSDarwin())
425 k = ConversionSpecifier::UArg;
426 break;
427 // MS specific.
428 case 'Z':
429 if (Target.getTriple().isOSMSVCRT())
430 k = ConversionSpecifier::ZArg;
431 break;
432 // ISO/IEC TR 18037 (fixed-point) specific.
433 // NOTE: 'r' is handled up above since FreeBSD also supports %r.
434 case 'k':
435 if (LO.FixedPoint)
436 k = ConversionSpecifier::kArg;
437 break;
438 case 'K':
439 if (LO.FixedPoint)
440 k = ConversionSpecifier::KArg;
441 break;
442 case 'R':
443 if (LO.FixedPoint)
444 k = ConversionSpecifier::RArg;
445 break;
446 }
447
448 // Check to see if we used the Objective-C modifier flags with
449 // a conversion specifier other than '@'.
450 if (k != ConversionSpecifier::ObjCObjArg &&
451 k != ConversionSpecifier::InvalidSpecifier && ObjCModifierFlagsStart) {
452 H.HandleObjCFlagsWithNonObjCConversion(
453 flagsStart: ObjCModifierFlagsStart, flagsEnd: ObjCModifierFlagsEnd + 1, conversionPosition);
454 return true;
455 }
456
457 PrintfConversionSpecifier CS(conversionPosition, k);
458 FS.setConversionSpecifier(CS);
459 if (CS.consumesDataArgument() && !FS.usesPositionalArg())
460 FS.setArgIndex(argIndex++);
461 // FreeBSD kernel specific.
462 if (k == ConversionSpecifier::FreeBSDbArg ||
463 k == ConversionSpecifier::FreeBSDDArg)
464 argIndex++;
465
466 if (k == ConversionSpecifier::InvalidSpecifier) {
467 unsigned Len = I - Start;
468 if (ParseUTF8InvalidSpecifier(SpecifierBegin: Start, FmtStrEnd: E, Len)) {
469 CS.setEndScanList(Start + Len);
470 FS.setConversionSpecifier(CS);
471 }
472 // Assume the conversion takes one argument.
473 return !H.HandleInvalidPrintfConversionSpecifier(FS, startSpecifier: Start, specifierLen: Len);
474 }
475 return PrintfSpecifierResult(Start, FS);
476}
477
478bool clang::analyze_format_string::ParsePrintfString(
479 FormatStringHandler &H, const char *I, const char *E, const LangOptions &LO,
480 const TargetInfo &Target, bool isFreeBSDKPrintf) {
481
482 unsigned argIndex = 0;
483
484 // Keep looking for a format specifier until we have exhausted the string.
485 while (I != E) {
486 const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(
487 H, Beg&: I, E, argIndex, LO, Target, Warn: true, isFreeBSDKPrintf);
488 // Did a fail-stop error of any kind occur when parsing the specifier?
489 // If so, don't do any more processing.
490 if (FSR.shouldStop())
491 return true;
492 // Did we exhaust the string or encounter an error that
493 // we can recover from?
494 if (!FSR.hasValue())
495 continue;
496 // We have a format specifier. Pass it to the callback.
497 if (!H.HandlePrintfSpecifier(FS: FSR.getValue(), startSpecifier: FSR.getStart(),
498 specifierLen: I - FSR.getStart(), Target))
499 return true;
500 }
501 assert(I == E && "Format string not exhausted");
502 return false;
503}
504
505bool clang::analyze_format_string::ParseFormatStringHasSArg(
506 const char *I, const char *E, const LangOptions &LO,
507 const TargetInfo &Target) {
508
509 unsigned argIndex = 0;
510
511 // Keep looking for a %s format specifier until we have exhausted the string.
512 FormatStringHandler H;
513 while (I != E) {
514 const PrintfSpecifierResult &FSR =
515 ParsePrintfSpecifier(H, Beg&: I, E, argIndex, LO, Target, Warn: false, isFreeBSDKPrintf: false);
516 // Did a fail-stop error of any kind occur when parsing the specifier?
517 // If so, don't do any more processing.
518 if (FSR.shouldStop())
519 return false;
520 // Did we exhaust the string or encounter an error that
521 // we can recover from?
522 if (!FSR.hasValue())
523 continue;
524 const analyze_printf::PrintfSpecifier &FS = FSR.getValue();
525 // Return true if this a %s format specifier.
526 if (FS.getConversionSpecifier().getKind() ==
527 ConversionSpecifier::Kind::sArg)
528 return true;
529 }
530 return false;
531}
532
533bool clang::analyze_format_string::parseFormatStringHasFormattingSpecifiers(
534 const char *Begin, const char *End, const LangOptions &LO,
535 const TargetInfo &Target) {
536 unsigned ArgIndex = 0;
537 // Keep looking for a formatting specifier until we have exhausted the string.
538 FormatStringHandler H;
539 while (Begin != End) {
540 const PrintfSpecifierResult &FSR =
541 ParsePrintfSpecifier(H, Beg&: Begin, E: End, argIndex&: ArgIndex, LO, Target, Warn: false, isFreeBSDKPrintf: false);
542 if (FSR.shouldStop())
543 break;
544 if (FSR.hasValue())
545 return true;
546 }
547 return false;
548}
549
550//===----------------------------------------------------------------------===//
551// Methods on PrintfSpecifier.
552//===----------------------------------------------------------------------===//
553
554ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx,
555 bool IsObjCLiteral) const {
556 if (CS.getKind() == ConversionSpecifier::cArg)
557 switch (LM.getKind()) {
558 case LengthModifier::None:
559 return Ctx.IntTy;
560 case LengthModifier::AsLong:
561 case LengthModifier::AsWide:
562 return ArgType(ArgType::WIntTy, "wint_t");
563 case LengthModifier::AsShort:
564 if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
565 return Ctx.IntTy;
566 [[fallthrough]];
567 default:
568 return ArgType::Invalid();
569 }
570
571 if (CS.isIntArg())
572 switch (LM.getKind()) {
573 case LengthModifier::AsLongDouble:
574 // GNU extension.
575 return Ctx.LongLongTy;
576 case LengthModifier::None:
577 case LengthModifier::AsShortLong:
578 return Ctx.IntTy;
579 case LengthModifier::AsInt32:
580 return ArgType(Ctx.IntTy, "__int32");
581 case LengthModifier::AsChar:
582 return ArgType::AnyCharTy;
583 case LengthModifier::AsShort:
584 return Ctx.ShortTy;
585 case LengthModifier::AsLong:
586 return Ctx.LongTy;
587 case LengthModifier::AsLongLong:
588 case LengthModifier::AsQuad:
589 return Ctx.LongLongTy;
590 case LengthModifier::AsInt64:
591 return ArgType(Ctx.LongLongTy, "__int64");
592 case LengthModifier::AsIntMax:
593 return ArgType(Ctx.getIntMaxType(), "intmax_t");
594 case LengthModifier::AsSizeT:
595 return ArgType::makeSizeT(
596 A: ArgType(Ctx.getSignedSizeType(), "signed size_t"));
597 case LengthModifier::AsInt3264:
598 return Ctx.getTargetInfo().getTriple().isArch64Bit()
599 ? ArgType(Ctx.LongLongTy, "__int64")
600 : ArgType(Ctx.IntTy, "__int32");
601 case LengthModifier::AsPtrDiff:
602 return ArgType::makePtrdiffT(
603 A: ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
604 case LengthModifier::AsIntN:
605 case LengthModifier::AsFastIntN:
606 return ArgType::makeIntNType(Ctx, LengthMod: LM,
607 Signed: CS.getKind() != ConversionSpecifier::bArg &&
608 CS.getKind() !=
609 ConversionSpecifier::BArg);
610 case LengthModifier::AsAllocate:
611 case LengthModifier::AsMAllocate:
612 case LengthModifier::AsWide:
613 case LengthModifier::AsDecimal32:
614 case LengthModifier::AsDecimal64:
615 case LengthModifier::AsDecimal128:
616 return ArgType::Invalid();
617 }
618
619 if (CS.isUIntArg())
620 switch (LM.getKind()) {
621 case LengthModifier::AsLongDouble:
622 // GNU extension.
623 return Ctx.UnsignedLongLongTy;
624 case LengthModifier::None:
625 case LengthModifier::AsShortLong:
626 return Ctx.UnsignedIntTy;
627 case LengthModifier::AsInt32:
628 return ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
629 case LengthModifier::AsChar:
630 return Ctx.UnsignedCharTy;
631 case LengthModifier::AsShort:
632 return Ctx.UnsignedShortTy;
633 case LengthModifier::AsLong:
634 return Ctx.UnsignedLongTy;
635 case LengthModifier::AsLongLong:
636 case LengthModifier::AsQuad:
637 return Ctx.UnsignedLongLongTy;
638 case LengthModifier::AsInt64:
639 return ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64");
640 case LengthModifier::AsIntMax:
641 return ArgType(Ctx.getUIntMaxType(), "uintmax_t");
642 case LengthModifier::AsSizeT:
643 return ArgType::makeSizeT(A: ArgType(Ctx.getSizeType(), "size_t"));
644 case LengthModifier::AsInt3264:
645 return Ctx.getTargetInfo().getTriple().isArch64Bit()
646 ? ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64")
647 : ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
648 case LengthModifier::AsPtrDiff:
649 return ArgType::makePtrdiffT(
650 A: ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t"));
651 case LengthModifier::AsIntN:
652 case LengthModifier::AsFastIntN:
653 return ArgType::makeIntNType(Ctx, LengthMod: LM, /*Signed=*/false);
654 case LengthModifier::AsAllocate:
655 case LengthModifier::AsMAllocate:
656 case LengthModifier::AsWide:
657 case LengthModifier::AsDecimal32:
658 case LengthModifier::AsDecimal64:
659 case LengthModifier::AsDecimal128:
660 return ArgType::Invalid();
661 }
662
663 if (CS.isDoubleArg()) {
664 if (!VectorNumElts.isInvalid()) {
665 switch (LM.getKind()) {
666 case LengthModifier::AsShort:
667 return Ctx.HalfTy;
668 case LengthModifier::AsShortLong:
669 return Ctx.FloatTy;
670 case LengthModifier::AsLong:
671 default:
672 return Ctx.DoubleTy;
673 }
674 }
675
676 switch (LM.getKind()) {
677 case LengthModifier::AsLongDouble:
678 return Ctx.LongDoubleTy;
679 case LengthModifier::AsDecimal32:
680 return ArgType::Unsupported(N: "_Decimal32");
681 case LengthModifier::AsDecimal64:
682 return ArgType::Unsupported(N: "_Decimal64");
683 case LengthModifier::AsDecimal128:
684 return ArgType::Unsupported(N: "_Decimal128");
685 default:
686 return Ctx.DoubleTy;
687 }
688 }
689
690 if (CS.getKind() == ConversionSpecifier::nArg) {
691 switch (LM.getKind()) {
692 case LengthModifier::None:
693 return ArgType::PtrTo(A: Ctx.IntTy);
694 case LengthModifier::AsChar:
695 return ArgType::PtrTo(A: Ctx.SignedCharTy);
696 case LengthModifier::AsShort:
697 return ArgType::PtrTo(A: Ctx.ShortTy);
698 case LengthModifier::AsLong:
699 return ArgType::PtrTo(A: Ctx.LongTy);
700 case LengthModifier::AsLongLong:
701 case LengthModifier::AsQuad:
702 return ArgType::PtrTo(A: Ctx.LongLongTy);
703 case LengthModifier::AsIntMax:
704 return ArgType::PtrTo(A: ArgType(Ctx.getIntMaxType(), "intmax_t"));
705 case LengthModifier::AsSizeT:
706 return ArgType::PtrTo(A: ArgType::makeSizeT(
707 A: ArgType(Ctx.getSignedSizeType(), "signed size_t")));
708 case LengthModifier::AsPtrDiff:
709 return ArgType::PtrTo(A: ArgType::makePtrdiffT(
710 A: ArgType(Ctx.getPointerDiffType(), "ptrdiff_t")));
711 case LengthModifier::AsIntN:
712 case LengthModifier::AsFastIntN:
713 return ArgType::PtrTo(A: ArgType::makeIntNType(Ctx, LengthMod: LM, /*Signed=*/true));
714 case LengthModifier::AsLongDouble:
715 return ArgType(); // FIXME: Is this a known extension?
716 case LengthModifier::AsAllocate:
717 case LengthModifier::AsMAllocate:
718 case LengthModifier::AsInt32:
719 case LengthModifier::AsInt3264:
720 case LengthModifier::AsInt64:
721 case LengthModifier::AsWide:
722 case LengthModifier::AsDecimal32:
723 case LengthModifier::AsDecimal64:
724 case LengthModifier::AsDecimal128:
725 return ArgType::Invalid();
726 case LengthModifier::AsShortLong:
727 llvm_unreachable("only used for OpenCL which doesn not handle nArg");
728 }
729 }
730
731 if (CS.isFixedPointArg() && !Ctx.getLangOpts().FixedPoint)
732 return ArgType::Invalid();
733
734 switch (CS.getKind()) {
735 case ConversionSpecifier::sArg:
736 if (LM.getKind() == LengthModifier::AsWideChar) {
737 if (IsObjCLiteral)
738 return ArgType(Ctx.getPointerType(T: Ctx.UnsignedShortTy.withConst()),
739 "const unichar *");
740 return ArgType(ArgType::WCStrTy, "wchar_t *");
741 }
742 if (LM.getKind() == LengthModifier::AsWide)
743 return ArgType(ArgType::WCStrTy, "wchar_t *");
744 return ArgType::CStrTy;
745 case ConversionSpecifier::SArg:
746 if (IsObjCLiteral)
747 return ArgType(Ctx.getPointerType(T: Ctx.UnsignedShortTy.withConst()),
748 "const unichar *");
749 if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&
750 LM.getKind() == LengthModifier::AsShort)
751 return ArgType::CStrTy;
752 return ArgType(ArgType::WCStrTy, "wchar_t *");
753 case ConversionSpecifier::CArg:
754 if (IsObjCLiteral)
755 return ArgType(Ctx.UnsignedShortTy, "unichar");
756 if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&
757 LM.getKind() == LengthModifier::AsShort)
758 return Ctx.IntTy;
759 return ArgType(Ctx.WideCharTy, "wchar_t");
760 case ConversionSpecifier::pArg:
761 case ConversionSpecifier::PArg:
762 return ArgType::CPointerTy;
763 case ConversionSpecifier::ObjCObjArg:
764 return ArgType::ObjCPointerTy;
765 case ConversionSpecifier::kArg:
766 switch (LM.getKind()) {
767 case LengthModifier::None:
768 return Ctx.AccumTy;
769 case LengthModifier::AsShort:
770 return Ctx.ShortAccumTy;
771 case LengthModifier::AsLong:
772 return Ctx.LongAccumTy;
773 default:
774 return ArgType::Invalid();
775 }
776 case ConversionSpecifier::KArg:
777 switch (LM.getKind()) {
778 case LengthModifier::None:
779 return Ctx.UnsignedAccumTy;
780 case LengthModifier::AsShort:
781 return Ctx.UnsignedShortAccumTy;
782 case LengthModifier::AsLong:
783 return Ctx.UnsignedLongAccumTy;
784 default:
785 return ArgType::Invalid();
786 }
787 case ConversionSpecifier::rArg:
788 switch (LM.getKind()) {
789 case LengthModifier::None:
790 return Ctx.FractTy;
791 case LengthModifier::AsShort:
792 return Ctx.ShortFractTy;
793 case LengthModifier::AsLong:
794 return Ctx.LongFractTy;
795 default:
796 return ArgType::Invalid();
797 }
798 case ConversionSpecifier::RArg:
799 switch (LM.getKind()) {
800 case LengthModifier::None:
801 return Ctx.UnsignedFractTy;
802 case LengthModifier::AsShort:
803 return Ctx.UnsignedShortFractTy;
804 case LengthModifier::AsLong:
805 return Ctx.UnsignedLongFractTy;
806 default:
807 return ArgType::Invalid();
808 }
809 default:
810 break;
811 }
812
813 // FIXME: Handle other cases.
814 return ArgType();
815}
816
817ArgType PrintfSpecifier::getArgType(ASTContext &Ctx, bool IsObjCLiteral) const {
818 const PrintfConversionSpecifier &CS = getConversionSpecifier();
819
820 if (!CS.consumesDataArgument())
821 return ArgType::Invalid();
822
823 ArgType ScalarTy = getScalarArgType(Ctx, IsObjCLiteral);
824 if (!ScalarTy.isValid() || VectorNumElts.isInvalid())
825 return ScalarTy;
826
827 return ScalarTy.makeVectorType(C&: Ctx, NumElts: VectorNumElts.getConstantAmount());
828}
829
830bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
831 ASTContext &Ctx, bool IsObjCLiteral) {
832 // %n is different from other conversion specifiers; don't try to fix it.
833 if (CS.getKind() == ConversionSpecifier::nArg)
834 return false;
835
836 // Handle Objective-C objects first. Note that while the '%@' specifier will
837 // not warn for structure pointer or void pointer arguments (because that's
838 // how CoreFoundation objects are implemented), we only show a fixit for '%@'
839 // if we know it's an object (block, id, class, or __attribute__((NSObject))).
840 if (QT->isObjCRetainableType()) {
841 if (!IsObjCLiteral)
842 return false;
843
844 CS.setKind(ConversionSpecifier::ObjCObjArg);
845
846 // Disable irrelevant flags
847 HasThousandsGrouping = false;
848 HasPlusPrefix = false;
849 HasSpacePrefix = false;
850 HasAlternativeForm = false;
851 HasLeadingZeroes = false;
852 Precision.setHowSpecified(OptionalAmount::NotSpecified);
853 LM.setKind(LengthModifier::None);
854
855 return true;
856 }
857
858 // Handle strings next (char *, wchar_t *)
859 if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) {
860 CS.setKind(ConversionSpecifier::sArg);
861
862 // Disable irrelevant flags
863 HasAlternativeForm = false;
864 HasLeadingZeroes = false;
865
866 // Set the long length modifier for wide characters
867 if (QT->getPointeeType()->isWideCharType())
868 LM.setKind(LengthModifier::AsWideChar);
869 else
870 LM.setKind(LengthModifier::None);
871
872 return true;
873 }
874
875 // If it's an enum, get its underlying type.
876 if (const auto *ED = QT->getAsEnumDecl())
877 QT = ED->getIntegerType();
878
879 const BuiltinType *BT = QT->getAs<BuiltinType>();
880 if (!BT) {
881 const VectorType *VT = QT->getAs<VectorType>();
882 if (VT) {
883 QT = VT->getElementType();
884 BT = QT->getAs<BuiltinType>();
885 VectorNumElts = OptionalAmount(VT->getNumElements());
886 }
887 }
888
889 // We can only work with builtin types.
890 if (!BT)
891 return false;
892
893 // Set length modifier
894 switch (BT->getKind()) {
895 case BuiltinType::Bool:
896 case BuiltinType::WChar_U:
897 case BuiltinType::WChar_S:
898 case BuiltinType::Char8: // FIXME: Treat like 'char'?
899 case BuiltinType::Char16:
900 case BuiltinType::Char32:
901 case BuiltinType::UInt128:
902 case BuiltinType::Int128:
903 case BuiltinType::Half:
904 case BuiltinType::BFloat16:
905 case BuiltinType::Float16:
906 case BuiltinType::Float128:
907 case BuiltinType::Ibm128:
908 case BuiltinType::ShortAccum:
909 case BuiltinType::Accum:
910 case BuiltinType::LongAccum:
911 case BuiltinType::UShortAccum:
912 case BuiltinType::UAccum:
913 case BuiltinType::ULongAccum:
914 case BuiltinType::ShortFract:
915 case BuiltinType::Fract:
916 case BuiltinType::LongFract:
917 case BuiltinType::UShortFract:
918 case BuiltinType::UFract:
919 case BuiltinType::ULongFract:
920 case BuiltinType::SatShortAccum:
921 case BuiltinType::SatAccum:
922 case BuiltinType::SatLongAccum:
923 case BuiltinType::SatUShortAccum:
924 case BuiltinType::SatUAccum:
925 case BuiltinType::SatULongAccum:
926 case BuiltinType::SatShortFract:
927 case BuiltinType::SatFract:
928 case BuiltinType::SatLongFract:
929 case BuiltinType::SatUShortFract:
930 case BuiltinType::SatUFract:
931 case BuiltinType::SatULongFract:
932 // Various types which are non-trivial to correct.
933 return false;
934
935#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
936 case BuiltinType::Id:
937#include "clang/Basic/OpenCLImageTypes.def"
938
939#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) case BuiltinType::Id:
940#include "clang/Basic/OpenCLExtensionTypes.def"
941
942#define SVE_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
943#include "clang/Basic/AArch64ACLETypes.def"
944
945#define PPC_VECTOR_TYPE(Name, Id, Size) case BuiltinType::Id:
946#include "clang/Basic/PPCTypes.def"
947
948#define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
949#include "clang/Basic/RISCVVTypes.def"
950
951#define WASM_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
952#include "clang/Basic/WebAssemblyReferenceTypes.def"
953
954#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) case BuiltinType::Id:
955#include "clang/Basic/AMDGPUTypes.def"
956
957#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
958#include "clang/Basic/HLSLIntangibleTypes.def"
959
960#define SIGNED_TYPE(Id, SingletonId)
961#define UNSIGNED_TYPE(Id, SingletonId)
962#define FLOATING_TYPE(Id, SingletonId)
963#define BUILTIN_TYPE(Id, SingletonId) case BuiltinType::Id:
964#include "clang/AST/BuiltinTypes.def"
965
966 // Misc other stuff which doesn't make sense here.
967 return false;
968
969 case BuiltinType::UInt:
970 case BuiltinType::Int:
971 case BuiltinType::Float:
972 LM.setKind(VectorNumElts.isInvalid() ? LengthModifier::None
973 : LengthModifier::AsShortLong);
974 break;
975 case BuiltinType::Double:
976 LM.setKind(VectorNumElts.isInvalid() ? LengthModifier::None
977 : LengthModifier::AsLong);
978 break;
979 case BuiltinType::Char_U:
980 case BuiltinType::UChar:
981 case BuiltinType::Char_S:
982 case BuiltinType::SChar:
983 LM.setKind(LengthModifier::AsChar);
984 break;
985
986 case BuiltinType::Short:
987 case BuiltinType::UShort:
988 LM.setKind(LengthModifier::AsShort);
989 break;
990
991 case BuiltinType::Long:
992 case BuiltinType::ULong:
993 LM.setKind(LengthModifier::AsLong);
994 break;
995
996 case BuiltinType::LongLong:
997 case BuiltinType::ULongLong:
998 LM.setKind(LengthModifier::AsLongLong);
999 break;
1000
1001 case BuiltinType::LongDouble:
1002 LM.setKind(LengthModifier::AsLongDouble);
1003 break;
1004 }
1005
1006 // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
1007 if (LangOpt.C99 || LangOpt.CPlusPlus11)
1008 namedTypeToLengthModifier(Ctx, QT, LM);
1009
1010 // If fixing the length modifier was enough, we might be done.
1011 if (hasValidLengthModifier(Target: Ctx.getTargetInfo(), LO: LangOpt)) {
1012 // If we're going to offer a fix anyway, make sure the sign matches.
1013 switch (CS.getKind()) {
1014 case ConversionSpecifier::uArg:
1015 case ConversionSpecifier::UArg:
1016 if (QT->isSignedIntegerType())
1017 CS.setKind(clang::analyze_format_string::ConversionSpecifier::dArg);
1018 break;
1019 case ConversionSpecifier::dArg:
1020 case ConversionSpecifier::DArg:
1021 case ConversionSpecifier::iArg:
1022 if (QT->isUnsignedIntegerType() && !HasPlusPrefix)
1023 CS.setKind(clang::analyze_format_string::ConversionSpecifier::uArg);
1024 break;
1025 default:
1026 // Other specifiers do not have signed/unsigned variants.
1027 break;
1028 }
1029
1030 const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral);
1031 if (ATR.isValid() && ATR.matchesType(C&: Ctx, argTy: QT))
1032 return true;
1033 }
1034
1035 // Set conversion specifier and disable any flags which do not apply to it.
1036 // Let typedefs to char fall through to int, as %c is silly for uint8_t.
1037 if (!QT->getAs<TypedefType>() && QT->isCharType()) {
1038 CS.setKind(ConversionSpecifier::cArg);
1039 LM.setKind(LengthModifier::None);
1040 Precision.setHowSpecified(OptionalAmount::NotSpecified);
1041 HasAlternativeForm = false;
1042 HasLeadingZeroes = false;
1043 HasPlusPrefix = false;
1044 }
1045 // Test for Floating type first as LongDouble can pass isUnsignedIntegerType
1046 else if (QT->isRealFloatingType()) {
1047 CS.setKind(ConversionSpecifier::fArg);
1048 } else if (QT->isSignedIntegerType()) {
1049 CS.setKind(ConversionSpecifier::dArg);
1050 HasAlternativeForm = false;
1051 } else if (QT->isUnsignedIntegerType()) {
1052 CS.setKind(ConversionSpecifier::uArg);
1053 HasAlternativeForm = false;
1054 HasPlusPrefix = false;
1055 } else {
1056 llvm_unreachable("Unexpected type");
1057 }
1058
1059 return true;
1060}
1061
1062void PrintfSpecifier::toString(raw_ostream &os) const {
1063 // Whilst some features have no defined order, we are using the order
1064 // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1)
1065 os << "%";
1066
1067 // Positional args
1068 if (usesPositionalArg()) {
1069 os << getPositionalArgIndex() << "$";
1070 }
1071
1072 // Conversion flags
1073 if (IsLeftJustified)
1074 os << "-";
1075 if (HasPlusPrefix)
1076 os << "+";
1077 if (HasSpacePrefix)
1078 os << " ";
1079 if (HasAlternativeForm)
1080 os << "#";
1081 if (HasLeadingZeroes)
1082 os << "0";
1083
1084 // Minimum field width
1085 FieldWidth.toString(os);
1086 // Precision
1087 Precision.toString(os);
1088
1089 // Vector modifier
1090 if (!VectorNumElts.isInvalid())
1091 os << 'v' << VectorNumElts.getConstantAmount();
1092
1093 // Length modifier
1094 os << LM.toString();
1095 // Conversion specifier
1096 os << CS.toString();
1097}
1098
1099bool PrintfSpecifier::hasValidPlusPrefix() const {
1100 if (!HasPlusPrefix)
1101 return true;
1102
1103 // The plus prefix only makes sense for signed conversions
1104 switch (CS.getKind()) {
1105 case ConversionSpecifier::dArg:
1106 case ConversionSpecifier::DArg:
1107 case ConversionSpecifier::iArg:
1108 case ConversionSpecifier::fArg:
1109 case ConversionSpecifier::FArg:
1110 case ConversionSpecifier::eArg:
1111 case ConversionSpecifier::EArg:
1112 case ConversionSpecifier::gArg:
1113 case ConversionSpecifier::GArg:
1114 case ConversionSpecifier::aArg:
1115 case ConversionSpecifier::AArg:
1116 case ConversionSpecifier::FreeBSDrArg:
1117 case ConversionSpecifier::FreeBSDyArg:
1118 case ConversionSpecifier::rArg:
1119 case ConversionSpecifier::kArg:
1120 return true;
1121
1122 default:
1123 return false;
1124 }
1125}
1126
1127bool PrintfSpecifier::hasValidAlternativeForm() const {
1128 if (!HasAlternativeForm)
1129 return true;
1130
1131 // Alternate form flag only valid with the bBoxXaAeEfFgGrRkK conversions
1132 switch (CS.getKind()) {
1133 case ConversionSpecifier::bArg:
1134 case ConversionSpecifier::BArg:
1135 case ConversionSpecifier::oArg:
1136 case ConversionSpecifier::OArg:
1137 case ConversionSpecifier::xArg:
1138 case ConversionSpecifier::XArg:
1139 case ConversionSpecifier::aArg:
1140 case ConversionSpecifier::AArg:
1141 case ConversionSpecifier::eArg:
1142 case ConversionSpecifier::EArg:
1143 case ConversionSpecifier::fArg:
1144 case ConversionSpecifier::FArg:
1145 case ConversionSpecifier::gArg:
1146 case ConversionSpecifier::GArg:
1147 case ConversionSpecifier::FreeBSDrArg:
1148 case ConversionSpecifier::FreeBSDyArg:
1149 case ConversionSpecifier::rArg:
1150 case ConversionSpecifier::RArg:
1151 case ConversionSpecifier::kArg:
1152 case ConversionSpecifier::KArg:
1153 return true;
1154
1155 default:
1156 return false;
1157 }
1158}
1159
1160bool PrintfSpecifier::hasValidLeadingZeros() const {
1161 if (!HasLeadingZeroes)
1162 return true;
1163
1164 // Leading zeroes flag only valid with the bBdiouxXaAeEfFgGrRkK conversions
1165 switch (CS.getKind()) {
1166 case ConversionSpecifier::bArg:
1167 case ConversionSpecifier::BArg:
1168 case ConversionSpecifier::dArg:
1169 case ConversionSpecifier::DArg:
1170 case ConversionSpecifier::iArg:
1171 case ConversionSpecifier::oArg:
1172 case ConversionSpecifier::OArg:
1173 case ConversionSpecifier::uArg:
1174 case ConversionSpecifier::UArg:
1175 case ConversionSpecifier::xArg:
1176 case ConversionSpecifier::XArg:
1177 case ConversionSpecifier::aArg:
1178 case ConversionSpecifier::AArg:
1179 case ConversionSpecifier::eArg:
1180 case ConversionSpecifier::EArg:
1181 case ConversionSpecifier::fArg:
1182 case ConversionSpecifier::FArg:
1183 case ConversionSpecifier::gArg:
1184 case ConversionSpecifier::GArg:
1185 case ConversionSpecifier::FreeBSDrArg:
1186 case ConversionSpecifier::FreeBSDyArg:
1187 case ConversionSpecifier::rArg:
1188 case ConversionSpecifier::RArg:
1189 case ConversionSpecifier::kArg:
1190 case ConversionSpecifier::KArg:
1191 return true;
1192
1193 default:
1194 return false;
1195 }
1196}
1197
1198bool PrintfSpecifier::hasValidSpacePrefix() const {
1199 if (!HasSpacePrefix)
1200 return true;
1201
1202 // The space prefix only makes sense for signed conversions
1203 switch (CS.getKind()) {
1204 case ConversionSpecifier::dArg:
1205 case ConversionSpecifier::DArg:
1206 case ConversionSpecifier::iArg:
1207 case ConversionSpecifier::fArg:
1208 case ConversionSpecifier::FArg:
1209 case ConversionSpecifier::eArg:
1210 case ConversionSpecifier::EArg:
1211 case ConversionSpecifier::gArg:
1212 case ConversionSpecifier::GArg:
1213 case ConversionSpecifier::aArg:
1214 case ConversionSpecifier::AArg:
1215 case ConversionSpecifier::FreeBSDrArg:
1216 case ConversionSpecifier::FreeBSDyArg:
1217 case ConversionSpecifier::rArg:
1218 case ConversionSpecifier::kArg:
1219 return true;
1220
1221 default:
1222 return false;
1223 }
1224}
1225
1226bool PrintfSpecifier::hasValidLeftJustified() const {
1227 if (!IsLeftJustified)
1228 return true;
1229
1230 // The left justified flag is valid for all conversions except n
1231 switch (CS.getKind()) {
1232 case ConversionSpecifier::nArg:
1233 return false;
1234
1235 default:
1236 return true;
1237 }
1238}
1239
1240bool PrintfSpecifier::hasValidThousandsGroupingPrefix() const {
1241 if (!HasThousandsGrouping)
1242 return true;
1243
1244 switch (CS.getKind()) {
1245 case ConversionSpecifier::dArg:
1246 case ConversionSpecifier::DArg:
1247 case ConversionSpecifier::iArg:
1248 case ConversionSpecifier::uArg:
1249 case ConversionSpecifier::UArg:
1250 case ConversionSpecifier::fArg:
1251 case ConversionSpecifier::FArg:
1252 case ConversionSpecifier::gArg:
1253 case ConversionSpecifier::GArg:
1254 return true;
1255 default:
1256 return false;
1257 }
1258}
1259
1260bool PrintfSpecifier::hasValidPrecision() const {
1261 if (Precision.getHowSpecified() == OptionalAmount::NotSpecified)
1262 return true;
1263
1264 // Precision is only valid with the bBdiouxXaAeEfFgGsPrRkK conversions
1265 switch (CS.getKind()) {
1266 case ConversionSpecifier::bArg:
1267 case ConversionSpecifier::BArg:
1268 case ConversionSpecifier::dArg:
1269 case ConversionSpecifier::DArg:
1270 case ConversionSpecifier::iArg:
1271 case ConversionSpecifier::oArg:
1272 case ConversionSpecifier::OArg:
1273 case ConversionSpecifier::uArg:
1274 case ConversionSpecifier::UArg:
1275 case ConversionSpecifier::xArg:
1276 case ConversionSpecifier::XArg:
1277 case ConversionSpecifier::aArg:
1278 case ConversionSpecifier::AArg:
1279 case ConversionSpecifier::eArg:
1280 case ConversionSpecifier::EArg:
1281 case ConversionSpecifier::fArg:
1282 case ConversionSpecifier::FArg:
1283 case ConversionSpecifier::gArg:
1284 case ConversionSpecifier::GArg:
1285 case ConversionSpecifier::sArg:
1286 case ConversionSpecifier::FreeBSDrArg:
1287 case ConversionSpecifier::FreeBSDyArg:
1288 case ConversionSpecifier::PArg:
1289 case ConversionSpecifier::rArg:
1290 case ConversionSpecifier::RArg:
1291 case ConversionSpecifier::kArg:
1292 case ConversionSpecifier::KArg:
1293 return true;
1294
1295 default:
1296 return false;
1297 }
1298}
1299bool PrintfSpecifier::hasValidFieldWidth() const {
1300 if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified)
1301 return true;
1302
1303 // The field width is valid for all conversions except n
1304 switch (CS.getKind()) {
1305 case ConversionSpecifier::nArg:
1306 return false;
1307
1308 default:
1309 return true;
1310 }
1311}
1312