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