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