xref: /llvm-project/clang/lib/AST/FormatString.cpp (revision 0e24686af49d2f9e50438d3a27db6f1ade594855)
1314fbfa1STim Northover // FormatString.cpp - Common stuff for handling printf/scanf formats -*- C++ -*-
2314fbfa1STim Northover //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6314fbfa1STim Northover //
7314fbfa1STim Northover //===----------------------------------------------------------------------===//
8314fbfa1STim Northover //
9314fbfa1STim Northover // Shared details for processing format strings of printf and scanf
10314fbfa1STim Northover // (and friends).
11314fbfa1STim Northover //
12314fbfa1STim Northover //===----------------------------------------------------------------------===//
13314fbfa1STim Northover 
14314fbfa1STim Northover #include "FormatStringParsing.h"
15314fbfa1STim Northover #include "clang/Basic/LangOptions.h"
16314fbfa1STim Northover #include "clang/Basic/TargetInfo.h"
17314fbfa1STim Northover #include "llvm/Support/ConvertUTF.h"
18a1580d7bSKazu Hirata #include <optional>
19314fbfa1STim Northover 
20314fbfa1STim Northover using clang::analyze_format_string::ArgType;
21314fbfa1STim Northover using clang::analyze_format_string::FormatStringHandler;
22314fbfa1STim Northover using clang::analyze_format_string::FormatSpecifier;
23314fbfa1STim Northover using clang::analyze_format_string::LengthModifier;
24314fbfa1STim Northover using clang::analyze_format_string::OptionalAmount;
25314fbfa1STim Northover using clang::analyze_format_string::ConversionSpecifier;
26314fbfa1STim Northover using namespace clang;
27314fbfa1STim Northover 
28314fbfa1STim Northover // Key function to FormatStringHandler.
29314fbfa1STim Northover FormatStringHandler::~FormatStringHandler() {}
30314fbfa1STim Northover 
31314fbfa1STim Northover //===----------------------------------------------------------------------===//
32314fbfa1STim Northover // Functions for parsing format strings components in both printf and
33314fbfa1STim Northover // scanf format strings.
34314fbfa1STim Northover //===----------------------------------------------------------------------===//
35314fbfa1STim Northover 
36314fbfa1STim Northover OptionalAmount
37314fbfa1STim Northover clang::analyze_format_string::ParseAmount(const char *&Beg, const char *E) {
38314fbfa1STim Northover   const char *I = Beg;
39314fbfa1STim Northover   UpdateOnReturn <const char*> UpdateBeg(Beg, I);
40314fbfa1STim Northover 
41314fbfa1STim Northover   unsigned accumulator = 0;
42314fbfa1STim Northover   bool hasDigits = false;
43314fbfa1STim Northover 
44314fbfa1STim Northover   for ( ; I != E; ++I) {
45314fbfa1STim Northover     char c = *I;
46314fbfa1STim Northover     if (c >= '0' && c <= '9') {
47314fbfa1STim Northover       hasDigits = true;
48314fbfa1STim Northover       accumulator = (accumulator * 10) + (c - '0');
49314fbfa1STim Northover       continue;
50314fbfa1STim Northover     }
51314fbfa1STim Northover 
52314fbfa1STim Northover     if (hasDigits)
53314fbfa1STim Northover       return OptionalAmount(OptionalAmount::Constant, accumulator, Beg, I - Beg,
54314fbfa1STim Northover           false);
55314fbfa1STim Northover 
56314fbfa1STim Northover     break;
57314fbfa1STim Northover   }
58314fbfa1STim Northover 
59314fbfa1STim Northover   return OptionalAmount();
60314fbfa1STim Northover }
61314fbfa1STim Northover 
62314fbfa1STim Northover OptionalAmount
63314fbfa1STim Northover clang::analyze_format_string::ParseNonPositionAmount(const char *&Beg,
64314fbfa1STim Northover                                                      const char *E,
65314fbfa1STim Northover                                                      unsigned &argIndex) {
66314fbfa1STim Northover   if (*Beg == '*') {
67314fbfa1STim Northover     ++Beg;
68314fbfa1STim Northover     return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg, 0, false);
69314fbfa1STim Northover   }
70314fbfa1STim Northover 
71314fbfa1STim Northover   return ParseAmount(Beg, E);
72314fbfa1STim Northover }
73314fbfa1STim Northover 
74314fbfa1STim Northover OptionalAmount
75314fbfa1STim Northover clang::analyze_format_string::ParsePositionAmount(FormatStringHandler &H,
76314fbfa1STim Northover                                                   const char *Start,
77314fbfa1STim Northover                                                   const char *&Beg,
78314fbfa1STim Northover                                                   const char *E,
79314fbfa1STim Northover                                                   PositionContext p) {
80314fbfa1STim Northover   if (*Beg == '*') {
81314fbfa1STim Northover     const char *I = Beg + 1;
82314fbfa1STim Northover     const OptionalAmount &Amt = ParseAmount(I, E);
83314fbfa1STim Northover 
84314fbfa1STim Northover     if (Amt.getHowSpecified() == OptionalAmount::NotSpecified) {
85314fbfa1STim Northover       H.HandleInvalidPosition(Beg, I - Beg, p);
86314fbfa1STim Northover       return OptionalAmount(false);
87314fbfa1STim Northover     }
88314fbfa1STim Northover 
89314fbfa1STim Northover     if (I == E) {
90314fbfa1STim Northover       // No more characters left?
91314fbfa1STim Northover       H.HandleIncompleteSpecifier(Start, E - Start);
92314fbfa1STim Northover       return OptionalAmount(false);
93314fbfa1STim Northover     }
94314fbfa1STim Northover 
95314fbfa1STim Northover     assert(Amt.getHowSpecified() == OptionalAmount::Constant);
96314fbfa1STim Northover 
97314fbfa1STim Northover     if (*I == '$') {
98314fbfa1STim Northover       // Handle positional arguments
99314fbfa1STim Northover 
100314fbfa1STim Northover       // Special case: '*0$', since this is an easy mistake.
101314fbfa1STim Northover       if (Amt.getConstantAmount() == 0) {
102314fbfa1STim Northover         H.HandleZeroPosition(Beg, I - Beg + 1);
103314fbfa1STim Northover         return OptionalAmount(false);
104314fbfa1STim Northover       }
105314fbfa1STim Northover 
106314fbfa1STim Northover       const char *Tmp = Beg;
107314fbfa1STim Northover       Beg = ++I;
108314fbfa1STim Northover 
109314fbfa1STim Northover       return OptionalAmount(OptionalAmount::Arg, Amt.getConstantAmount() - 1,
110314fbfa1STim Northover                             Tmp, 0, true);
111314fbfa1STim Northover     }
112314fbfa1STim Northover 
113314fbfa1STim Northover     H.HandleInvalidPosition(Beg, I - Beg, p);
114314fbfa1STim Northover     return OptionalAmount(false);
115314fbfa1STim Northover   }
116314fbfa1STim Northover 
117314fbfa1STim Northover   return ParseAmount(Beg, E);
118314fbfa1STim Northover }
119314fbfa1STim Northover 
120314fbfa1STim Northover 
121314fbfa1STim Northover bool
122314fbfa1STim Northover clang::analyze_format_string::ParseFieldWidth(FormatStringHandler &H,
123314fbfa1STim Northover                                               FormatSpecifier &CS,
124314fbfa1STim Northover                                               const char *Start,
125314fbfa1STim Northover                                               const char *&Beg, const char *E,
126314fbfa1STim Northover                                               unsigned *argIndex) {
127314fbfa1STim Northover   // FIXME: Support negative field widths.
128314fbfa1STim Northover   if (argIndex) {
129314fbfa1STim Northover     CS.setFieldWidth(ParseNonPositionAmount(Beg, E, *argIndex));
130314fbfa1STim Northover   }
131314fbfa1STim Northover   else {
132314fbfa1STim Northover     const OptionalAmount Amt =
133314fbfa1STim Northover       ParsePositionAmount(H, Start, Beg, E,
134314fbfa1STim Northover                           analyze_format_string::FieldWidthPos);
135314fbfa1STim Northover 
136314fbfa1STim Northover     if (Amt.isInvalid())
137314fbfa1STim Northover       return true;
138314fbfa1STim Northover     CS.setFieldWidth(Amt);
139314fbfa1STim Northover   }
140314fbfa1STim Northover   return false;
141314fbfa1STim Northover }
142314fbfa1STim Northover 
143314fbfa1STim Northover bool
144314fbfa1STim Northover clang::analyze_format_string::ParseArgPosition(FormatStringHandler &H,
145314fbfa1STim Northover                                                FormatSpecifier &FS,
146314fbfa1STim Northover                                                const char *Start,
147314fbfa1STim Northover                                                const char *&Beg,
148314fbfa1STim Northover                                                const char *E) {
149314fbfa1STim Northover   const char *I = Beg;
150314fbfa1STim Northover 
151314fbfa1STim Northover   const OptionalAmount &Amt = ParseAmount(I, E);
152314fbfa1STim Northover 
153314fbfa1STim Northover   if (I == E) {
154314fbfa1STim Northover     // No more characters left?
155314fbfa1STim Northover     H.HandleIncompleteSpecifier(Start, E - Start);
156314fbfa1STim Northover     return true;
157314fbfa1STim Northover   }
158314fbfa1STim Northover 
159314fbfa1STim Northover   if (Amt.getHowSpecified() == OptionalAmount::Constant && *(I++) == '$') {
160314fbfa1STim Northover     // Warn that positional arguments are non-standard.
161314fbfa1STim Northover     H.HandlePosition(Start, I - Start);
162314fbfa1STim Northover 
163314fbfa1STim Northover     // Special case: '%0$', since this is an easy mistake.
164314fbfa1STim Northover     if (Amt.getConstantAmount() == 0) {
165314fbfa1STim Northover       H.HandleZeroPosition(Start, I - Start);
166314fbfa1STim Northover       return true;
167314fbfa1STim Northover     }
168314fbfa1STim Northover 
169314fbfa1STim Northover     FS.setArgIndex(Amt.getConstantAmount() - 1);
170314fbfa1STim Northover     FS.setUsesPositionalArg();
171314fbfa1STim Northover     // Update the caller's pointer if we decided to consume
172314fbfa1STim Northover     // these characters.
173314fbfa1STim Northover     Beg = I;
174314fbfa1STim Northover     return false;
175314fbfa1STim Northover   }
176314fbfa1STim Northover 
177314fbfa1STim Northover   return false;
178314fbfa1STim Northover }
179314fbfa1STim Northover 
180314fbfa1STim Northover bool
1810ff50d49SMatt Arsenault clang::analyze_format_string::ParseVectorModifier(FormatStringHandler &H,
1820ff50d49SMatt Arsenault                                                   FormatSpecifier &FS,
1830ff50d49SMatt Arsenault                                                   const char *&I,
1840ff50d49SMatt Arsenault                                                   const char *E,
1850ff50d49SMatt Arsenault                                                   const LangOptions &LO) {
1860ff50d49SMatt Arsenault   if (!LO.OpenCL)
1870ff50d49SMatt Arsenault     return false;
1880ff50d49SMatt Arsenault 
1890ff50d49SMatt Arsenault   const char *Start = I;
1900ff50d49SMatt Arsenault   if (*I == 'v') {
1910ff50d49SMatt Arsenault     ++I;
1920ff50d49SMatt Arsenault 
1930ff50d49SMatt Arsenault     if (I == E) {
1940ff50d49SMatt Arsenault       H.HandleIncompleteSpecifier(Start, E - Start);
1950ff50d49SMatt Arsenault       return true;
1960ff50d49SMatt Arsenault     }
1970ff50d49SMatt Arsenault 
1980ff50d49SMatt Arsenault     OptionalAmount NumElts = ParseAmount(I, E);
1990ff50d49SMatt Arsenault     if (NumElts.getHowSpecified() != OptionalAmount::Constant) {
2000ff50d49SMatt Arsenault       H.HandleIncompleteSpecifier(Start, E - Start);
2010ff50d49SMatt Arsenault       return true;
2020ff50d49SMatt Arsenault     }
2030ff50d49SMatt Arsenault 
2040ff50d49SMatt Arsenault     FS.setVectorNumElts(NumElts);
2050ff50d49SMatt Arsenault   }
2060ff50d49SMatt Arsenault 
2070ff50d49SMatt Arsenault   return false;
2080ff50d49SMatt Arsenault }
2090ff50d49SMatt Arsenault 
2100ff50d49SMatt Arsenault bool
211314fbfa1STim Northover clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,
212314fbfa1STim Northover                                                   const char *&I,
213314fbfa1STim Northover                                                   const char *E,
214314fbfa1STim Northover                                                   const LangOptions &LO,
215314fbfa1STim Northover                                                   bool IsScanf) {
216314fbfa1STim Northover   LengthModifier::Kind lmKind = LengthModifier::None;
217314fbfa1STim Northover   const char *lmPosition = I;
218314fbfa1STim Northover   switch (*I) {
219314fbfa1STim Northover     default:
220314fbfa1STim Northover       return false;
221314fbfa1STim Northover     case 'h':
222314fbfa1STim Northover       ++I;
223314fbfa1STim Northover       if (I != E && *I == 'h') {
224314fbfa1STim Northover         ++I;
225314fbfa1STim Northover         lmKind = LengthModifier::AsChar;
22658fc8082SMatt Arsenault       } else if (I != E && *I == 'l' && LO.OpenCL) {
22758fc8082SMatt Arsenault         ++I;
22858fc8082SMatt Arsenault         lmKind = LengthModifier::AsShortLong;
229314fbfa1STim Northover       } else {
230314fbfa1STim Northover         lmKind = LengthModifier::AsShort;
231314fbfa1STim Northover       }
232314fbfa1STim Northover       break;
233314fbfa1STim Northover     case 'l':
234314fbfa1STim Northover       ++I;
235314fbfa1STim Northover       if (I != E && *I == 'l') {
236314fbfa1STim Northover         ++I;
237314fbfa1STim Northover         lmKind = LengthModifier::AsLongLong;
238314fbfa1STim Northover       } else {
239314fbfa1STim Northover         lmKind = LengthModifier::AsLong;
240314fbfa1STim Northover       }
241314fbfa1STim Northover       break;
242314fbfa1STim Northover     case 'j': lmKind = LengthModifier::AsIntMax;     ++I; break;
243314fbfa1STim Northover     case 'z': lmKind = LengthModifier::AsSizeT;      ++I; break;
244314fbfa1STim Northover     case 't': lmKind = LengthModifier::AsPtrDiff;    ++I; break;
245314fbfa1STim Northover     case 'L': lmKind = LengthModifier::AsLongDouble; ++I; break;
246314fbfa1STim Northover     case 'q': lmKind = LengthModifier::AsQuad;       ++I; break;
247314fbfa1STim Northover     case 'a':
248314fbfa1STim Northover       if (IsScanf && !LO.C99 && !LO.CPlusPlus11) {
249314fbfa1STim Northover         // For scanf in C90, look at the next character to see if this should
250314fbfa1STim Northover         // be parsed as the GNU extension 'a' length modifier. If not, this
251314fbfa1STim Northover         // will be parsed as a conversion specifier.
252314fbfa1STim Northover         ++I;
253314fbfa1STim Northover         if (I != E && (*I == 's' || *I == 'S' || *I == '[')) {
254314fbfa1STim Northover           lmKind = LengthModifier::AsAllocate;
255314fbfa1STim Northover           break;
256314fbfa1STim Northover         }
257314fbfa1STim Northover         --I;
258314fbfa1STim Northover       }
259314fbfa1STim Northover       return false;
260314fbfa1STim Northover     case 'm':
261314fbfa1STim Northover       if (IsScanf) {
262314fbfa1STim Northover         lmKind = LengthModifier::AsMAllocate;
263314fbfa1STim Northover         ++I;
264314fbfa1STim Northover         break;
265314fbfa1STim Northover       }
266314fbfa1STim Northover       return false;
267314fbfa1STim Northover     // printf: AsInt64, AsInt32, AsInt3264
268314fbfa1STim Northover     // scanf:  AsInt64
269314fbfa1STim Northover     case 'I':
270314fbfa1STim Northover       if (I + 1 != E && I + 2 != E) {
271314fbfa1STim Northover         if (I[1] == '6' && I[2] == '4') {
272314fbfa1STim Northover           I += 3;
273314fbfa1STim Northover           lmKind = LengthModifier::AsInt64;
274314fbfa1STim Northover           break;
275314fbfa1STim Northover         }
276314fbfa1STim Northover         if (IsScanf)
277314fbfa1STim Northover           return false;
278314fbfa1STim Northover 
279314fbfa1STim Northover         if (I[1] == '3' && I[2] == '2') {
280314fbfa1STim Northover           I += 3;
281314fbfa1STim Northover           lmKind = LengthModifier::AsInt32;
282314fbfa1STim Northover           break;
283314fbfa1STim Northover         }
284314fbfa1STim Northover       }
285314fbfa1STim Northover       ++I;
286314fbfa1STim Northover       lmKind = LengthModifier::AsInt3264;
287314fbfa1STim Northover       break;
288314fbfa1STim Northover     case 'w':
289314fbfa1STim Northover       lmKind = LengthModifier::AsWide; ++I; break;
290314fbfa1STim Northover   }
291314fbfa1STim Northover   LengthModifier lm(lmPosition, lmKind);
292314fbfa1STim Northover   FS.setLengthModifier(lm);
293314fbfa1STim Northover   return true;
294314fbfa1STim Northover }
295314fbfa1STim Northover 
296314fbfa1STim Northover bool clang::analyze_format_string::ParseUTF8InvalidSpecifier(
297314fbfa1STim Northover     const char *SpecifierBegin, const char *FmtStrEnd, unsigned &Len) {
298314fbfa1STim Northover   if (SpecifierBegin + 1 >= FmtStrEnd)
299314fbfa1STim Northover     return false;
300314fbfa1STim Northover 
301314fbfa1STim Northover   const llvm::UTF8 *SB =
302314fbfa1STim Northover       reinterpret_cast<const llvm::UTF8 *>(SpecifierBegin + 1);
303314fbfa1STim Northover   const llvm::UTF8 *SE = reinterpret_cast<const llvm::UTF8 *>(FmtStrEnd);
304314fbfa1STim Northover   const char FirstByte = *SB;
305314fbfa1STim Northover 
306314fbfa1STim Northover   // If the invalid specifier is a multibyte UTF-8 string, return the
307314fbfa1STim Northover   // total length accordingly so that the conversion specifier can be
308314fbfa1STim Northover   // properly updated to reflect a complete UTF-8 specifier.
309314fbfa1STim Northover   unsigned NumBytes = llvm::getNumBytesForUTF8(FirstByte);
310314fbfa1STim Northover   if (NumBytes == 1)
311314fbfa1STim Northover     return false;
312314fbfa1STim Northover   if (SB + NumBytes > SE)
313314fbfa1STim Northover     return false;
314314fbfa1STim Northover 
315314fbfa1STim Northover   Len = NumBytes + 1;
316314fbfa1STim Northover   return true;
317314fbfa1STim Northover }
318314fbfa1STim Northover 
319314fbfa1STim Northover //===----------------------------------------------------------------------===//
320314fbfa1STim Northover // Methods on ArgType.
321314fbfa1STim Northover //===----------------------------------------------------------------------===//
322314fbfa1STim Northover 
323314fbfa1STim Northover clang::analyze_format_string::ArgType::MatchKind
324314fbfa1STim Northover ArgType::matchesType(ASTContext &C, QualType argTy) const {
32592edd74bSFélix Cloutier   // When using the format attribute in C++, you can receive a function or an
32692edd74bSFélix Cloutier   // array that will necessarily decay to a pointer when passed to the final
32792edd74bSFélix Cloutier   // format consumer. Apply decay before type comparison.
32892edd74bSFélix Cloutier   if (argTy->canDecayToPointerType())
32992edd74bSFélix Cloutier     argTy = C.getDecayedType(argTy);
33092edd74bSFélix Cloutier 
331314fbfa1STim Northover   if (Ptr) {
332314fbfa1STim Northover     // It has to be a pointer.
333314fbfa1STim Northover     const PointerType *PT = argTy->getAs<PointerType>();
334314fbfa1STim Northover     if (!PT)
335314fbfa1STim Northover       return NoMatch;
336314fbfa1STim Northover 
337314fbfa1STim Northover     // We cannot write through a const qualified pointer.
338314fbfa1STim Northover     if (PT->getPointeeType().isConstQualified())
339314fbfa1STim Northover       return NoMatch;
340314fbfa1STim Northover 
341314fbfa1STim Northover     argTy = PT->getPointeeType();
342314fbfa1STim Northover   }
343314fbfa1STim Northover 
344314fbfa1STim Northover   switch (K) {
345314fbfa1STim Northover     case InvalidTy:
346314fbfa1STim Northover       llvm_unreachable("ArgType must be valid");
347314fbfa1STim Northover 
348314fbfa1STim Northover     case UnknownTy:
349314fbfa1STim Northover       return Match;
350314fbfa1STim Northover 
351314fbfa1STim Northover     case AnyCharTy: {
352e3bd67edSYingChi Long       if (const auto *ETy = argTy->getAs<EnumType>()) {
353314fbfa1STim Northover         // If the enum is incomplete we know nothing about the underlying type.
3543632e2f5SAaron Ballman         // Assume that it's 'int'. Do not use the underlying type for a scoped
3553632e2f5SAaron Ballman         // enumeration.
356314fbfa1STim Northover         if (!ETy->getDecl()->isComplete())
357314fbfa1STim Northover           return NoMatch;
3583632e2f5SAaron Ballman         if (ETy->isUnscopedEnumerationType())
359314fbfa1STim Northover           argTy = ETy->getDecl()->getIntegerType();
360314fbfa1STim Northover       }
361314fbfa1STim Northover 
362e3bd67edSYingChi Long       if (const auto *BT = argTy->getAs<BuiltinType>()) {
363e3bd67edSYingChi Long         // The types are perfectly matched?
364314fbfa1STim Northover         switch (BT->getKind()) {
365314fbfa1STim Northover         default:
366314fbfa1STim Northover           break;
367314fbfa1STim Northover         case BuiltinType::Char_S:
368314fbfa1STim Northover         case BuiltinType::SChar:
369314fbfa1STim Northover         case BuiltinType::UChar:
370314fbfa1STim Northover         case BuiltinType::Char_U:
371314fbfa1STim Northover             return Match;
372e4e56f91SPodchishchaeva, Mariya         case BuiltinType::Bool:
373e4e56f91SPodchishchaeva, Mariya           if (!Ptr)
374e4e56f91SPodchishchaeva, Mariya             return Match;
375e4e56f91SPodchishchaeva, Mariya           break;
376314fbfa1STim Northover         }
377e3bd67edSYingChi Long         // "Partially matched" because of promotions?
378e3bd67edSYingChi Long         if (!Ptr) {
379e3bd67edSYingChi Long           switch (BT->getKind()) {
380e3bd67edSYingChi Long           default:
381e3bd67edSYingChi Long             break;
382e3bd67edSYingChi Long           case BuiltinType::Int:
383e3bd67edSYingChi Long           case BuiltinType::UInt:
384e3bd67edSYingChi Long             return MatchPromotion;
385e3bd67edSYingChi Long           case BuiltinType::Short:
386e3bd67edSYingChi Long           case BuiltinType::UShort:
387e3bd67edSYingChi Long           case BuiltinType::WChar_S:
388e3bd67edSYingChi Long           case BuiltinType::WChar_U:
389e3bd67edSYingChi Long             return NoMatchPromotionTypeConfusion;
390e3bd67edSYingChi Long           }
391e3bd67edSYingChi Long         }
392e3bd67edSYingChi Long       }
393314fbfa1STim Northover       return NoMatch;
394314fbfa1STim Northover     }
395314fbfa1STim Northover 
396314fbfa1STim Northover     case SpecificTy: {
397314fbfa1STim Northover       if (const EnumType *ETy = argTy->getAs<EnumType>()) {
398314fbfa1STim Northover         // If the enum is incomplete we know nothing about the underlying type.
3993632e2f5SAaron Ballman         // Assume that it's 'int'. Do not use the underlying type for a scoped
4003632e2f5SAaron Ballman         // enumeration as that needs an exact match.
401314fbfa1STim Northover         if (!ETy->getDecl()->isComplete())
402314fbfa1STim Northover           argTy = C.IntTy;
4033632e2f5SAaron Ballman         else if (ETy->isUnscopedEnumerationType())
404314fbfa1STim Northover           argTy = ETy->getDecl()->getIntegerType();
405314fbfa1STim Northover       }
40640ba1f60SPiJoules 
40740ba1f60SPiJoules       if (argTy->isSaturatedFixedPointType())
40840ba1f60SPiJoules         argTy = C.getCorrespondingUnsaturatedType(argTy);
40940ba1f60SPiJoules 
410314fbfa1STim Northover       argTy = C.getCanonicalType(argTy).getUnqualifiedType();
411314fbfa1STim Northover 
412314fbfa1STim Northover       if (T == argTy)
413314fbfa1STim Northover         return Match;
414e3bd67edSYingChi Long       if (const auto *BT = argTy->getAs<BuiltinType>()) {
415e3bd67edSYingChi Long         // Check if the only difference between them is signed vs unsigned
416ea92b1f9SKarl-Johan Karlsson         // if true, return match signedness.
417314fbfa1STim Northover         switch (BT->getKind()) {
418314fbfa1STim Northover           default:
419314fbfa1STim Northover             break;
420e4e56f91SPodchishchaeva, Mariya           case BuiltinType::Bool:
421e4e56f91SPodchishchaeva, Mariya             if (Ptr && (T == C.UnsignedCharTy || T == C.SignedCharTy))
422e4e56f91SPodchishchaeva, Mariya               return NoMatch;
423e4e56f91SPodchishchaeva, Mariya             [[fallthrough]];
424314fbfa1STim Northover           case BuiltinType::Char_S:
425314fbfa1STim Northover           case BuiltinType::SChar:
426ea92b1f9SKarl-Johan Karlsson             if (T == C.UnsignedShortTy || T == C.ShortTy)
427ea92b1f9SKarl-Johan Karlsson               return NoMatchTypeConfusion;
428ea92b1f9SKarl-Johan Karlsson             if (T == C.UnsignedCharTy)
429ea92b1f9SKarl-Johan Karlsson               return NoMatchSignedness;
430ea92b1f9SKarl-Johan Karlsson             if (T == C.SignedCharTy)
431ea92b1f9SKarl-Johan Karlsson               return Match;
432ea92b1f9SKarl-Johan Karlsson             break;
433314fbfa1STim Northover           case BuiltinType::Char_U:
434314fbfa1STim Northover           case BuiltinType::UChar:
435cc01d642SNathan Huckleberry             if (T == C.UnsignedShortTy || T == C.ShortTy)
436f7766b1eSErik Pilkington               return NoMatchTypeConfusion;
437ea92b1f9SKarl-Johan Karlsson             if (T == C.UnsignedCharTy)
438e3bd67edSYingChi Long               return Match;
439ea92b1f9SKarl-Johan Karlsson             if (T == C.SignedCharTy)
440ea92b1f9SKarl-Johan Karlsson               return NoMatchSignedness;
441e3bd67edSYingChi Long             break;
442314fbfa1STim Northover           case BuiltinType::Short:
443e3bd67edSYingChi Long             if (T == C.UnsignedShortTy)
444ea92b1f9SKarl-Johan Karlsson               return NoMatchSignedness;
445e3bd67edSYingChi Long             break;
446314fbfa1STim Northover           case BuiltinType::UShort:
447e3bd67edSYingChi Long             if (T == C.ShortTy)
448ea92b1f9SKarl-Johan Karlsson               return NoMatchSignedness;
449e3bd67edSYingChi Long             break;
450314fbfa1STim Northover           case BuiltinType::Int:
451e3bd67edSYingChi Long             if (T == C.UnsignedIntTy)
452ea92b1f9SKarl-Johan Karlsson               return NoMatchSignedness;
453e3bd67edSYingChi Long             break;
454314fbfa1STim Northover           case BuiltinType::UInt:
455e3bd67edSYingChi Long             if (T == C.IntTy)
456ea92b1f9SKarl-Johan Karlsson               return NoMatchSignedness;
457e3bd67edSYingChi Long             break;
458314fbfa1STim Northover           case BuiltinType::Long:
459e3bd67edSYingChi Long             if (T == C.UnsignedLongTy)
460ea92b1f9SKarl-Johan Karlsson               return NoMatchSignedness;
461e3bd67edSYingChi Long             break;
462314fbfa1STim Northover           case BuiltinType::ULong:
463e3bd67edSYingChi Long             if (T == C.LongTy)
464ea92b1f9SKarl-Johan Karlsson               return NoMatchSignedness;
465e3bd67edSYingChi Long             break;
466314fbfa1STim Northover           case BuiltinType::LongLong:
467e3bd67edSYingChi Long             if (T == C.UnsignedLongLongTy)
468ea92b1f9SKarl-Johan Karlsson               return NoMatchSignedness;
469e3bd67edSYingChi Long             break;
470314fbfa1STim Northover           case BuiltinType::ULongLong:
471e3bd67edSYingChi Long             if (T == C.LongLongTy)
472ea92b1f9SKarl-Johan Karlsson               return NoMatchSignedness;
473e3bd67edSYingChi Long             break;
474e3bd67edSYingChi Long           }
475e3bd67edSYingChi Long           // "Partially matched" because of promotions?
476e3bd67edSYingChi Long           if (!Ptr) {
477e3bd67edSYingChi Long             switch (BT->getKind()) {
478e3bd67edSYingChi Long             default:
479e3bd67edSYingChi Long               break;
48004e6178aSFélix Cloutier             case BuiltinType::Bool:
48104e6178aSFélix Cloutier               if (T == C.IntTy || T == C.UnsignedIntTy)
48204e6178aSFélix Cloutier                 return MatchPromotion;
48304e6178aSFélix Cloutier               break;
484e3bd67edSYingChi Long             case BuiltinType::Int:
485e3bd67edSYingChi Long             case BuiltinType::UInt:
486e3bd67edSYingChi Long               if (T == C.SignedCharTy || T == C.UnsignedCharTy ||
487e3bd67edSYingChi Long                   T == C.ShortTy || T == C.UnsignedShortTy || T == C.WCharTy ||
488e3bd67edSYingChi Long                   T == C.WideCharTy)
489e3bd67edSYingChi Long                 return MatchPromotion;
490e3bd67edSYingChi Long               break;
49104e6178aSFélix Cloutier             case BuiltinType::Char_U:
49204e6178aSFélix Cloutier               if (T == C.UnsignedIntTy)
49304e6178aSFélix Cloutier                 return MatchPromotion;
49404e6178aSFélix Cloutier               if (T == C.UnsignedShortTy)
49504e6178aSFélix Cloutier                 return NoMatchPromotionTypeConfusion;
49604e6178aSFélix Cloutier               break;
49704e6178aSFélix Cloutier             case BuiltinType::Char_S:
49804e6178aSFélix Cloutier               if (T == C.IntTy)
49904e6178aSFélix Cloutier                 return MatchPromotion;
50004e6178aSFélix Cloutier               if (T == C.ShortTy)
50104e6178aSFélix Cloutier                 return NoMatchPromotionTypeConfusion;
50204e6178aSFélix Cloutier               break;
50304e6178aSFélix Cloutier             case BuiltinType::Half:
50404e6178aSFélix Cloutier             case BuiltinType::Float:
50504e6178aSFélix Cloutier               if (T == C.DoubleTy)
50604e6178aSFélix Cloutier                 return MatchPromotion;
50704e6178aSFélix Cloutier               break;
508e3bd67edSYingChi Long             case BuiltinType::Short:
509e3bd67edSYingChi Long             case BuiltinType::UShort:
510e3bd67edSYingChi Long               if (T == C.SignedCharTy || T == C.UnsignedCharTy)
511e3bd67edSYingChi Long                 return NoMatchPromotionTypeConfusion;
512e3bd67edSYingChi Long               break;
513e3bd67edSYingChi Long             case BuiltinType::WChar_U:
514e3bd67edSYingChi Long             case BuiltinType::WChar_S:
515e3bd67edSYingChi Long               if (T != C.WCharTy && T != C.WideCharTy)
516e3bd67edSYingChi Long                 return NoMatchPromotionTypeConfusion;
517e3bd67edSYingChi Long             }
518e3bd67edSYingChi Long           }
519314fbfa1STim Northover       }
520314fbfa1STim Northover       return NoMatch;
521314fbfa1STim Northover     }
522314fbfa1STim Northover 
523*0e24686aSMital Ashok     case CStrTy:
524*0e24686aSMital Ashok       if (const auto *PT = argTy->getAs<PointerType>();
525*0e24686aSMital Ashok           PT && PT->getPointeeType()->isCharType())
526314fbfa1STim Northover         return Match;
527314fbfa1STim Northover       return NoMatch;
528314fbfa1STim Northover 
529*0e24686aSMital Ashok     case WCStrTy:
530*0e24686aSMital Ashok       if (const auto *PT = argTy->getAs<PointerType>();
531*0e24686aSMital Ashok           PT &&
532*0e24686aSMital Ashok           C.hasSameUnqualifiedType(PT->getPointeeType(), C.getWideCharType()))
533*0e24686aSMital Ashok         return Match;
534314fbfa1STim Northover       return NoMatch;
535314fbfa1STim Northover 
536314fbfa1STim Northover     case WIntTy: {
537314fbfa1STim Northover       QualType WInt = C.getCanonicalType(C.getWIntType()).getUnqualifiedType();
538314fbfa1STim Northover 
539314fbfa1STim Northover       if (C.getCanonicalType(argTy).getUnqualifiedType() == WInt)
540314fbfa1STim Northover         return Match;
541314fbfa1STim Northover 
542464926efSXiang Li       QualType PromoArg = C.isPromotableIntegerType(argTy)
543314fbfa1STim Northover                               ? C.getPromotedIntegerType(argTy)
544314fbfa1STim Northover                               : argTy;
545314fbfa1STim Northover       PromoArg = C.getCanonicalType(PromoArg).getUnqualifiedType();
546314fbfa1STim Northover 
547314fbfa1STim Northover       // If the promoted argument is the corresponding signed type of the
548314fbfa1STim Northover       // wint_t type, then it should match.
549314fbfa1STim Northover       if (PromoArg->hasSignedIntegerRepresentation() &&
550314fbfa1STim Northover           C.getCorrespondingUnsignedType(PromoArg) == WInt)
551314fbfa1STim Northover         return Match;
552314fbfa1STim Northover 
553314fbfa1STim Northover       return WInt == PromoArg ? Match : NoMatch;
554314fbfa1STim Northover     }
555314fbfa1STim Northover 
556314fbfa1STim Northover     case CPointerTy:
557*0e24686aSMital Ashok       if (const auto *PT = argTy->getAs<PointerType>()) {
558*0e24686aSMital Ashok         QualType PointeeTy = PT->getPointeeType();
559*0e24686aSMital Ashok         if (PointeeTy->isVoidType() || (!Ptr && PointeeTy->isCharType()))
560314fbfa1STim Northover           return Match;
561314fbfa1STim Northover         return NoMatchPedantic;
562314fbfa1STim Northover       }
563314fbfa1STim Northover 
564*0e24686aSMital Ashok       // nullptr_t* is not a double pointer, so reject when something like
565*0e24686aSMital Ashok       // void** is expected.
566*0e24686aSMital Ashok       // In C++, nullptr is promoted to void*. In C23, va_arg(ap, void*) is not
567*0e24686aSMital Ashok       // undefined when the next argument is of type nullptr_t.
568*0e24686aSMital Ashok       if (!Ptr && argTy->isNullPtrType())
569*0e24686aSMital Ashok         return C.getLangOpts().CPlusPlus ? MatchPromotion : Match;
570*0e24686aSMital Ashok 
571*0e24686aSMital Ashok       if (argTy->isObjCObjectPointerType() || argTy->isBlockPointerType())
572*0e24686aSMital Ashok         return NoMatchPedantic;
573*0e24686aSMital Ashok 
574*0e24686aSMital Ashok       return NoMatch;
575*0e24686aSMital Ashok 
576314fbfa1STim Northover     case ObjCPointerTy: {
577314fbfa1STim Northover       if (argTy->getAs<ObjCObjectPointerType>() ||
578314fbfa1STim Northover           argTy->getAs<BlockPointerType>())
579314fbfa1STim Northover         return Match;
580314fbfa1STim Northover 
581314fbfa1STim Northover       // Handle implicit toll-free bridging.
582314fbfa1STim Northover       if (const PointerType *PT = argTy->getAs<PointerType>()) {
583314fbfa1STim Northover         // Things such as CFTypeRef are really just opaque pointers
584314fbfa1STim Northover         // to C structs representing CF types that can often be bridged
585314fbfa1STim Northover         // to Objective-C objects.  Since the compiler doesn't know which
586314fbfa1STim Northover         // structs can be toll-free bridged, we just accept them all.
587314fbfa1STim Northover         QualType pointee = PT->getPointeeType();
588314fbfa1STim Northover         if (pointee->getAsStructureType() || pointee->isVoidType())
589314fbfa1STim Northover           return Match;
590314fbfa1STim Northover       }
591314fbfa1STim Northover       return NoMatch;
592314fbfa1STim Northover     }
593314fbfa1STim Northover   }
594314fbfa1STim Northover 
595314fbfa1STim Northover   llvm_unreachable("Invalid ArgType Kind!");
596314fbfa1STim Northover }
597314fbfa1STim Northover 
5980ff50d49SMatt Arsenault ArgType ArgType::makeVectorType(ASTContext &C, unsigned NumElts) const {
59958fc8082SMatt Arsenault   // Check for valid vector element types.
60058fc8082SMatt Arsenault   if (T.isNull())
6010ff50d49SMatt Arsenault     return ArgType::Invalid();
6020ff50d49SMatt Arsenault 
6030ff50d49SMatt Arsenault   QualType Vec = C.getExtVectorType(T, NumElts);
6040ff50d49SMatt Arsenault   return ArgType(Vec, Name);
6050ff50d49SMatt Arsenault }
6060ff50d49SMatt Arsenault 
607314fbfa1STim Northover QualType ArgType::getRepresentativeType(ASTContext &C) const {
608314fbfa1STim Northover   QualType Res;
609314fbfa1STim Northover   switch (K) {
610314fbfa1STim Northover     case InvalidTy:
611314fbfa1STim Northover       llvm_unreachable("No representative type for Invalid ArgType");
612314fbfa1STim Northover     case UnknownTy:
613314fbfa1STim Northover       llvm_unreachable("No representative type for Unknown ArgType");
614314fbfa1STim Northover     case AnyCharTy:
615314fbfa1STim Northover       Res = C.CharTy;
616314fbfa1STim Northover       break;
617314fbfa1STim Northover     case SpecificTy:
618314fbfa1STim Northover       Res = T;
619314fbfa1STim Northover       break;
620314fbfa1STim Northover     case CStrTy:
621314fbfa1STim Northover       Res = C.getPointerType(C.CharTy);
622314fbfa1STim Northover       break;
623314fbfa1STim Northover     case WCStrTy:
624314fbfa1STim Northover       Res = C.getPointerType(C.getWideCharType());
625314fbfa1STim Northover       break;
626314fbfa1STim Northover     case ObjCPointerTy:
627314fbfa1STim Northover       Res = C.ObjCBuiltinIdTy;
628314fbfa1STim Northover       break;
629314fbfa1STim Northover     case CPointerTy:
630314fbfa1STim Northover       Res = C.VoidPtrTy;
631314fbfa1STim Northover       break;
632314fbfa1STim Northover     case WIntTy: {
633314fbfa1STim Northover       Res = C.getWIntType();
634314fbfa1STim Northover       break;
635314fbfa1STim Northover     }
636314fbfa1STim Northover   }
637314fbfa1STim Northover 
638314fbfa1STim Northover   if (Ptr)
639314fbfa1STim Northover     Res = C.getPointerType(Res);
640314fbfa1STim Northover   return Res;
641314fbfa1STim Northover }
642314fbfa1STim Northover 
643314fbfa1STim Northover std::string ArgType::getRepresentativeTypeName(ASTContext &C) const {
6445fee6936SJessica Clarke   std::string S = getRepresentativeType(C).getAsString(C.getPrintingPolicy());
645314fbfa1STim Northover 
646314fbfa1STim Northover   std::string Alias;
647314fbfa1STim Northover   if (Name) {
648314fbfa1STim Northover     // Use a specific name for this type, e.g. "size_t".
649314fbfa1STim Northover     Alias = Name;
650314fbfa1STim Northover     if (Ptr) {
651314fbfa1STim Northover       // If ArgType is actually a pointer to T, append an asterisk.
652314fbfa1STim Northover       Alias += (Alias[Alias.size()-1] == '*') ? "*" : " *";
653314fbfa1STim Northover     }
654314fbfa1STim Northover     // If Alias is the same as the underlying type, e.g. wchar_t, then drop it.
655314fbfa1STim Northover     if (S == Alias)
656314fbfa1STim Northover       Alias.clear();
657314fbfa1STim Northover   }
658314fbfa1STim Northover 
659314fbfa1STim Northover   if (!Alias.empty())
660314fbfa1STim Northover     return std::string("'") + Alias + "' (aka '" + S + "')";
661314fbfa1STim Northover   return std::string("'") + S + "'";
662314fbfa1STim Northover }
663314fbfa1STim Northover 
664314fbfa1STim Northover 
665314fbfa1STim Northover //===----------------------------------------------------------------------===//
666314fbfa1STim Northover // Methods on OptionalAmount.
667314fbfa1STim Northover //===----------------------------------------------------------------------===//
668314fbfa1STim Northover 
669314fbfa1STim Northover ArgType
670314fbfa1STim Northover analyze_format_string::OptionalAmount::getArgType(ASTContext &Ctx) const {
671314fbfa1STim Northover   return Ctx.IntTy;
672314fbfa1STim Northover }
673314fbfa1STim Northover 
674314fbfa1STim Northover //===----------------------------------------------------------------------===//
675314fbfa1STim Northover // Methods on LengthModifier.
676314fbfa1STim Northover //===----------------------------------------------------------------------===//
677314fbfa1STim Northover 
678314fbfa1STim Northover const char *
679314fbfa1STim Northover analyze_format_string::LengthModifier::toString() const {
680314fbfa1STim Northover   switch (kind) {
681314fbfa1STim Northover   case AsChar:
682314fbfa1STim Northover     return "hh";
683314fbfa1STim Northover   case AsShort:
684314fbfa1STim Northover     return "h";
68558fc8082SMatt Arsenault   case AsShortLong:
68658fc8082SMatt Arsenault     return "hl";
687314fbfa1STim Northover   case AsLong: // or AsWideChar
688314fbfa1STim Northover     return "l";
689314fbfa1STim Northover   case AsLongLong:
690314fbfa1STim Northover     return "ll";
691314fbfa1STim Northover   case AsQuad:
692314fbfa1STim Northover     return "q";
693314fbfa1STim Northover   case AsIntMax:
694314fbfa1STim Northover     return "j";
695314fbfa1STim Northover   case AsSizeT:
696314fbfa1STim Northover     return "z";
697314fbfa1STim Northover   case AsPtrDiff:
698314fbfa1STim Northover     return "t";
699314fbfa1STim Northover   case AsInt32:
700314fbfa1STim Northover     return "I32";
701314fbfa1STim Northover   case AsInt3264:
702314fbfa1STim Northover     return "I";
703314fbfa1STim Northover   case AsInt64:
704314fbfa1STim Northover     return "I64";
705314fbfa1STim Northover   case AsLongDouble:
706314fbfa1STim Northover     return "L";
707314fbfa1STim Northover   case AsAllocate:
708314fbfa1STim Northover     return "a";
709314fbfa1STim Northover   case AsMAllocate:
710314fbfa1STim Northover     return "m";
711314fbfa1STim Northover   case AsWide:
712314fbfa1STim Northover     return "w";
713314fbfa1STim Northover   case None:
714314fbfa1STim Northover     return "";
715314fbfa1STim Northover   }
716314fbfa1STim Northover   return nullptr;
717314fbfa1STim Northover }
718314fbfa1STim Northover 
719314fbfa1STim Northover //===----------------------------------------------------------------------===//
720314fbfa1STim Northover // Methods on ConversionSpecifier.
721314fbfa1STim Northover //===----------------------------------------------------------------------===//
722314fbfa1STim Northover 
723314fbfa1STim Northover const char *ConversionSpecifier::toString() const {
724314fbfa1STim Northover   switch (kind) {
72588501dc7SFangrui Song   case bArg: return "b";
72688501dc7SFangrui Song   case BArg: return "B";
727314fbfa1STim Northover   case dArg: return "d";
728314fbfa1STim Northover   case DArg: return "D";
729314fbfa1STim Northover   case iArg: return "i";
730314fbfa1STim Northover   case oArg: return "o";
731314fbfa1STim Northover   case OArg: return "O";
732314fbfa1STim Northover   case uArg: return "u";
733314fbfa1STim Northover   case UArg: return "U";
734314fbfa1STim Northover   case xArg: return "x";
735314fbfa1STim Northover   case XArg: return "X";
736314fbfa1STim Northover   case fArg: return "f";
737314fbfa1STim Northover   case FArg: return "F";
738314fbfa1STim Northover   case eArg: return "e";
739314fbfa1STim Northover   case EArg: return "E";
740314fbfa1STim Northover   case gArg: return "g";
741314fbfa1STim Northover   case GArg: return "G";
742314fbfa1STim Northover   case aArg: return "a";
743314fbfa1STim Northover   case AArg: return "A";
744314fbfa1STim Northover   case cArg: return "c";
745314fbfa1STim Northover   case sArg: return "s";
746314fbfa1STim Northover   case pArg: return "p";
747314fbfa1STim Northover   case PArg:
748314fbfa1STim Northover     return "P";
749314fbfa1STim Northover   case nArg: return "n";
750314fbfa1STim Northover   case PercentArg:  return "%";
751314fbfa1STim Northover   case ScanListArg: return "[";
752314fbfa1STim Northover   case InvalidSpecifier: return nullptr;
753314fbfa1STim Northover 
754314fbfa1STim Northover   // POSIX unicode extensions.
755314fbfa1STim Northover   case CArg: return "C";
756314fbfa1STim Northover   case SArg: return "S";
757314fbfa1STim Northover 
758314fbfa1STim Northover   // Objective-C specific specifiers.
759314fbfa1STim Northover   case ObjCObjArg: return "@";
760314fbfa1STim Northover 
761314fbfa1STim Northover   // FreeBSD kernel specific specifiers.
762314fbfa1STim Northover   case FreeBSDbArg: return "b";
763314fbfa1STim Northover   case FreeBSDDArg: return "D";
764314fbfa1STim Northover   case FreeBSDrArg: return "r";
765314fbfa1STim Northover   case FreeBSDyArg: return "y";
766314fbfa1STim Northover 
767314fbfa1STim Northover   // GlibC specific specifiers.
768314fbfa1STim Northover   case PrintErrno: return "m";
769314fbfa1STim Northover 
770314fbfa1STim Northover   // MS specific specifiers.
771314fbfa1STim Northover   case ZArg: return "Z";
77240ba1f60SPiJoules 
77340ba1f60SPiJoules   // ISO/IEC TR 18037 (fixed-point) specific specifiers.
77440ba1f60SPiJoules   case rArg:
77540ba1f60SPiJoules     return "r";
77640ba1f60SPiJoules   case RArg:
77740ba1f60SPiJoules     return "R";
77840ba1f60SPiJoules   case kArg:
77940ba1f60SPiJoules     return "k";
78040ba1f60SPiJoules   case KArg:
78140ba1f60SPiJoules     return "K";
782314fbfa1STim Northover   }
783314fbfa1STim Northover   return nullptr;
784314fbfa1STim Northover }
785314fbfa1STim Northover 
7866ad0788cSKazu Hirata std::optional<ConversionSpecifier>
787314fbfa1STim Northover ConversionSpecifier::getStandardSpecifier() const {
788314fbfa1STim Northover   ConversionSpecifier::Kind NewKind;
789314fbfa1STim Northover 
790314fbfa1STim Northover   switch (getKind()) {
791314fbfa1STim Northover   default:
792e31564afSKazu Hirata     return std::nullopt;
793314fbfa1STim Northover   case DArg:
794314fbfa1STim Northover     NewKind = dArg;
795314fbfa1STim Northover     break;
796314fbfa1STim Northover   case UArg:
797314fbfa1STim Northover     NewKind = uArg;
798314fbfa1STim Northover     break;
799314fbfa1STim Northover   case OArg:
800314fbfa1STim Northover     NewKind = oArg;
801314fbfa1STim Northover     break;
802314fbfa1STim Northover   }
803314fbfa1STim Northover 
804314fbfa1STim Northover   ConversionSpecifier FixedCS(*this);
805314fbfa1STim Northover   FixedCS.setKind(NewKind);
806314fbfa1STim Northover   return FixedCS;
807314fbfa1STim Northover }
808314fbfa1STim Northover 
809314fbfa1STim Northover //===----------------------------------------------------------------------===//
810314fbfa1STim Northover // Methods on OptionalAmount.
811314fbfa1STim Northover //===----------------------------------------------------------------------===//
812314fbfa1STim Northover 
813314fbfa1STim Northover void OptionalAmount::toString(raw_ostream &os) const {
814314fbfa1STim Northover   switch (hs) {
815314fbfa1STim Northover   case Invalid:
816314fbfa1STim Northover   case NotSpecified:
817314fbfa1STim Northover     return;
818314fbfa1STim Northover   case Arg:
819314fbfa1STim Northover     if (UsesDotPrefix)
820314fbfa1STim Northover         os << ".";
821314fbfa1STim Northover     if (usesPositionalArg())
822314fbfa1STim Northover       os << "*" << getPositionalArgIndex() << "$";
823314fbfa1STim Northover     else
824314fbfa1STim Northover       os << "*";
825314fbfa1STim Northover     break;
826314fbfa1STim Northover   case Constant:
827314fbfa1STim Northover     if (UsesDotPrefix)
828314fbfa1STim Northover         os << ".";
829314fbfa1STim Northover     os << amt;
830314fbfa1STim Northover     break;
831314fbfa1STim Northover   }
832314fbfa1STim Northover }
833314fbfa1STim Northover 
83458fc8082SMatt Arsenault bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target,
83558fc8082SMatt Arsenault                                              const LangOptions &LO) const {
836314fbfa1STim Northover   switch (LM.getKind()) {
837314fbfa1STim Northover     case LengthModifier::None:
838314fbfa1STim Northover       return true;
839314fbfa1STim Northover 
840314fbfa1STim Northover     // Handle most integer flags
841314fbfa1STim Northover     case LengthModifier::AsShort:
84258fc8082SMatt Arsenault       // Length modifier only applies to FP vectors.
84358fc8082SMatt Arsenault       if (LO.OpenCL && CS.isDoubleArg())
84458fc8082SMatt Arsenault         return !VectorNumElts.isInvalid();
84558fc8082SMatt Arsenault 
84640ba1f60SPiJoules       if (CS.isFixedPointArg())
84740ba1f60SPiJoules         return true;
84840ba1f60SPiJoules 
849314fbfa1STim Northover       if (Target.getTriple().isOSMSVCRT()) {
850314fbfa1STim Northover         switch (CS.getKind()) {
851314fbfa1STim Northover           case ConversionSpecifier::cArg:
852314fbfa1STim Northover           case ConversionSpecifier::CArg:
853314fbfa1STim Northover           case ConversionSpecifier::sArg:
854314fbfa1STim Northover           case ConversionSpecifier::SArg:
855314fbfa1STim Northover           case ConversionSpecifier::ZArg:
856314fbfa1STim Northover             return true;
857314fbfa1STim Northover           default:
858314fbfa1STim Northover             break;
859314fbfa1STim Northover         }
860314fbfa1STim Northover       }
8613f18f7c0SFangrui Song       [[fallthrough]];
862314fbfa1STim Northover     case LengthModifier::AsChar:
863314fbfa1STim Northover     case LengthModifier::AsLongLong:
864314fbfa1STim Northover     case LengthModifier::AsQuad:
865314fbfa1STim Northover     case LengthModifier::AsIntMax:
866314fbfa1STim Northover     case LengthModifier::AsSizeT:
867314fbfa1STim Northover     case LengthModifier::AsPtrDiff:
868314fbfa1STim Northover       switch (CS.getKind()) {
86988501dc7SFangrui Song         case ConversionSpecifier::bArg:
87088501dc7SFangrui Song         case ConversionSpecifier::BArg:
871314fbfa1STim Northover         case ConversionSpecifier::dArg:
872314fbfa1STim Northover         case ConversionSpecifier::DArg:
873314fbfa1STim Northover         case ConversionSpecifier::iArg:
874314fbfa1STim Northover         case ConversionSpecifier::oArg:
875314fbfa1STim Northover         case ConversionSpecifier::OArg:
876314fbfa1STim Northover         case ConversionSpecifier::uArg:
877314fbfa1STim Northover         case ConversionSpecifier::UArg:
878314fbfa1STim Northover         case ConversionSpecifier::xArg:
879314fbfa1STim Northover         case ConversionSpecifier::XArg:
880314fbfa1STim Northover         case ConversionSpecifier::nArg:
881314fbfa1STim Northover           return true;
882314fbfa1STim Northover         case ConversionSpecifier::FreeBSDrArg:
883314fbfa1STim Northover         case ConversionSpecifier::FreeBSDyArg:
884b2c6251cSPaul Robinson           return Target.getTriple().isOSFreeBSD() || Target.getTriple().isPS();
885314fbfa1STim Northover         default:
886314fbfa1STim Northover           return false;
887314fbfa1STim Northover       }
888314fbfa1STim Northover 
88958fc8082SMatt Arsenault     case LengthModifier::AsShortLong:
89058fc8082SMatt Arsenault       return LO.OpenCL && !VectorNumElts.isInvalid();
89158fc8082SMatt Arsenault 
892314fbfa1STim Northover     // Handle 'l' flag
893314fbfa1STim Northover     case LengthModifier::AsLong: // or AsWideChar
89458fc8082SMatt Arsenault       if (CS.isDoubleArg()) {
89558fc8082SMatt Arsenault         // Invalid for OpenCL FP scalars.
89658fc8082SMatt Arsenault         if (LO.OpenCL && VectorNumElts.isInvalid())
89758fc8082SMatt Arsenault           return false;
89858fc8082SMatt Arsenault         return true;
89958fc8082SMatt Arsenault       }
90058fc8082SMatt Arsenault 
90140ba1f60SPiJoules       if (CS.isFixedPointArg())
90240ba1f60SPiJoules         return true;
90340ba1f60SPiJoules 
904314fbfa1STim Northover       switch (CS.getKind()) {
9055cf37d8bSFangrui Song         case ConversionSpecifier::bArg:
9065cf37d8bSFangrui Song         case ConversionSpecifier::BArg:
907314fbfa1STim Northover         case ConversionSpecifier::dArg:
908314fbfa1STim Northover         case ConversionSpecifier::DArg:
909314fbfa1STim Northover         case ConversionSpecifier::iArg:
910314fbfa1STim Northover         case ConversionSpecifier::oArg:
911314fbfa1STim Northover         case ConversionSpecifier::OArg:
912314fbfa1STim Northover         case ConversionSpecifier::uArg:
913314fbfa1STim Northover         case ConversionSpecifier::UArg:
914314fbfa1STim Northover         case ConversionSpecifier::xArg:
915314fbfa1STim Northover         case ConversionSpecifier::XArg:
916314fbfa1STim Northover         case ConversionSpecifier::nArg:
917314fbfa1STim Northover         case ConversionSpecifier::cArg:
918314fbfa1STim Northover         case ConversionSpecifier::sArg:
919314fbfa1STim Northover         case ConversionSpecifier::ScanListArg:
920314fbfa1STim Northover         case ConversionSpecifier::ZArg:
921314fbfa1STim Northover           return true;
922314fbfa1STim Northover         case ConversionSpecifier::FreeBSDrArg:
923314fbfa1STim Northover         case ConversionSpecifier::FreeBSDyArg:
924b2c6251cSPaul Robinson           return Target.getTriple().isOSFreeBSD() || Target.getTriple().isPS();
925314fbfa1STim Northover         default:
926314fbfa1STim Northover           return false;
927314fbfa1STim Northover       }
928314fbfa1STim Northover 
929314fbfa1STim Northover     case LengthModifier::AsLongDouble:
930314fbfa1STim Northover       switch (CS.getKind()) {
931314fbfa1STim Northover         case ConversionSpecifier::aArg:
932314fbfa1STim Northover         case ConversionSpecifier::AArg:
933314fbfa1STim Northover         case ConversionSpecifier::fArg:
934314fbfa1STim Northover         case ConversionSpecifier::FArg:
935314fbfa1STim Northover         case ConversionSpecifier::eArg:
936314fbfa1STim Northover         case ConversionSpecifier::EArg:
937314fbfa1STim Northover         case ConversionSpecifier::gArg:
938314fbfa1STim Northover         case ConversionSpecifier::GArg:
939314fbfa1STim Northover           return true;
940314fbfa1STim Northover         // GNU libc extension.
941314fbfa1STim Northover         case ConversionSpecifier::dArg:
942314fbfa1STim Northover         case ConversionSpecifier::iArg:
943314fbfa1STim Northover         case ConversionSpecifier::oArg:
944314fbfa1STim Northover         case ConversionSpecifier::uArg:
945314fbfa1STim Northover         case ConversionSpecifier::xArg:
946314fbfa1STim Northover         case ConversionSpecifier::XArg:
947314fbfa1STim Northover           return !Target.getTriple().isOSDarwin() &&
948314fbfa1STim Northover                  !Target.getTriple().isOSWindows();
949314fbfa1STim Northover         default:
950314fbfa1STim Northover           return false;
951314fbfa1STim Northover       }
952314fbfa1STim Northover 
953314fbfa1STim Northover     case LengthModifier::AsAllocate:
954314fbfa1STim Northover       switch (CS.getKind()) {
955314fbfa1STim Northover         case ConversionSpecifier::sArg:
956314fbfa1STim Northover         case ConversionSpecifier::SArg:
957314fbfa1STim Northover         case ConversionSpecifier::ScanListArg:
958314fbfa1STim Northover           return true;
959314fbfa1STim Northover         default:
960314fbfa1STim Northover           return false;
961314fbfa1STim Northover       }
962314fbfa1STim Northover 
963314fbfa1STim Northover     case LengthModifier::AsMAllocate:
964314fbfa1STim Northover       switch (CS.getKind()) {
965314fbfa1STim Northover         case ConversionSpecifier::cArg:
966314fbfa1STim Northover         case ConversionSpecifier::CArg:
967314fbfa1STim Northover         case ConversionSpecifier::sArg:
968314fbfa1STim Northover         case ConversionSpecifier::SArg:
969314fbfa1STim Northover         case ConversionSpecifier::ScanListArg:
970314fbfa1STim Northover           return true;
971314fbfa1STim Northover         default:
972314fbfa1STim Northover           return false;
973314fbfa1STim Northover       }
974314fbfa1STim Northover     case LengthModifier::AsInt32:
975314fbfa1STim Northover     case LengthModifier::AsInt3264:
976314fbfa1STim Northover     case LengthModifier::AsInt64:
977314fbfa1STim Northover       switch (CS.getKind()) {
978314fbfa1STim Northover         case ConversionSpecifier::dArg:
979314fbfa1STim Northover         case ConversionSpecifier::iArg:
980314fbfa1STim Northover         case ConversionSpecifier::oArg:
981314fbfa1STim Northover         case ConversionSpecifier::uArg:
982314fbfa1STim Northover         case ConversionSpecifier::xArg:
983314fbfa1STim Northover         case ConversionSpecifier::XArg:
984314fbfa1STim Northover           return Target.getTriple().isOSMSVCRT();
985314fbfa1STim Northover         default:
986314fbfa1STim Northover           return false;
987314fbfa1STim Northover       }
988314fbfa1STim Northover     case LengthModifier::AsWide:
989314fbfa1STim Northover       switch (CS.getKind()) {
990314fbfa1STim Northover         case ConversionSpecifier::cArg:
991314fbfa1STim Northover         case ConversionSpecifier::CArg:
992314fbfa1STim Northover         case ConversionSpecifier::sArg:
993314fbfa1STim Northover         case ConversionSpecifier::SArg:
994314fbfa1STim Northover         case ConversionSpecifier::ZArg:
995314fbfa1STim Northover           return Target.getTriple().isOSMSVCRT();
996314fbfa1STim Northover         default:
997314fbfa1STim Northover           return false;
998314fbfa1STim Northover       }
999314fbfa1STim Northover   }
1000314fbfa1STim Northover   llvm_unreachable("Invalid LengthModifier Kind!");
1001314fbfa1STim Northover }
1002314fbfa1STim Northover 
1003314fbfa1STim Northover bool FormatSpecifier::hasStandardLengthModifier() const {
1004314fbfa1STim Northover   switch (LM.getKind()) {
1005314fbfa1STim Northover     case LengthModifier::None:
1006314fbfa1STim Northover     case LengthModifier::AsChar:
1007314fbfa1STim Northover     case LengthModifier::AsShort:
1008314fbfa1STim Northover     case LengthModifier::AsLong:
1009314fbfa1STim Northover     case LengthModifier::AsLongLong:
1010314fbfa1STim Northover     case LengthModifier::AsIntMax:
1011314fbfa1STim Northover     case LengthModifier::AsSizeT:
1012314fbfa1STim Northover     case LengthModifier::AsPtrDiff:
1013314fbfa1STim Northover     case LengthModifier::AsLongDouble:
1014314fbfa1STim Northover       return true;
1015314fbfa1STim Northover     case LengthModifier::AsAllocate:
1016314fbfa1STim Northover     case LengthModifier::AsMAllocate:
1017314fbfa1STim Northover     case LengthModifier::AsQuad:
1018314fbfa1STim Northover     case LengthModifier::AsInt32:
1019314fbfa1STim Northover     case LengthModifier::AsInt3264:
1020314fbfa1STim Northover     case LengthModifier::AsInt64:
1021314fbfa1STim Northover     case LengthModifier::AsWide:
102258fc8082SMatt Arsenault     case LengthModifier::AsShortLong: // ???
1023314fbfa1STim Northover       return false;
1024314fbfa1STim Northover   }
1025314fbfa1STim Northover   llvm_unreachable("Invalid LengthModifier Kind!");
1026314fbfa1STim Northover }
1027314fbfa1STim Northover 
1028314fbfa1STim Northover bool FormatSpecifier::hasStandardConversionSpecifier(
1029314fbfa1STim Northover     const LangOptions &LangOpt) const {
1030314fbfa1STim Northover   switch (CS.getKind()) {
103188501dc7SFangrui Song     case ConversionSpecifier::bArg:
103288501dc7SFangrui Song     case ConversionSpecifier::BArg:
1033314fbfa1STim Northover     case ConversionSpecifier::cArg:
1034314fbfa1STim Northover     case ConversionSpecifier::dArg:
1035314fbfa1STim Northover     case ConversionSpecifier::iArg:
1036314fbfa1STim Northover     case ConversionSpecifier::oArg:
1037314fbfa1STim Northover     case ConversionSpecifier::uArg:
1038314fbfa1STim Northover     case ConversionSpecifier::xArg:
1039314fbfa1STim Northover     case ConversionSpecifier::XArg:
1040314fbfa1STim Northover     case ConversionSpecifier::fArg:
1041314fbfa1STim Northover     case ConversionSpecifier::FArg:
1042314fbfa1STim Northover     case ConversionSpecifier::eArg:
1043314fbfa1STim Northover     case ConversionSpecifier::EArg:
1044314fbfa1STim Northover     case ConversionSpecifier::gArg:
1045314fbfa1STim Northover     case ConversionSpecifier::GArg:
1046314fbfa1STim Northover     case ConversionSpecifier::aArg:
1047314fbfa1STim Northover     case ConversionSpecifier::AArg:
1048314fbfa1STim Northover     case ConversionSpecifier::sArg:
1049314fbfa1STim Northover     case ConversionSpecifier::pArg:
1050314fbfa1STim Northover     case ConversionSpecifier::nArg:
1051314fbfa1STim Northover     case ConversionSpecifier::ObjCObjArg:
1052314fbfa1STim Northover     case ConversionSpecifier::ScanListArg:
1053314fbfa1STim Northover     case ConversionSpecifier::PercentArg:
1054314fbfa1STim Northover     case ConversionSpecifier::PArg:
1055314fbfa1STim Northover       return true;
1056314fbfa1STim Northover     case ConversionSpecifier::CArg:
1057314fbfa1STim Northover     case ConversionSpecifier::SArg:
1058314fbfa1STim Northover       return LangOpt.ObjC;
1059314fbfa1STim Northover     case ConversionSpecifier::InvalidSpecifier:
1060314fbfa1STim Northover     case ConversionSpecifier::FreeBSDbArg:
1061314fbfa1STim Northover     case ConversionSpecifier::FreeBSDDArg:
1062314fbfa1STim Northover     case ConversionSpecifier::FreeBSDrArg:
1063314fbfa1STim Northover     case ConversionSpecifier::FreeBSDyArg:
1064314fbfa1STim Northover     case ConversionSpecifier::PrintErrno:
1065314fbfa1STim Northover     case ConversionSpecifier::DArg:
1066314fbfa1STim Northover     case ConversionSpecifier::OArg:
1067314fbfa1STim Northover     case ConversionSpecifier::UArg:
1068314fbfa1STim Northover     case ConversionSpecifier::ZArg:
1069314fbfa1STim Northover       return false;
107040ba1f60SPiJoules     case ConversionSpecifier::rArg:
107140ba1f60SPiJoules     case ConversionSpecifier::RArg:
107240ba1f60SPiJoules     case ConversionSpecifier::kArg:
107340ba1f60SPiJoules     case ConversionSpecifier::KArg:
107440ba1f60SPiJoules       return LangOpt.FixedPoint;
1075314fbfa1STim Northover   }
1076314fbfa1STim Northover   llvm_unreachable("Invalid ConversionSpecifier Kind!");
1077314fbfa1STim Northover }
1078314fbfa1STim Northover 
1079314fbfa1STim Northover bool FormatSpecifier::hasStandardLengthConversionCombination() const {
1080314fbfa1STim Northover   if (LM.getKind() == LengthModifier::AsLongDouble) {
1081314fbfa1STim Northover     switch(CS.getKind()) {
1082314fbfa1STim Northover         case ConversionSpecifier::dArg:
1083314fbfa1STim Northover         case ConversionSpecifier::iArg:
1084314fbfa1STim Northover         case ConversionSpecifier::oArg:
1085314fbfa1STim Northover         case ConversionSpecifier::uArg:
1086314fbfa1STim Northover         case ConversionSpecifier::xArg:
1087314fbfa1STim Northover         case ConversionSpecifier::XArg:
1088314fbfa1STim Northover           return false;
1089314fbfa1STim Northover         default:
1090314fbfa1STim Northover           return true;
1091314fbfa1STim Northover     }
1092314fbfa1STim Northover   }
1093314fbfa1STim Northover   return true;
1094314fbfa1STim Northover }
1095314fbfa1STim Northover 
10966ad0788cSKazu Hirata std::optional<LengthModifier>
10976ad0788cSKazu Hirata FormatSpecifier::getCorrectedLengthModifier() const {
1098314fbfa1STim Northover   if (CS.isAnyIntArg() || CS.getKind() == ConversionSpecifier::nArg) {
1099314fbfa1STim Northover     if (LM.getKind() == LengthModifier::AsLongDouble ||
1100314fbfa1STim Northover         LM.getKind() == LengthModifier::AsQuad) {
1101314fbfa1STim Northover       LengthModifier FixedLM(LM);
1102314fbfa1STim Northover       FixedLM.setKind(LengthModifier::AsLongLong);
1103314fbfa1STim Northover       return FixedLM;
1104314fbfa1STim Northover     }
1105314fbfa1STim Northover   }
1106314fbfa1STim Northover 
1107e31564afSKazu Hirata   return std::nullopt;
1108314fbfa1STim Northover }
1109314fbfa1STim Northover 
1110314fbfa1STim Northover bool FormatSpecifier::namedTypeToLengthModifier(QualType QT,
1111314fbfa1STim Northover                                                 LengthModifier &LM) {
111215f3cd6bSMatheus Izvekov   for (/**/; const auto *TT = QT->getAs<TypedefType>();
111315f3cd6bSMatheus Izvekov        QT = TT->getDecl()->getUnderlyingType()) {
111415f3cd6bSMatheus Izvekov     const TypedefNameDecl *Typedef = TT->getDecl();
1115314fbfa1STim Northover     const IdentifierInfo *Identifier = Typedef->getIdentifier();
1116314fbfa1STim Northover     if (Identifier->getName() == "size_t") {
1117314fbfa1STim Northover       LM.setKind(LengthModifier::AsSizeT);
1118314fbfa1STim Northover       return true;
1119314fbfa1STim Northover     } else if (Identifier->getName() == "ssize_t") {
1120314fbfa1STim Northover       // Not C99, but common in Unix.
1121314fbfa1STim Northover       LM.setKind(LengthModifier::AsSizeT);
1122314fbfa1STim Northover       return true;
1123314fbfa1STim Northover     } else if (Identifier->getName() == "intmax_t") {
1124314fbfa1STim Northover       LM.setKind(LengthModifier::AsIntMax);
1125314fbfa1STim Northover       return true;
1126314fbfa1STim Northover     } else if (Identifier->getName() == "uintmax_t") {
1127314fbfa1STim Northover       LM.setKind(LengthModifier::AsIntMax);
1128314fbfa1STim Northover       return true;
1129314fbfa1STim Northover     } else if (Identifier->getName() == "ptrdiff_t") {
1130314fbfa1STim Northover       LM.setKind(LengthModifier::AsPtrDiff);
1131314fbfa1STim Northover       return true;
1132314fbfa1STim Northover     }
1133314fbfa1STim Northover   }
1134314fbfa1STim Northover   return false;
1135314fbfa1STim Northover }
1136