xref: /openbsd-src/gnu/llvm/clang/lib/AST/FormatString.cpp (revision 7a9b00ce7716f522d49aa36666c74a71cd12203a)
1e5dd7070Spatrick // FormatString.cpp - Common stuff for handling printf/scanf formats -*- C++ -*-
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // Shared details for processing format strings of printf and scanf
10e5dd7070Spatrick // (and friends).
11e5dd7070Spatrick //
12e5dd7070Spatrick //===----------------------------------------------------------------------===//
13e5dd7070Spatrick 
14e5dd7070Spatrick #include "FormatStringParsing.h"
15e5dd7070Spatrick #include "clang/Basic/LangOptions.h"
16e5dd7070Spatrick #include "clang/Basic/TargetInfo.h"
17e5dd7070Spatrick #include "llvm/Support/ConvertUTF.h"
18*7a9b00ceSrobert #include <optional>
19e5dd7070Spatrick 
20e5dd7070Spatrick using clang::analyze_format_string::ArgType;
21e5dd7070Spatrick using clang::analyze_format_string::FormatStringHandler;
22e5dd7070Spatrick using clang::analyze_format_string::FormatSpecifier;
23e5dd7070Spatrick using clang::analyze_format_string::LengthModifier;
24e5dd7070Spatrick using clang::analyze_format_string::OptionalAmount;
25e5dd7070Spatrick using clang::analyze_format_string::ConversionSpecifier;
26e5dd7070Spatrick using namespace clang;
27e5dd7070Spatrick 
28e5dd7070Spatrick // Key function to FormatStringHandler.
~FormatStringHandler()29e5dd7070Spatrick FormatStringHandler::~FormatStringHandler() {}
30e5dd7070Spatrick 
31e5dd7070Spatrick //===----------------------------------------------------------------------===//
32e5dd7070Spatrick // Functions for parsing format strings components in both printf and
33e5dd7070Spatrick // scanf format strings.
34e5dd7070Spatrick //===----------------------------------------------------------------------===//
35e5dd7070Spatrick 
36e5dd7070Spatrick OptionalAmount
ParseAmount(const char * & Beg,const char * E)37e5dd7070Spatrick clang::analyze_format_string::ParseAmount(const char *&Beg, const char *E) {
38e5dd7070Spatrick   const char *I = Beg;
39e5dd7070Spatrick   UpdateOnReturn <const char*> UpdateBeg(Beg, I);
40e5dd7070Spatrick 
41e5dd7070Spatrick   unsigned accumulator = 0;
42e5dd7070Spatrick   bool hasDigits = false;
43e5dd7070Spatrick 
44e5dd7070Spatrick   for ( ; I != E; ++I) {
45e5dd7070Spatrick     char c = *I;
46e5dd7070Spatrick     if (c >= '0' && c <= '9') {
47e5dd7070Spatrick       hasDigits = true;
48e5dd7070Spatrick       accumulator = (accumulator * 10) + (c - '0');
49e5dd7070Spatrick       continue;
50e5dd7070Spatrick     }
51e5dd7070Spatrick 
52e5dd7070Spatrick     if (hasDigits)
53e5dd7070Spatrick       return OptionalAmount(OptionalAmount::Constant, accumulator, Beg, I - Beg,
54e5dd7070Spatrick           false);
55e5dd7070Spatrick 
56e5dd7070Spatrick     break;
57e5dd7070Spatrick   }
58e5dd7070Spatrick 
59e5dd7070Spatrick   return OptionalAmount();
60e5dd7070Spatrick }
61e5dd7070Spatrick 
62e5dd7070Spatrick OptionalAmount
ParseNonPositionAmount(const char * & Beg,const char * E,unsigned & argIndex)63e5dd7070Spatrick clang::analyze_format_string::ParseNonPositionAmount(const char *&Beg,
64e5dd7070Spatrick                                                      const char *E,
65e5dd7070Spatrick                                                      unsigned &argIndex) {
66e5dd7070Spatrick   if (*Beg == '*') {
67e5dd7070Spatrick     ++Beg;
68e5dd7070Spatrick     return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg, 0, false);
69e5dd7070Spatrick   }
70e5dd7070Spatrick 
71e5dd7070Spatrick   return ParseAmount(Beg, E);
72e5dd7070Spatrick }
73e5dd7070Spatrick 
74e5dd7070Spatrick OptionalAmount
ParsePositionAmount(FormatStringHandler & H,const char * Start,const char * & Beg,const char * E,PositionContext p)75e5dd7070Spatrick clang::analyze_format_string::ParsePositionAmount(FormatStringHandler &H,
76e5dd7070Spatrick                                                   const char *Start,
77e5dd7070Spatrick                                                   const char *&Beg,
78e5dd7070Spatrick                                                   const char *E,
79e5dd7070Spatrick                                                   PositionContext p) {
80e5dd7070Spatrick   if (*Beg == '*') {
81e5dd7070Spatrick     const char *I = Beg + 1;
82e5dd7070Spatrick     const OptionalAmount &Amt = ParseAmount(I, E);
83e5dd7070Spatrick 
84e5dd7070Spatrick     if (Amt.getHowSpecified() == OptionalAmount::NotSpecified) {
85e5dd7070Spatrick       H.HandleInvalidPosition(Beg, I - Beg, p);
86e5dd7070Spatrick       return OptionalAmount(false);
87e5dd7070Spatrick     }
88e5dd7070Spatrick 
89e5dd7070Spatrick     if (I == E) {
90e5dd7070Spatrick       // No more characters left?
91e5dd7070Spatrick       H.HandleIncompleteSpecifier(Start, E - Start);
92e5dd7070Spatrick       return OptionalAmount(false);
93e5dd7070Spatrick     }
94e5dd7070Spatrick 
95e5dd7070Spatrick     assert(Amt.getHowSpecified() == OptionalAmount::Constant);
96e5dd7070Spatrick 
97e5dd7070Spatrick     if (*I == '$') {
98e5dd7070Spatrick       // Handle positional arguments
99e5dd7070Spatrick 
100e5dd7070Spatrick       // Special case: '*0$', since this is an easy mistake.
101e5dd7070Spatrick       if (Amt.getConstantAmount() == 0) {
102e5dd7070Spatrick         H.HandleZeroPosition(Beg, I - Beg + 1);
103e5dd7070Spatrick         return OptionalAmount(false);
104e5dd7070Spatrick       }
105e5dd7070Spatrick 
106e5dd7070Spatrick       const char *Tmp = Beg;
107e5dd7070Spatrick       Beg = ++I;
108e5dd7070Spatrick 
109e5dd7070Spatrick       return OptionalAmount(OptionalAmount::Arg, Amt.getConstantAmount() - 1,
110e5dd7070Spatrick                             Tmp, 0, true);
111e5dd7070Spatrick     }
112e5dd7070Spatrick 
113e5dd7070Spatrick     H.HandleInvalidPosition(Beg, I - Beg, p);
114e5dd7070Spatrick     return OptionalAmount(false);
115e5dd7070Spatrick   }
116e5dd7070Spatrick 
117e5dd7070Spatrick   return ParseAmount(Beg, E);
118e5dd7070Spatrick }
119e5dd7070Spatrick 
120e5dd7070Spatrick 
121e5dd7070Spatrick bool
ParseFieldWidth(FormatStringHandler & H,FormatSpecifier & CS,const char * Start,const char * & Beg,const char * E,unsigned * argIndex)122e5dd7070Spatrick clang::analyze_format_string::ParseFieldWidth(FormatStringHandler &H,
123e5dd7070Spatrick                                               FormatSpecifier &CS,
124e5dd7070Spatrick                                               const char *Start,
125e5dd7070Spatrick                                               const char *&Beg, const char *E,
126e5dd7070Spatrick                                               unsigned *argIndex) {
127e5dd7070Spatrick   // FIXME: Support negative field widths.
128e5dd7070Spatrick   if (argIndex) {
129e5dd7070Spatrick     CS.setFieldWidth(ParseNonPositionAmount(Beg, E, *argIndex));
130e5dd7070Spatrick   }
131e5dd7070Spatrick   else {
132e5dd7070Spatrick     const OptionalAmount Amt =
133e5dd7070Spatrick       ParsePositionAmount(H, Start, Beg, E,
134e5dd7070Spatrick                           analyze_format_string::FieldWidthPos);
135e5dd7070Spatrick 
136e5dd7070Spatrick     if (Amt.isInvalid())
137e5dd7070Spatrick       return true;
138e5dd7070Spatrick     CS.setFieldWidth(Amt);
139e5dd7070Spatrick   }
140e5dd7070Spatrick   return false;
141e5dd7070Spatrick }
142e5dd7070Spatrick 
143e5dd7070Spatrick bool
ParseArgPosition(FormatStringHandler & H,FormatSpecifier & FS,const char * Start,const char * & Beg,const char * E)144e5dd7070Spatrick clang::analyze_format_string::ParseArgPosition(FormatStringHandler &H,
145e5dd7070Spatrick                                                FormatSpecifier &FS,
146e5dd7070Spatrick                                                const char *Start,
147e5dd7070Spatrick                                                const char *&Beg,
148e5dd7070Spatrick                                                const char *E) {
149e5dd7070Spatrick   const char *I = Beg;
150e5dd7070Spatrick 
151e5dd7070Spatrick   const OptionalAmount &Amt = ParseAmount(I, E);
152e5dd7070Spatrick 
153e5dd7070Spatrick   if (I == E) {
154e5dd7070Spatrick     // No more characters left?
155e5dd7070Spatrick     H.HandleIncompleteSpecifier(Start, E - Start);
156e5dd7070Spatrick     return true;
157e5dd7070Spatrick   }
158e5dd7070Spatrick 
159e5dd7070Spatrick   if (Amt.getHowSpecified() == OptionalAmount::Constant && *(I++) == '$') {
160e5dd7070Spatrick     // Warn that positional arguments are non-standard.
161e5dd7070Spatrick     H.HandlePosition(Start, I - Start);
162e5dd7070Spatrick 
163e5dd7070Spatrick     // Special case: '%0$', since this is an easy mistake.
164e5dd7070Spatrick     if (Amt.getConstantAmount() == 0) {
165e5dd7070Spatrick       H.HandleZeroPosition(Start, I - Start);
166e5dd7070Spatrick       return true;
167e5dd7070Spatrick     }
168e5dd7070Spatrick 
169e5dd7070Spatrick     FS.setArgIndex(Amt.getConstantAmount() - 1);
170e5dd7070Spatrick     FS.setUsesPositionalArg();
171e5dd7070Spatrick     // Update the caller's pointer if we decided to consume
172e5dd7070Spatrick     // these characters.
173e5dd7070Spatrick     Beg = I;
174e5dd7070Spatrick     return false;
175e5dd7070Spatrick   }
176e5dd7070Spatrick 
177e5dd7070Spatrick   return false;
178e5dd7070Spatrick }
179e5dd7070Spatrick 
180e5dd7070Spatrick bool
ParseVectorModifier(FormatStringHandler & H,FormatSpecifier & FS,const char * & I,const char * E,const LangOptions & LO)181e5dd7070Spatrick clang::analyze_format_string::ParseVectorModifier(FormatStringHandler &H,
182e5dd7070Spatrick                                                   FormatSpecifier &FS,
183e5dd7070Spatrick                                                   const char *&I,
184e5dd7070Spatrick                                                   const char *E,
185e5dd7070Spatrick                                                   const LangOptions &LO) {
186e5dd7070Spatrick   if (!LO.OpenCL)
187e5dd7070Spatrick     return false;
188e5dd7070Spatrick 
189e5dd7070Spatrick   const char *Start = I;
190e5dd7070Spatrick   if (*I == 'v') {
191e5dd7070Spatrick     ++I;
192e5dd7070Spatrick 
193e5dd7070Spatrick     if (I == E) {
194e5dd7070Spatrick       H.HandleIncompleteSpecifier(Start, E - Start);
195e5dd7070Spatrick       return true;
196e5dd7070Spatrick     }
197e5dd7070Spatrick 
198e5dd7070Spatrick     OptionalAmount NumElts = ParseAmount(I, E);
199e5dd7070Spatrick     if (NumElts.getHowSpecified() != OptionalAmount::Constant) {
200e5dd7070Spatrick       H.HandleIncompleteSpecifier(Start, E - Start);
201e5dd7070Spatrick       return true;
202e5dd7070Spatrick     }
203e5dd7070Spatrick 
204e5dd7070Spatrick     FS.setVectorNumElts(NumElts);
205e5dd7070Spatrick   }
206e5dd7070Spatrick 
207e5dd7070Spatrick   return false;
208e5dd7070Spatrick }
209e5dd7070Spatrick 
210e5dd7070Spatrick bool
ParseLengthModifier(FormatSpecifier & FS,const char * & I,const char * E,const LangOptions & LO,bool IsScanf)211e5dd7070Spatrick clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,
212e5dd7070Spatrick                                                   const char *&I,
213e5dd7070Spatrick                                                   const char *E,
214e5dd7070Spatrick                                                   const LangOptions &LO,
215e5dd7070Spatrick                                                   bool IsScanf) {
216e5dd7070Spatrick   LengthModifier::Kind lmKind = LengthModifier::None;
217e5dd7070Spatrick   const char *lmPosition = I;
218e5dd7070Spatrick   switch (*I) {
219e5dd7070Spatrick     default:
220e5dd7070Spatrick       return false;
221e5dd7070Spatrick     case 'h':
222e5dd7070Spatrick       ++I;
223e5dd7070Spatrick       if (I != E && *I == 'h') {
224e5dd7070Spatrick         ++I;
225e5dd7070Spatrick         lmKind = LengthModifier::AsChar;
226e5dd7070Spatrick       } else if (I != E && *I == 'l' && LO.OpenCL) {
227e5dd7070Spatrick         ++I;
228e5dd7070Spatrick         lmKind = LengthModifier::AsShortLong;
229e5dd7070Spatrick       } else {
230e5dd7070Spatrick         lmKind = LengthModifier::AsShort;
231e5dd7070Spatrick       }
232e5dd7070Spatrick       break;
233e5dd7070Spatrick     case 'l':
234e5dd7070Spatrick       ++I;
235e5dd7070Spatrick       if (I != E && *I == 'l') {
236e5dd7070Spatrick         ++I;
237e5dd7070Spatrick         lmKind = LengthModifier::AsLongLong;
238e5dd7070Spatrick       } else {
239e5dd7070Spatrick         lmKind = LengthModifier::AsLong;
240e5dd7070Spatrick       }
241e5dd7070Spatrick       break;
242e5dd7070Spatrick     case 'j': lmKind = LengthModifier::AsIntMax;     ++I; break;
243e5dd7070Spatrick     case 'z': lmKind = LengthModifier::AsSizeT;      ++I; break;
244e5dd7070Spatrick     case 't': lmKind = LengthModifier::AsPtrDiff;    ++I; break;
245e5dd7070Spatrick     case 'L': lmKind = LengthModifier::AsLongDouble; ++I; break;
246e5dd7070Spatrick     case 'q': lmKind = LengthModifier::AsQuad;       ++I; break;
247e5dd7070Spatrick     case 'a':
248e5dd7070Spatrick       if (IsScanf && !LO.C99 && !LO.CPlusPlus11) {
249e5dd7070Spatrick         // For scanf in C90, look at the next character to see if this should
250e5dd7070Spatrick         // be parsed as the GNU extension 'a' length modifier. If not, this
251e5dd7070Spatrick         // will be parsed as a conversion specifier.
252e5dd7070Spatrick         ++I;
253e5dd7070Spatrick         if (I != E && (*I == 's' || *I == 'S' || *I == '[')) {
254e5dd7070Spatrick           lmKind = LengthModifier::AsAllocate;
255e5dd7070Spatrick           break;
256e5dd7070Spatrick         }
257e5dd7070Spatrick         --I;
258e5dd7070Spatrick       }
259e5dd7070Spatrick       return false;
260e5dd7070Spatrick     case 'm':
261e5dd7070Spatrick       if (IsScanf) {
262e5dd7070Spatrick         lmKind = LengthModifier::AsMAllocate;
263e5dd7070Spatrick         ++I;
264e5dd7070Spatrick         break;
265e5dd7070Spatrick       }
266e5dd7070Spatrick       return false;
267e5dd7070Spatrick     // printf: AsInt64, AsInt32, AsInt3264
268e5dd7070Spatrick     // scanf:  AsInt64
269e5dd7070Spatrick     case 'I':
270e5dd7070Spatrick       if (I + 1 != E && I + 2 != E) {
271e5dd7070Spatrick         if (I[1] == '6' && I[2] == '4') {
272e5dd7070Spatrick           I += 3;
273e5dd7070Spatrick           lmKind = LengthModifier::AsInt64;
274e5dd7070Spatrick           break;
275e5dd7070Spatrick         }
276e5dd7070Spatrick         if (IsScanf)
277e5dd7070Spatrick           return false;
278e5dd7070Spatrick 
279e5dd7070Spatrick         if (I[1] == '3' && I[2] == '2') {
280e5dd7070Spatrick           I += 3;
281e5dd7070Spatrick           lmKind = LengthModifier::AsInt32;
282e5dd7070Spatrick           break;
283e5dd7070Spatrick         }
284e5dd7070Spatrick       }
285e5dd7070Spatrick       ++I;
286e5dd7070Spatrick       lmKind = LengthModifier::AsInt3264;
287e5dd7070Spatrick       break;
288e5dd7070Spatrick     case 'w':
289e5dd7070Spatrick       lmKind = LengthModifier::AsWide; ++I; break;
290e5dd7070Spatrick   }
291e5dd7070Spatrick   LengthModifier lm(lmPosition, lmKind);
292e5dd7070Spatrick   FS.setLengthModifier(lm);
293e5dd7070Spatrick   return true;
294e5dd7070Spatrick }
295e5dd7070Spatrick 
ParseUTF8InvalidSpecifier(const char * SpecifierBegin,const char * FmtStrEnd,unsigned & Len)296e5dd7070Spatrick bool clang::analyze_format_string::ParseUTF8InvalidSpecifier(
297e5dd7070Spatrick     const char *SpecifierBegin, const char *FmtStrEnd, unsigned &Len) {
298e5dd7070Spatrick   if (SpecifierBegin + 1 >= FmtStrEnd)
299e5dd7070Spatrick     return false;
300e5dd7070Spatrick 
301e5dd7070Spatrick   const llvm::UTF8 *SB =
302e5dd7070Spatrick       reinterpret_cast<const llvm::UTF8 *>(SpecifierBegin + 1);
303e5dd7070Spatrick   const llvm::UTF8 *SE = reinterpret_cast<const llvm::UTF8 *>(FmtStrEnd);
304e5dd7070Spatrick   const char FirstByte = *SB;
305e5dd7070Spatrick 
306e5dd7070Spatrick   // If the invalid specifier is a multibyte UTF-8 string, return the
307e5dd7070Spatrick   // total length accordingly so that the conversion specifier can be
308e5dd7070Spatrick   // properly updated to reflect a complete UTF-8 specifier.
309e5dd7070Spatrick   unsigned NumBytes = llvm::getNumBytesForUTF8(FirstByte);
310e5dd7070Spatrick   if (NumBytes == 1)
311e5dd7070Spatrick     return false;
312e5dd7070Spatrick   if (SB + NumBytes > SE)
313e5dd7070Spatrick     return false;
314e5dd7070Spatrick 
315e5dd7070Spatrick   Len = NumBytes + 1;
316e5dd7070Spatrick   return true;
317e5dd7070Spatrick }
318e5dd7070Spatrick 
319e5dd7070Spatrick //===----------------------------------------------------------------------===//
320e5dd7070Spatrick // Methods on ArgType.
321e5dd7070Spatrick //===----------------------------------------------------------------------===//
322e5dd7070Spatrick 
323e5dd7070Spatrick clang::analyze_format_string::ArgType::MatchKind
matchesType(ASTContext & C,QualType argTy) const324e5dd7070Spatrick ArgType::matchesType(ASTContext &C, QualType argTy) const {
325*7a9b00ceSrobert   // When using the format attribute in C++, you can receive a function or an
326*7a9b00ceSrobert   // array that will necessarily decay to a pointer when passed to the final
327*7a9b00ceSrobert   // format consumer. Apply decay before type comparison.
328*7a9b00ceSrobert   if (argTy->canDecayToPointerType())
329*7a9b00ceSrobert     argTy = C.getDecayedType(argTy);
330*7a9b00ceSrobert 
331e5dd7070Spatrick   if (Ptr) {
332e5dd7070Spatrick     // It has to be a pointer.
333e5dd7070Spatrick     const PointerType *PT = argTy->getAs<PointerType>();
334e5dd7070Spatrick     if (!PT)
335e5dd7070Spatrick       return NoMatch;
336e5dd7070Spatrick 
337e5dd7070Spatrick     // We cannot write through a const qualified pointer.
338e5dd7070Spatrick     if (PT->getPointeeType().isConstQualified())
339e5dd7070Spatrick       return NoMatch;
340e5dd7070Spatrick 
341e5dd7070Spatrick     argTy = PT->getPointeeType();
342e5dd7070Spatrick   }
343e5dd7070Spatrick 
344e5dd7070Spatrick   switch (K) {
345e5dd7070Spatrick     case InvalidTy:
346e5dd7070Spatrick       llvm_unreachable("ArgType must be valid");
347e5dd7070Spatrick 
348e5dd7070Spatrick     case UnknownTy:
349e5dd7070Spatrick       return Match;
350e5dd7070Spatrick 
351e5dd7070Spatrick     case AnyCharTy: {
352*7a9b00ceSrobert       if (const auto *ETy = argTy->getAs<EnumType>()) {
353e5dd7070Spatrick         // If the enum is incomplete we know nothing about the underlying type.
354e5dd7070Spatrick         // Assume that it's 'int'.
355e5dd7070Spatrick         if (!ETy->getDecl()->isComplete())
356e5dd7070Spatrick           return NoMatch;
357e5dd7070Spatrick         argTy = ETy->getDecl()->getIntegerType();
358e5dd7070Spatrick       }
359e5dd7070Spatrick 
360*7a9b00ceSrobert       if (const auto *BT = argTy->getAs<BuiltinType>()) {
361*7a9b00ceSrobert         // The types are perfectly matched?
362e5dd7070Spatrick         switch (BT->getKind()) {
363e5dd7070Spatrick         default:
364e5dd7070Spatrick           break;
365e5dd7070Spatrick         case BuiltinType::Char_S:
366e5dd7070Spatrick         case BuiltinType::SChar:
367e5dd7070Spatrick         case BuiltinType::UChar:
368e5dd7070Spatrick         case BuiltinType::Char_U:
369e5dd7070Spatrick         case BuiltinType::Bool:
370e5dd7070Spatrick           return Match;
371e5dd7070Spatrick         }
372*7a9b00ceSrobert         // "Partially matched" because of promotions?
373*7a9b00ceSrobert         if (!Ptr) {
374*7a9b00ceSrobert           switch (BT->getKind()) {
375*7a9b00ceSrobert           default:
376*7a9b00ceSrobert             break;
377*7a9b00ceSrobert           case BuiltinType::Int:
378*7a9b00ceSrobert           case BuiltinType::UInt:
379*7a9b00ceSrobert             return MatchPromotion;
380*7a9b00ceSrobert           case BuiltinType::Short:
381*7a9b00ceSrobert           case BuiltinType::UShort:
382*7a9b00ceSrobert           case BuiltinType::WChar_S:
383*7a9b00ceSrobert           case BuiltinType::WChar_U:
384*7a9b00ceSrobert             return NoMatchPromotionTypeConfusion;
385*7a9b00ceSrobert           }
386*7a9b00ceSrobert         }
387*7a9b00ceSrobert       }
388e5dd7070Spatrick       return NoMatch;
389e5dd7070Spatrick     }
390e5dd7070Spatrick 
391e5dd7070Spatrick     case SpecificTy: {
392e5dd7070Spatrick       if (const EnumType *ETy = argTy->getAs<EnumType>()) {
393e5dd7070Spatrick         // If the enum is incomplete we know nothing about the underlying type.
394e5dd7070Spatrick         // Assume that it's 'int'.
395e5dd7070Spatrick         if (!ETy->getDecl()->isComplete())
396e5dd7070Spatrick           argTy = C.IntTy;
397e5dd7070Spatrick         else
398e5dd7070Spatrick           argTy = ETy->getDecl()->getIntegerType();
399e5dd7070Spatrick       }
400e5dd7070Spatrick       argTy = C.getCanonicalType(argTy).getUnqualifiedType();
401e5dd7070Spatrick 
402e5dd7070Spatrick       if (T == argTy)
403e5dd7070Spatrick         return Match;
404*7a9b00ceSrobert       if (const auto *BT = argTy->getAs<BuiltinType>()) {
405*7a9b00ceSrobert         // Check if the only difference between them is signed vs unsigned
406*7a9b00ceSrobert         // if true, we consider they are compatible.
407e5dd7070Spatrick         switch (BT->getKind()) {
408e5dd7070Spatrick           default:
409e5dd7070Spatrick             break;
410e5dd7070Spatrick           case BuiltinType::Char_S:
411e5dd7070Spatrick           case BuiltinType::SChar:
412e5dd7070Spatrick           case BuiltinType::Char_U:
413e5dd7070Spatrick           case BuiltinType::UChar:
414e5dd7070Spatrick           case BuiltinType::Bool:
415e5dd7070Spatrick             if (T == C.UnsignedShortTy || T == C.ShortTy)
416e5dd7070Spatrick               return NoMatchTypeConfusion;
417*7a9b00ceSrobert             if (T == C.UnsignedCharTy || T == C.SignedCharTy)
418*7a9b00ceSrobert               return Match;
419*7a9b00ceSrobert             break;
420e5dd7070Spatrick           case BuiltinType::Short:
421*7a9b00ceSrobert             if (T == C.UnsignedShortTy)
422*7a9b00ceSrobert               return Match;
423*7a9b00ceSrobert             break;
424e5dd7070Spatrick           case BuiltinType::UShort:
425*7a9b00ceSrobert             if (T == C.ShortTy)
426*7a9b00ceSrobert               return Match;
427*7a9b00ceSrobert             break;
428e5dd7070Spatrick           case BuiltinType::Int:
429*7a9b00ceSrobert             if (T == C.UnsignedIntTy)
430*7a9b00ceSrobert               return Match;
431*7a9b00ceSrobert             break;
432e5dd7070Spatrick           case BuiltinType::UInt:
433*7a9b00ceSrobert             if (T == C.IntTy)
434*7a9b00ceSrobert               return Match;
435*7a9b00ceSrobert             break;
436e5dd7070Spatrick           case BuiltinType::Long:
437*7a9b00ceSrobert             if (T == C.UnsignedLongTy)
438*7a9b00ceSrobert               return Match;
439*7a9b00ceSrobert             break;
440e5dd7070Spatrick           case BuiltinType::ULong:
441*7a9b00ceSrobert             if (T == C.LongTy)
442*7a9b00ceSrobert               return Match;
443*7a9b00ceSrobert             break;
444e5dd7070Spatrick           case BuiltinType::LongLong:
445*7a9b00ceSrobert             if (T == C.UnsignedLongLongTy)
446*7a9b00ceSrobert               return Match;
447*7a9b00ceSrobert             break;
448e5dd7070Spatrick           case BuiltinType::ULongLong:
449*7a9b00ceSrobert             if (T == C.LongLongTy)
450*7a9b00ceSrobert               return Match;
451*7a9b00ceSrobert             break;
452*7a9b00ceSrobert           }
453*7a9b00ceSrobert           // "Partially matched" because of promotions?
454*7a9b00ceSrobert           if (!Ptr) {
455*7a9b00ceSrobert             switch (BT->getKind()) {
456*7a9b00ceSrobert             default:
457*7a9b00ceSrobert               break;
458*7a9b00ceSrobert             case BuiltinType::Int:
459*7a9b00ceSrobert             case BuiltinType::UInt:
460*7a9b00ceSrobert               if (T == C.SignedCharTy || T == C.UnsignedCharTy ||
461*7a9b00ceSrobert                   T == C.ShortTy || T == C.UnsignedShortTy || T == C.WCharTy ||
462*7a9b00ceSrobert                   T == C.WideCharTy)
463*7a9b00ceSrobert                 return MatchPromotion;
464*7a9b00ceSrobert               break;
465*7a9b00ceSrobert             case BuiltinType::Short:
466*7a9b00ceSrobert             case BuiltinType::UShort:
467*7a9b00ceSrobert               if (T == C.SignedCharTy || T == C.UnsignedCharTy)
468*7a9b00ceSrobert                 return NoMatchPromotionTypeConfusion;
469*7a9b00ceSrobert               break;
470*7a9b00ceSrobert             case BuiltinType::WChar_U:
471*7a9b00ceSrobert             case BuiltinType::WChar_S:
472*7a9b00ceSrobert               if (T != C.WCharTy && T != C.WideCharTy)
473*7a9b00ceSrobert                 return NoMatchPromotionTypeConfusion;
474*7a9b00ceSrobert             }
475*7a9b00ceSrobert           }
476e5dd7070Spatrick       }
477e5dd7070Spatrick       return NoMatch;
478e5dd7070Spatrick     }
479e5dd7070Spatrick 
480e5dd7070Spatrick     case CStrTy: {
481e5dd7070Spatrick       const PointerType *PT = argTy->getAs<PointerType>();
482e5dd7070Spatrick       if (!PT)
483e5dd7070Spatrick         return NoMatch;
484e5dd7070Spatrick       QualType pointeeTy = PT->getPointeeType();
485e5dd7070Spatrick       if (const BuiltinType *BT = pointeeTy->getAs<BuiltinType>())
486e5dd7070Spatrick         switch (BT->getKind()) {
487e5dd7070Spatrick           case BuiltinType::Char_U:
488e5dd7070Spatrick           case BuiltinType::UChar:
489e5dd7070Spatrick           case BuiltinType::Char_S:
490e5dd7070Spatrick           case BuiltinType::SChar:
491e5dd7070Spatrick             return Match;
492e5dd7070Spatrick           default:
493e5dd7070Spatrick             break;
494e5dd7070Spatrick         }
495e5dd7070Spatrick 
496e5dd7070Spatrick       return NoMatch;
497e5dd7070Spatrick     }
498e5dd7070Spatrick 
499e5dd7070Spatrick     case WCStrTy: {
500e5dd7070Spatrick       const PointerType *PT = argTy->getAs<PointerType>();
501e5dd7070Spatrick       if (!PT)
502e5dd7070Spatrick         return NoMatch;
503e5dd7070Spatrick       QualType pointeeTy =
504e5dd7070Spatrick         C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType();
505e5dd7070Spatrick       return pointeeTy == C.getWideCharType() ? Match : NoMatch;
506e5dd7070Spatrick     }
507e5dd7070Spatrick 
508e5dd7070Spatrick     case WIntTy: {
509e5dd7070Spatrick       QualType WInt = C.getCanonicalType(C.getWIntType()).getUnqualifiedType();
510e5dd7070Spatrick 
511e5dd7070Spatrick       if (C.getCanonicalType(argTy).getUnqualifiedType() == WInt)
512e5dd7070Spatrick         return Match;
513e5dd7070Spatrick 
514*7a9b00ceSrobert       QualType PromoArg = C.isPromotableIntegerType(argTy)
515e5dd7070Spatrick                               ? C.getPromotedIntegerType(argTy)
516e5dd7070Spatrick                               : argTy;
517e5dd7070Spatrick       PromoArg = C.getCanonicalType(PromoArg).getUnqualifiedType();
518e5dd7070Spatrick 
519e5dd7070Spatrick       // If the promoted argument is the corresponding signed type of the
520e5dd7070Spatrick       // wint_t type, then it should match.
521e5dd7070Spatrick       if (PromoArg->hasSignedIntegerRepresentation() &&
522e5dd7070Spatrick           C.getCorrespondingUnsignedType(PromoArg) == WInt)
523e5dd7070Spatrick         return Match;
524e5dd7070Spatrick 
525e5dd7070Spatrick       return WInt == PromoArg ? Match : NoMatch;
526e5dd7070Spatrick     }
527e5dd7070Spatrick 
528e5dd7070Spatrick     case CPointerTy:
529e5dd7070Spatrick       if (argTy->isVoidPointerType()) {
530e5dd7070Spatrick         return Match;
531e5dd7070Spatrick       } if (argTy->isPointerType() || argTy->isObjCObjectPointerType() ||
532e5dd7070Spatrick             argTy->isBlockPointerType() || argTy->isNullPtrType()) {
533e5dd7070Spatrick         return NoMatchPedantic;
534e5dd7070Spatrick       } else {
535e5dd7070Spatrick         return NoMatch;
536e5dd7070Spatrick       }
537e5dd7070Spatrick 
538e5dd7070Spatrick     case ObjCPointerTy: {
539e5dd7070Spatrick       if (argTy->getAs<ObjCObjectPointerType>() ||
540e5dd7070Spatrick           argTy->getAs<BlockPointerType>())
541e5dd7070Spatrick         return Match;
542e5dd7070Spatrick 
543e5dd7070Spatrick       // Handle implicit toll-free bridging.
544e5dd7070Spatrick       if (const PointerType *PT = argTy->getAs<PointerType>()) {
545e5dd7070Spatrick         // Things such as CFTypeRef are really just opaque pointers
546e5dd7070Spatrick         // to C structs representing CF types that can often be bridged
547e5dd7070Spatrick         // to Objective-C objects.  Since the compiler doesn't know which
548e5dd7070Spatrick         // structs can be toll-free bridged, we just accept them all.
549e5dd7070Spatrick         QualType pointee = PT->getPointeeType();
550e5dd7070Spatrick         if (pointee->getAsStructureType() || pointee->isVoidType())
551e5dd7070Spatrick           return Match;
552e5dd7070Spatrick       }
553e5dd7070Spatrick       return NoMatch;
554e5dd7070Spatrick     }
555e5dd7070Spatrick   }
556e5dd7070Spatrick 
557e5dd7070Spatrick   llvm_unreachable("Invalid ArgType Kind!");
558e5dd7070Spatrick }
559e5dd7070Spatrick 
makeVectorType(ASTContext & C,unsigned NumElts) const560e5dd7070Spatrick ArgType ArgType::makeVectorType(ASTContext &C, unsigned NumElts) const {
561e5dd7070Spatrick   // Check for valid vector element types.
562e5dd7070Spatrick   if (T.isNull())
563e5dd7070Spatrick     return ArgType::Invalid();
564e5dd7070Spatrick 
565e5dd7070Spatrick   QualType Vec = C.getExtVectorType(T, NumElts);
566e5dd7070Spatrick   return ArgType(Vec, Name);
567e5dd7070Spatrick }
568e5dd7070Spatrick 
getRepresentativeType(ASTContext & C) const569e5dd7070Spatrick QualType ArgType::getRepresentativeType(ASTContext &C) const {
570e5dd7070Spatrick   QualType Res;
571e5dd7070Spatrick   switch (K) {
572e5dd7070Spatrick     case InvalidTy:
573e5dd7070Spatrick       llvm_unreachable("No representative type for Invalid ArgType");
574e5dd7070Spatrick     case UnknownTy:
575e5dd7070Spatrick       llvm_unreachable("No representative type for Unknown ArgType");
576e5dd7070Spatrick     case AnyCharTy:
577e5dd7070Spatrick       Res = C.CharTy;
578e5dd7070Spatrick       break;
579e5dd7070Spatrick     case SpecificTy:
580e5dd7070Spatrick       Res = T;
581e5dd7070Spatrick       break;
582e5dd7070Spatrick     case CStrTy:
583e5dd7070Spatrick       Res = C.getPointerType(C.CharTy);
584e5dd7070Spatrick       break;
585e5dd7070Spatrick     case WCStrTy:
586e5dd7070Spatrick       Res = C.getPointerType(C.getWideCharType());
587e5dd7070Spatrick       break;
588e5dd7070Spatrick     case ObjCPointerTy:
589e5dd7070Spatrick       Res = C.ObjCBuiltinIdTy;
590e5dd7070Spatrick       break;
591e5dd7070Spatrick     case CPointerTy:
592e5dd7070Spatrick       Res = C.VoidPtrTy;
593e5dd7070Spatrick       break;
594e5dd7070Spatrick     case WIntTy: {
595e5dd7070Spatrick       Res = C.getWIntType();
596e5dd7070Spatrick       break;
597e5dd7070Spatrick     }
598e5dd7070Spatrick   }
599e5dd7070Spatrick 
600e5dd7070Spatrick   if (Ptr)
601e5dd7070Spatrick     Res = C.getPointerType(Res);
602e5dd7070Spatrick   return Res;
603e5dd7070Spatrick }
604e5dd7070Spatrick 
getRepresentativeTypeName(ASTContext & C) const605e5dd7070Spatrick std::string ArgType::getRepresentativeTypeName(ASTContext &C) const {
606ec727ea7Spatrick   std::string S = getRepresentativeType(C).getAsString(C.getPrintingPolicy());
607e5dd7070Spatrick 
608e5dd7070Spatrick   std::string Alias;
609e5dd7070Spatrick   if (Name) {
610e5dd7070Spatrick     // Use a specific name for this type, e.g. "size_t".
611e5dd7070Spatrick     Alias = Name;
612e5dd7070Spatrick     if (Ptr) {
613e5dd7070Spatrick       // If ArgType is actually a pointer to T, append an asterisk.
614e5dd7070Spatrick       Alias += (Alias[Alias.size()-1] == '*') ? "*" : " *";
615e5dd7070Spatrick     }
616e5dd7070Spatrick     // If Alias is the same as the underlying type, e.g. wchar_t, then drop it.
617e5dd7070Spatrick     if (S == Alias)
618e5dd7070Spatrick       Alias.clear();
619e5dd7070Spatrick   }
620e5dd7070Spatrick 
621e5dd7070Spatrick   if (!Alias.empty())
622e5dd7070Spatrick     return std::string("'") + Alias + "' (aka '" + S + "')";
623e5dd7070Spatrick   return std::string("'") + S + "'";
624e5dd7070Spatrick }
625e5dd7070Spatrick 
626e5dd7070Spatrick 
627e5dd7070Spatrick //===----------------------------------------------------------------------===//
628e5dd7070Spatrick // Methods on OptionalAmount.
629e5dd7070Spatrick //===----------------------------------------------------------------------===//
630e5dd7070Spatrick 
631e5dd7070Spatrick ArgType
getArgType(ASTContext & Ctx) const632e5dd7070Spatrick analyze_format_string::OptionalAmount::getArgType(ASTContext &Ctx) const {
633e5dd7070Spatrick   return Ctx.IntTy;
634e5dd7070Spatrick }
635e5dd7070Spatrick 
636e5dd7070Spatrick //===----------------------------------------------------------------------===//
637e5dd7070Spatrick // Methods on LengthModifier.
638e5dd7070Spatrick //===----------------------------------------------------------------------===//
639e5dd7070Spatrick 
640e5dd7070Spatrick const char *
toString() const641e5dd7070Spatrick analyze_format_string::LengthModifier::toString() const {
642e5dd7070Spatrick   switch (kind) {
643e5dd7070Spatrick   case AsChar:
644e5dd7070Spatrick     return "hh";
645e5dd7070Spatrick   case AsShort:
646e5dd7070Spatrick     return "h";
647e5dd7070Spatrick   case AsShortLong:
648e5dd7070Spatrick     return "hl";
649e5dd7070Spatrick   case AsLong: // or AsWideChar
650e5dd7070Spatrick     return "l";
651e5dd7070Spatrick   case AsLongLong:
652e5dd7070Spatrick     return "ll";
653e5dd7070Spatrick   case AsQuad:
654e5dd7070Spatrick     return "q";
655e5dd7070Spatrick   case AsIntMax:
656e5dd7070Spatrick     return "j";
657e5dd7070Spatrick   case AsSizeT:
658e5dd7070Spatrick     return "z";
659e5dd7070Spatrick   case AsPtrDiff:
660e5dd7070Spatrick     return "t";
661e5dd7070Spatrick   case AsInt32:
662e5dd7070Spatrick     return "I32";
663e5dd7070Spatrick   case AsInt3264:
664e5dd7070Spatrick     return "I";
665e5dd7070Spatrick   case AsInt64:
666e5dd7070Spatrick     return "I64";
667e5dd7070Spatrick   case AsLongDouble:
668e5dd7070Spatrick     return "L";
669e5dd7070Spatrick   case AsAllocate:
670e5dd7070Spatrick     return "a";
671e5dd7070Spatrick   case AsMAllocate:
672e5dd7070Spatrick     return "m";
673e5dd7070Spatrick   case AsWide:
674e5dd7070Spatrick     return "w";
675e5dd7070Spatrick   case None:
676e5dd7070Spatrick     return "";
677e5dd7070Spatrick   }
678e5dd7070Spatrick   return nullptr;
679e5dd7070Spatrick }
680e5dd7070Spatrick 
681e5dd7070Spatrick //===----------------------------------------------------------------------===//
682e5dd7070Spatrick // Methods on ConversionSpecifier.
683e5dd7070Spatrick //===----------------------------------------------------------------------===//
684e5dd7070Spatrick 
toString() const685e5dd7070Spatrick const char *ConversionSpecifier::toString() const {
686e5dd7070Spatrick   switch (kind) {
687*7a9b00ceSrobert   case bArg: return "b";
688*7a9b00ceSrobert   case BArg: return "B";
689e5dd7070Spatrick   case dArg: return "d";
690e5dd7070Spatrick   case DArg: return "D";
691e5dd7070Spatrick   case iArg: return "i";
692e5dd7070Spatrick   case oArg: return "o";
693e5dd7070Spatrick   case OArg: return "O";
694e5dd7070Spatrick   case uArg: return "u";
695e5dd7070Spatrick   case UArg: return "U";
696e5dd7070Spatrick   case xArg: return "x";
697e5dd7070Spatrick   case XArg: return "X";
698e5dd7070Spatrick   case fArg: return "f";
699e5dd7070Spatrick   case FArg: return "F";
700e5dd7070Spatrick   case eArg: return "e";
701e5dd7070Spatrick   case EArg: return "E";
702e5dd7070Spatrick   case gArg: return "g";
703e5dd7070Spatrick   case GArg: return "G";
704e5dd7070Spatrick   case aArg: return "a";
705e5dd7070Spatrick   case AArg: return "A";
706e5dd7070Spatrick   case cArg: return "c";
707e5dd7070Spatrick   case sArg: return "s";
708e5dd7070Spatrick   case pArg: return "p";
709e5dd7070Spatrick   case PArg:
710e5dd7070Spatrick     return "P";
711e5dd7070Spatrick   case nArg: return "n";
712e5dd7070Spatrick   case PercentArg:  return "%";
713e5dd7070Spatrick   case ScanListArg: return "[";
714e5dd7070Spatrick   case InvalidSpecifier: return nullptr;
715e5dd7070Spatrick 
716e5dd7070Spatrick   // POSIX unicode extensions.
717e5dd7070Spatrick   case CArg: return "C";
718e5dd7070Spatrick   case SArg: return "S";
719e5dd7070Spatrick 
720e5dd7070Spatrick   // Objective-C specific specifiers.
721e5dd7070Spatrick   case ObjCObjArg: return "@";
722e5dd7070Spatrick 
723e5dd7070Spatrick   // FreeBSD kernel specific specifiers.
724e5dd7070Spatrick   case FreeBSDbArg: return "b";
725e5dd7070Spatrick   case FreeBSDDArg: return "D";
726e5dd7070Spatrick   case FreeBSDrArg: return "r";
727e5dd7070Spatrick   case FreeBSDyArg: return "y";
728e5dd7070Spatrick 
729e5dd7070Spatrick   // GlibC specific specifiers.
730e5dd7070Spatrick   case PrintErrno: return "m";
731e5dd7070Spatrick 
732e5dd7070Spatrick   // MS specific specifiers.
733e5dd7070Spatrick   case ZArg: return "Z";
734e5dd7070Spatrick   }
735e5dd7070Spatrick   return nullptr;
736e5dd7070Spatrick }
737e5dd7070Spatrick 
738*7a9b00ceSrobert std::optional<ConversionSpecifier>
getStandardSpecifier() const739e5dd7070Spatrick ConversionSpecifier::getStandardSpecifier() const {
740e5dd7070Spatrick   ConversionSpecifier::Kind NewKind;
741e5dd7070Spatrick 
742e5dd7070Spatrick   switch (getKind()) {
743e5dd7070Spatrick   default:
744*7a9b00ceSrobert     return std::nullopt;
745e5dd7070Spatrick   case DArg:
746e5dd7070Spatrick     NewKind = dArg;
747e5dd7070Spatrick     break;
748e5dd7070Spatrick   case UArg:
749e5dd7070Spatrick     NewKind = uArg;
750e5dd7070Spatrick     break;
751e5dd7070Spatrick   case OArg:
752e5dd7070Spatrick     NewKind = oArg;
753e5dd7070Spatrick     break;
754e5dd7070Spatrick   }
755e5dd7070Spatrick 
756e5dd7070Spatrick   ConversionSpecifier FixedCS(*this);
757e5dd7070Spatrick   FixedCS.setKind(NewKind);
758e5dd7070Spatrick   return FixedCS;
759e5dd7070Spatrick }
760e5dd7070Spatrick 
761e5dd7070Spatrick //===----------------------------------------------------------------------===//
762e5dd7070Spatrick // Methods on OptionalAmount.
763e5dd7070Spatrick //===----------------------------------------------------------------------===//
764e5dd7070Spatrick 
toString(raw_ostream & os) const765e5dd7070Spatrick void OptionalAmount::toString(raw_ostream &os) const {
766e5dd7070Spatrick   switch (hs) {
767e5dd7070Spatrick   case Invalid:
768e5dd7070Spatrick   case NotSpecified:
769e5dd7070Spatrick     return;
770e5dd7070Spatrick   case Arg:
771e5dd7070Spatrick     if (UsesDotPrefix)
772e5dd7070Spatrick         os << ".";
773e5dd7070Spatrick     if (usesPositionalArg())
774e5dd7070Spatrick       os << "*" << getPositionalArgIndex() << "$";
775e5dd7070Spatrick     else
776e5dd7070Spatrick       os << "*";
777e5dd7070Spatrick     break;
778e5dd7070Spatrick   case Constant:
779e5dd7070Spatrick     if (UsesDotPrefix)
780e5dd7070Spatrick         os << ".";
781e5dd7070Spatrick     os << amt;
782e5dd7070Spatrick     break;
783e5dd7070Spatrick   }
784e5dd7070Spatrick }
785e5dd7070Spatrick 
hasValidLengthModifier(const TargetInfo & Target,const LangOptions & LO) const786e5dd7070Spatrick bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target,
787e5dd7070Spatrick                                              const LangOptions &LO) const {
788e5dd7070Spatrick   switch (LM.getKind()) {
789e5dd7070Spatrick     case LengthModifier::None:
790e5dd7070Spatrick       return true;
791e5dd7070Spatrick 
792e5dd7070Spatrick     // Handle most integer flags
793e5dd7070Spatrick     case LengthModifier::AsShort:
794e5dd7070Spatrick       // Length modifier only applies to FP vectors.
795e5dd7070Spatrick       if (LO.OpenCL && CS.isDoubleArg())
796e5dd7070Spatrick         return !VectorNumElts.isInvalid();
797e5dd7070Spatrick 
798e5dd7070Spatrick       if (Target.getTriple().isOSMSVCRT()) {
799e5dd7070Spatrick         switch (CS.getKind()) {
800e5dd7070Spatrick           case ConversionSpecifier::cArg:
801e5dd7070Spatrick           case ConversionSpecifier::CArg:
802e5dd7070Spatrick           case ConversionSpecifier::sArg:
803e5dd7070Spatrick           case ConversionSpecifier::SArg:
804e5dd7070Spatrick           case ConversionSpecifier::ZArg:
805e5dd7070Spatrick             return true;
806e5dd7070Spatrick           default:
807e5dd7070Spatrick             break;
808e5dd7070Spatrick         }
809e5dd7070Spatrick       }
810*7a9b00ceSrobert       [[fallthrough]];
811e5dd7070Spatrick     case LengthModifier::AsChar:
812e5dd7070Spatrick     case LengthModifier::AsLongLong:
813e5dd7070Spatrick     case LengthModifier::AsQuad:
814e5dd7070Spatrick     case LengthModifier::AsIntMax:
815e5dd7070Spatrick     case LengthModifier::AsSizeT:
816e5dd7070Spatrick     case LengthModifier::AsPtrDiff:
817e5dd7070Spatrick       switch (CS.getKind()) {
818*7a9b00ceSrobert         case ConversionSpecifier::bArg:
819*7a9b00ceSrobert         case ConversionSpecifier::BArg:
820e5dd7070Spatrick         case ConversionSpecifier::dArg:
821e5dd7070Spatrick         case ConversionSpecifier::DArg:
822e5dd7070Spatrick         case ConversionSpecifier::iArg:
823e5dd7070Spatrick         case ConversionSpecifier::oArg:
824e5dd7070Spatrick         case ConversionSpecifier::OArg:
825e5dd7070Spatrick         case ConversionSpecifier::uArg:
826e5dd7070Spatrick         case ConversionSpecifier::UArg:
827e5dd7070Spatrick         case ConversionSpecifier::xArg:
828e5dd7070Spatrick         case ConversionSpecifier::XArg:
829e5dd7070Spatrick         case ConversionSpecifier::nArg:
830e5dd7070Spatrick           return true;
831adae0cfdSpatrick         case ConversionSpecifier::FreeBSDbArg:
832adae0cfdSpatrick           return Target.getTriple().isOSFreeBSD() ||
833adae0cfdSpatrick                  Target.getTriple().isPS4() ||
834adae0cfdSpatrick                  Target.getTriple().isOSOpenBSD();
835e5dd7070Spatrick         case ConversionSpecifier::FreeBSDrArg:
836e5dd7070Spatrick         case ConversionSpecifier::FreeBSDyArg:
837*7a9b00ceSrobert           return Target.getTriple().isOSFreeBSD() || Target.getTriple().isPS();
838e5dd7070Spatrick         default:
839e5dd7070Spatrick           return false;
840e5dd7070Spatrick       }
841e5dd7070Spatrick 
842e5dd7070Spatrick     case LengthModifier::AsShortLong:
843e5dd7070Spatrick       return LO.OpenCL && !VectorNumElts.isInvalid();
844e5dd7070Spatrick 
845e5dd7070Spatrick     // Handle 'l' flag
846e5dd7070Spatrick     case LengthModifier::AsLong: // or AsWideChar
847e5dd7070Spatrick       if (CS.isDoubleArg()) {
848e5dd7070Spatrick         // Invalid for OpenCL FP scalars.
849e5dd7070Spatrick         if (LO.OpenCL && VectorNumElts.isInvalid())
850e5dd7070Spatrick           return false;
851e5dd7070Spatrick         return true;
852e5dd7070Spatrick       }
853e5dd7070Spatrick 
854e5dd7070Spatrick       switch (CS.getKind()) {
855e5dd7070Spatrick         case ConversionSpecifier::dArg:
856e5dd7070Spatrick         case ConversionSpecifier::DArg:
857e5dd7070Spatrick         case ConversionSpecifier::iArg:
858e5dd7070Spatrick         case ConversionSpecifier::oArg:
859e5dd7070Spatrick         case ConversionSpecifier::OArg:
860e5dd7070Spatrick         case ConversionSpecifier::uArg:
861e5dd7070Spatrick         case ConversionSpecifier::UArg:
862e5dd7070Spatrick         case ConversionSpecifier::xArg:
863e5dd7070Spatrick         case ConversionSpecifier::XArg:
864e5dd7070Spatrick         case ConversionSpecifier::nArg:
865e5dd7070Spatrick         case ConversionSpecifier::cArg:
866e5dd7070Spatrick         case ConversionSpecifier::sArg:
867e5dd7070Spatrick         case ConversionSpecifier::ScanListArg:
868e5dd7070Spatrick         case ConversionSpecifier::ZArg:
869e5dd7070Spatrick           return true;
870adae0cfdSpatrick         case ConversionSpecifier::FreeBSDbArg:
871adae0cfdSpatrick           return Target.getTriple().isOSFreeBSD() ||
872adae0cfdSpatrick                  Target.getTriple().isPS4() ||
873adae0cfdSpatrick                  Target.getTriple().isOSOpenBSD();
874e5dd7070Spatrick         case ConversionSpecifier::FreeBSDrArg:
875e5dd7070Spatrick         case ConversionSpecifier::FreeBSDyArg:
876*7a9b00ceSrobert           return Target.getTriple().isOSFreeBSD() || Target.getTriple().isPS();
877e5dd7070Spatrick         default:
878e5dd7070Spatrick           return false;
879e5dd7070Spatrick       }
880e5dd7070Spatrick 
881e5dd7070Spatrick     case LengthModifier::AsLongDouble:
882e5dd7070Spatrick       switch (CS.getKind()) {
883e5dd7070Spatrick         case ConversionSpecifier::aArg:
884e5dd7070Spatrick         case ConversionSpecifier::AArg:
885e5dd7070Spatrick         case ConversionSpecifier::fArg:
886e5dd7070Spatrick         case ConversionSpecifier::FArg:
887e5dd7070Spatrick         case ConversionSpecifier::eArg:
888e5dd7070Spatrick         case ConversionSpecifier::EArg:
889e5dd7070Spatrick         case ConversionSpecifier::gArg:
890e5dd7070Spatrick         case ConversionSpecifier::GArg:
891e5dd7070Spatrick           return true;
892e5dd7070Spatrick         // GNU libc extension.
893e5dd7070Spatrick         case ConversionSpecifier::dArg:
894e5dd7070Spatrick         case ConversionSpecifier::iArg:
895e5dd7070Spatrick         case ConversionSpecifier::oArg:
896e5dd7070Spatrick         case ConversionSpecifier::uArg:
897e5dd7070Spatrick         case ConversionSpecifier::xArg:
898e5dd7070Spatrick         case ConversionSpecifier::XArg:
899e5dd7070Spatrick           return !Target.getTriple().isOSDarwin() &&
900e5dd7070Spatrick                  !Target.getTriple().isOSWindows();
901e5dd7070Spatrick         default:
902e5dd7070Spatrick           return false;
903e5dd7070Spatrick       }
904e5dd7070Spatrick 
905e5dd7070Spatrick     case LengthModifier::AsAllocate:
906e5dd7070Spatrick       switch (CS.getKind()) {
907e5dd7070Spatrick         case ConversionSpecifier::sArg:
908e5dd7070Spatrick         case ConversionSpecifier::SArg:
909e5dd7070Spatrick         case ConversionSpecifier::ScanListArg:
910e5dd7070Spatrick           return true;
911e5dd7070Spatrick         default:
912e5dd7070Spatrick           return false;
913e5dd7070Spatrick       }
914e5dd7070Spatrick 
915e5dd7070Spatrick     case LengthModifier::AsMAllocate:
916e5dd7070Spatrick       switch (CS.getKind()) {
917e5dd7070Spatrick         case ConversionSpecifier::cArg:
918e5dd7070Spatrick         case ConversionSpecifier::CArg:
919e5dd7070Spatrick         case ConversionSpecifier::sArg:
920e5dd7070Spatrick         case ConversionSpecifier::SArg:
921e5dd7070Spatrick         case ConversionSpecifier::ScanListArg:
922e5dd7070Spatrick           return true;
923e5dd7070Spatrick         default:
924e5dd7070Spatrick           return false;
925e5dd7070Spatrick       }
926e5dd7070Spatrick     case LengthModifier::AsInt32:
927e5dd7070Spatrick     case LengthModifier::AsInt3264:
928e5dd7070Spatrick     case LengthModifier::AsInt64:
929e5dd7070Spatrick       switch (CS.getKind()) {
930e5dd7070Spatrick         case ConversionSpecifier::dArg:
931e5dd7070Spatrick         case ConversionSpecifier::iArg:
932e5dd7070Spatrick         case ConversionSpecifier::oArg:
933e5dd7070Spatrick         case ConversionSpecifier::uArg:
934e5dd7070Spatrick         case ConversionSpecifier::xArg:
935e5dd7070Spatrick         case ConversionSpecifier::XArg:
936e5dd7070Spatrick           return Target.getTriple().isOSMSVCRT();
937e5dd7070Spatrick         default:
938e5dd7070Spatrick           return false;
939e5dd7070Spatrick       }
940e5dd7070Spatrick     case LengthModifier::AsWide:
941e5dd7070Spatrick       switch (CS.getKind()) {
942e5dd7070Spatrick         case ConversionSpecifier::cArg:
943e5dd7070Spatrick         case ConversionSpecifier::CArg:
944e5dd7070Spatrick         case ConversionSpecifier::sArg:
945e5dd7070Spatrick         case ConversionSpecifier::SArg:
946e5dd7070Spatrick         case ConversionSpecifier::ZArg:
947e5dd7070Spatrick           return Target.getTriple().isOSMSVCRT();
948e5dd7070Spatrick         default:
949e5dd7070Spatrick           return false;
950e5dd7070Spatrick       }
951e5dd7070Spatrick   }
952e5dd7070Spatrick   llvm_unreachable("Invalid LengthModifier Kind!");
953e5dd7070Spatrick }
954e5dd7070Spatrick 
hasStandardLengthModifier() const955e5dd7070Spatrick bool FormatSpecifier::hasStandardLengthModifier() const {
956e5dd7070Spatrick   switch (LM.getKind()) {
957e5dd7070Spatrick     case LengthModifier::None:
958e5dd7070Spatrick     case LengthModifier::AsChar:
959e5dd7070Spatrick     case LengthModifier::AsShort:
960e5dd7070Spatrick     case LengthModifier::AsLong:
961e5dd7070Spatrick     case LengthModifier::AsLongLong:
962e5dd7070Spatrick     case LengthModifier::AsIntMax:
963e5dd7070Spatrick     case LengthModifier::AsSizeT:
964e5dd7070Spatrick     case LengthModifier::AsPtrDiff:
965e5dd7070Spatrick     case LengthModifier::AsLongDouble:
966e5dd7070Spatrick       return true;
967e5dd7070Spatrick     case LengthModifier::AsAllocate:
968e5dd7070Spatrick     case LengthModifier::AsMAllocate:
969e5dd7070Spatrick     case LengthModifier::AsQuad:
970e5dd7070Spatrick     case LengthModifier::AsInt32:
971e5dd7070Spatrick     case LengthModifier::AsInt3264:
972e5dd7070Spatrick     case LengthModifier::AsInt64:
973e5dd7070Spatrick     case LengthModifier::AsWide:
974e5dd7070Spatrick     case LengthModifier::AsShortLong: // ???
975e5dd7070Spatrick       return false;
976e5dd7070Spatrick   }
977e5dd7070Spatrick   llvm_unreachable("Invalid LengthModifier Kind!");
978e5dd7070Spatrick }
979e5dd7070Spatrick 
hasStandardConversionSpecifier(const LangOptions & LangOpt) const980e5dd7070Spatrick bool FormatSpecifier::hasStandardConversionSpecifier(
981e5dd7070Spatrick     const LangOptions &LangOpt) const {
982e5dd7070Spatrick   switch (CS.getKind()) {
983*7a9b00ceSrobert     case ConversionSpecifier::bArg:
984*7a9b00ceSrobert     case ConversionSpecifier::BArg:
985e5dd7070Spatrick     case ConversionSpecifier::cArg:
986e5dd7070Spatrick     case ConversionSpecifier::dArg:
987e5dd7070Spatrick     case ConversionSpecifier::iArg:
988e5dd7070Spatrick     case ConversionSpecifier::oArg:
989e5dd7070Spatrick     case ConversionSpecifier::uArg:
990e5dd7070Spatrick     case ConversionSpecifier::xArg:
991e5dd7070Spatrick     case ConversionSpecifier::XArg:
992e5dd7070Spatrick     case ConversionSpecifier::fArg:
993e5dd7070Spatrick     case ConversionSpecifier::FArg:
994e5dd7070Spatrick     case ConversionSpecifier::eArg:
995e5dd7070Spatrick     case ConversionSpecifier::EArg:
996e5dd7070Spatrick     case ConversionSpecifier::gArg:
997e5dd7070Spatrick     case ConversionSpecifier::GArg:
998e5dd7070Spatrick     case ConversionSpecifier::aArg:
999e5dd7070Spatrick     case ConversionSpecifier::AArg:
1000e5dd7070Spatrick     case ConversionSpecifier::sArg:
1001e5dd7070Spatrick     case ConversionSpecifier::pArg:
1002e5dd7070Spatrick     case ConversionSpecifier::nArg:
1003e5dd7070Spatrick     case ConversionSpecifier::ObjCObjArg:
1004e5dd7070Spatrick     case ConversionSpecifier::ScanListArg:
1005e5dd7070Spatrick     case ConversionSpecifier::PercentArg:
1006e5dd7070Spatrick     case ConversionSpecifier::PArg:
1007e5dd7070Spatrick       return true;
1008e5dd7070Spatrick     case ConversionSpecifier::CArg:
1009e5dd7070Spatrick     case ConversionSpecifier::SArg:
1010e5dd7070Spatrick       return LangOpt.ObjC;
1011e5dd7070Spatrick     case ConversionSpecifier::InvalidSpecifier:
1012e5dd7070Spatrick     case ConversionSpecifier::FreeBSDbArg:
1013e5dd7070Spatrick     case ConversionSpecifier::FreeBSDDArg:
1014e5dd7070Spatrick     case ConversionSpecifier::FreeBSDrArg:
1015e5dd7070Spatrick     case ConversionSpecifier::FreeBSDyArg:
1016e5dd7070Spatrick     case ConversionSpecifier::PrintErrno:
1017e5dd7070Spatrick     case ConversionSpecifier::DArg:
1018e5dd7070Spatrick     case ConversionSpecifier::OArg:
1019e5dd7070Spatrick     case ConversionSpecifier::UArg:
1020e5dd7070Spatrick     case ConversionSpecifier::ZArg:
1021e5dd7070Spatrick       return false;
1022e5dd7070Spatrick   }
1023e5dd7070Spatrick   llvm_unreachable("Invalid ConversionSpecifier Kind!");
1024e5dd7070Spatrick }
1025e5dd7070Spatrick 
hasStandardLengthConversionCombination() const1026e5dd7070Spatrick bool FormatSpecifier::hasStandardLengthConversionCombination() const {
1027e5dd7070Spatrick   if (LM.getKind() == LengthModifier::AsLongDouble) {
1028e5dd7070Spatrick     switch(CS.getKind()) {
1029e5dd7070Spatrick         case ConversionSpecifier::dArg:
1030e5dd7070Spatrick         case ConversionSpecifier::iArg:
1031e5dd7070Spatrick         case ConversionSpecifier::oArg:
1032e5dd7070Spatrick         case ConversionSpecifier::uArg:
1033e5dd7070Spatrick         case ConversionSpecifier::xArg:
1034e5dd7070Spatrick         case ConversionSpecifier::XArg:
1035adae0cfdSpatrick         case ConversionSpecifier::FreeBSDbArg:
1036e5dd7070Spatrick           return false;
1037e5dd7070Spatrick         default:
1038e5dd7070Spatrick           return true;
1039e5dd7070Spatrick     }
1040e5dd7070Spatrick   }
1041e5dd7070Spatrick   return true;
1042e5dd7070Spatrick }
1043e5dd7070Spatrick 
1044*7a9b00ceSrobert std::optional<LengthModifier>
getCorrectedLengthModifier() const1045*7a9b00ceSrobert FormatSpecifier::getCorrectedLengthModifier() const {
1046e5dd7070Spatrick   if (CS.isAnyIntArg() || CS.getKind() == ConversionSpecifier::nArg) {
1047e5dd7070Spatrick     if (LM.getKind() == LengthModifier::AsLongDouble ||
1048e5dd7070Spatrick         LM.getKind() == LengthModifier::AsQuad) {
1049e5dd7070Spatrick       LengthModifier FixedLM(LM);
1050e5dd7070Spatrick       FixedLM.setKind(LengthModifier::AsLongLong);
1051e5dd7070Spatrick       return FixedLM;
1052e5dd7070Spatrick     }
1053e5dd7070Spatrick   }
1054e5dd7070Spatrick 
1055*7a9b00ceSrobert   return std::nullopt;
1056e5dd7070Spatrick }
1057e5dd7070Spatrick 
namedTypeToLengthModifier(QualType QT,LengthModifier & LM)1058e5dd7070Spatrick bool FormatSpecifier::namedTypeToLengthModifier(QualType QT,
1059e5dd7070Spatrick                                                 LengthModifier &LM) {
1060*7a9b00ceSrobert   for (/**/; const auto *TT = QT->getAs<TypedefType>();
1061*7a9b00ceSrobert        QT = TT->getDecl()->getUnderlyingType()) {
1062*7a9b00ceSrobert     const TypedefNameDecl *Typedef = TT->getDecl();
1063e5dd7070Spatrick     const IdentifierInfo *Identifier = Typedef->getIdentifier();
1064e5dd7070Spatrick     if (Identifier->getName() == "size_t") {
1065e5dd7070Spatrick       LM.setKind(LengthModifier::AsSizeT);
1066e5dd7070Spatrick       return true;
1067e5dd7070Spatrick     } else if (Identifier->getName() == "ssize_t") {
1068e5dd7070Spatrick       // Not C99, but common in Unix.
1069e5dd7070Spatrick       LM.setKind(LengthModifier::AsSizeT);
1070e5dd7070Spatrick       return true;
1071e5dd7070Spatrick     } else if (Identifier->getName() == "intmax_t") {
1072e5dd7070Spatrick       LM.setKind(LengthModifier::AsIntMax);
1073e5dd7070Spatrick       return true;
1074e5dd7070Spatrick     } else if (Identifier->getName() == "uintmax_t") {
1075e5dd7070Spatrick       LM.setKind(LengthModifier::AsIntMax);
1076e5dd7070Spatrick       return true;
1077e5dd7070Spatrick     } else if (Identifier->getName() == "ptrdiff_t") {
1078e5dd7070Spatrick       LM.setKind(LengthModifier::AsPtrDiff);
1079e5dd7070Spatrick       return true;
1080e5dd7070Spatrick     }
1081e5dd7070Spatrick   }
1082e5dd7070Spatrick   return false;
1083e5dd7070Spatrick }
1084