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