12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010 |
- // FormatString.cpp - Common stuff for handling printf/scanf formats -*- C++ -*-
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // Shared details for processing format strings of printf and scanf
- // (and friends).
- //
- //===----------------------------------------------------------------------===//
- #include "FormatStringParsing.h"
- #include "clang/Basic/LangOptions.h"
- #include "clang/Basic/TargetInfo.h"
- #include "llvm/Support/ConvertUTF.h"
- using clang::analyze_format_string::ArgType;
- using clang::analyze_format_string::FormatStringHandler;
- using clang::analyze_format_string::FormatSpecifier;
- using clang::analyze_format_string::LengthModifier;
- using clang::analyze_format_string::OptionalAmount;
- using clang::analyze_format_string::PositionContext;
- using clang::analyze_format_string::ConversionSpecifier;
- using namespace clang;
- // Key function to FormatStringHandler.
- FormatStringHandler::~FormatStringHandler() {}
- //===----------------------------------------------------------------------===//
- // Functions for parsing format strings components in both printf and
- // scanf format strings.
- //===----------------------------------------------------------------------===//
- OptionalAmount
- clang::analyze_format_string::ParseAmount(const char *&Beg, const char *E) {
- const char *I = Beg;
- UpdateOnReturn <const char*> UpdateBeg(Beg, I);
- unsigned accumulator = 0;
- bool hasDigits = false;
- for ( ; I != E; ++I) {
- char c = *I;
- if (c >= '0' && c <= '9') {
- hasDigits = true;
- accumulator = (accumulator * 10) + (c - '0');
- continue;
- }
- if (hasDigits)
- return OptionalAmount(OptionalAmount::Constant, accumulator, Beg, I - Beg,
- false);
- break;
- }
- return OptionalAmount();
- }
- OptionalAmount
- clang::analyze_format_string::ParseNonPositionAmount(const char *&Beg,
- const char *E,
- unsigned &argIndex) {
- if (*Beg == '*') {
- ++Beg;
- return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg, 0, false);
- }
- return ParseAmount(Beg, E);
- }
- OptionalAmount
- clang::analyze_format_string::ParsePositionAmount(FormatStringHandler &H,
- const char *Start,
- const char *&Beg,
- const char *E,
- PositionContext p) {
- if (*Beg == '*') {
- const char *I = Beg + 1;
- const OptionalAmount &Amt = ParseAmount(I, E);
- if (Amt.getHowSpecified() == OptionalAmount::NotSpecified) {
- H.HandleInvalidPosition(Beg, I - Beg, p);
- return OptionalAmount(false);
- }
- if (I == E) {
- // No more characters left?
- H.HandleIncompleteSpecifier(Start, E - Start);
- return OptionalAmount(false);
- }
- assert(Amt.getHowSpecified() == OptionalAmount::Constant);
- if (*I == '$') {
- // Handle positional arguments
- // Special case: '*0$', since this is an easy mistake.
- if (Amt.getConstantAmount() == 0) {
- H.HandleZeroPosition(Beg, I - Beg + 1);
- return OptionalAmount(false);
- }
- const char *Tmp = Beg;
- Beg = ++I;
- return OptionalAmount(OptionalAmount::Arg, Amt.getConstantAmount() - 1,
- Tmp, 0, true);
- }
- H.HandleInvalidPosition(Beg, I - Beg, p);
- return OptionalAmount(false);
- }
- return ParseAmount(Beg, E);
- }
- bool
- clang::analyze_format_string::ParseFieldWidth(FormatStringHandler &H,
- FormatSpecifier &CS,
- const char *Start,
- const char *&Beg, const char *E,
- unsigned *argIndex) {
- // FIXME: Support negative field widths.
- if (argIndex) {
- CS.setFieldWidth(ParseNonPositionAmount(Beg, E, *argIndex));
- }
- else {
- const OptionalAmount Amt =
- ParsePositionAmount(H, Start, Beg, E,
- analyze_format_string::FieldWidthPos);
- if (Amt.isInvalid())
- return true;
- CS.setFieldWidth(Amt);
- }
- return false;
- }
- bool
- clang::analyze_format_string::ParseArgPosition(FormatStringHandler &H,
- FormatSpecifier &FS,
- const char *Start,
- const char *&Beg,
- const char *E) {
- const char *I = Beg;
- const OptionalAmount &Amt = ParseAmount(I, E);
- if (I == E) {
- // No more characters left?
- H.HandleIncompleteSpecifier(Start, E - Start);
- return true;
- }
- if (Amt.getHowSpecified() == OptionalAmount::Constant && *(I++) == '$') {
- // Warn that positional arguments are non-standard.
- H.HandlePosition(Start, I - Start);
- // Special case: '%0$', since this is an easy mistake.
- if (Amt.getConstantAmount() == 0) {
- H.HandleZeroPosition(Start, I - Start);
- return true;
- }
- FS.setArgIndex(Amt.getConstantAmount() - 1);
- FS.setUsesPositionalArg();
- // Update the caller's pointer if we decided to consume
- // these characters.
- Beg = I;
- return false;
- }
- return false;
- }
- bool
- clang::analyze_format_string::ParseVectorModifier(FormatStringHandler &H,
- FormatSpecifier &FS,
- const char *&I,
- const char *E,
- const LangOptions &LO) {
- if (!LO.OpenCL)
- return false;
- const char *Start = I;
- if (*I == 'v') {
- ++I;
- if (I == E) {
- H.HandleIncompleteSpecifier(Start, E - Start);
- return true;
- }
- OptionalAmount NumElts = ParseAmount(I, E);
- if (NumElts.getHowSpecified() != OptionalAmount::Constant) {
- H.HandleIncompleteSpecifier(Start, E - Start);
- return true;
- }
- FS.setVectorNumElts(NumElts);
- }
- return false;
- }
- bool
- clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,
- const char *&I,
- const char *E,
- const LangOptions &LO,
- bool IsScanf) {
- LengthModifier::Kind lmKind = LengthModifier::None;
- const char *lmPosition = I;
- switch (*I) {
- default:
- return false;
- case 'h':
- ++I;
- if (I != E && *I == 'h') {
- ++I;
- lmKind = LengthModifier::AsChar;
- } else if (I != E && *I == 'l' && LO.OpenCL) {
- ++I;
- lmKind = LengthModifier::AsShortLong;
- } else {
- lmKind = LengthModifier::AsShort;
- }
- break;
- case 'l':
- ++I;
- if (I != E && *I == 'l') {
- ++I;
- lmKind = LengthModifier::AsLongLong;
- } else {
- lmKind = LengthModifier::AsLong;
- }
- break;
- case 'j': lmKind = LengthModifier::AsIntMax; ++I; break;
- case 'z': lmKind = LengthModifier::AsSizeT; ++I; break;
- case 't': lmKind = LengthModifier::AsPtrDiff; ++I; break;
- case 'L': lmKind = LengthModifier::AsLongDouble; ++I; break;
- case 'q': lmKind = LengthModifier::AsQuad; ++I; break;
- case 'a':
- if (IsScanf && !LO.C99 && !LO.CPlusPlus11) {
- // For scanf in C90, look at the next character to see if this should
- // be parsed as the GNU extension 'a' length modifier. If not, this
- // will be parsed as a conversion specifier.
- ++I;
- if (I != E && (*I == 's' || *I == 'S' || *I == '[')) {
- lmKind = LengthModifier::AsAllocate;
- break;
- }
- --I;
- }
- return false;
- case 'm':
- if (IsScanf) {
- lmKind = LengthModifier::AsMAllocate;
- ++I;
- break;
- }
- return false;
- // printf: AsInt64, AsInt32, AsInt3264
- // scanf: AsInt64
- case 'I':
- if (I + 1 != E && I + 2 != E) {
- if (I[1] == '6' && I[2] == '4') {
- I += 3;
- lmKind = LengthModifier::AsInt64;
- break;
- }
- if (IsScanf)
- return false;
- if (I[1] == '3' && I[2] == '2') {
- I += 3;
- lmKind = LengthModifier::AsInt32;
- break;
- }
- }
- ++I;
- lmKind = LengthModifier::AsInt3264;
- break;
- case 'w':
- lmKind = LengthModifier::AsWide; ++I; break;
- }
- LengthModifier lm(lmPosition, lmKind);
- FS.setLengthModifier(lm);
- return true;
- }
- bool clang::analyze_format_string::ParseUTF8InvalidSpecifier(
- const char *SpecifierBegin, const char *FmtStrEnd, unsigned &Len) {
- if (SpecifierBegin + 1 >= FmtStrEnd)
- return false;
- const llvm::UTF8 *SB =
- reinterpret_cast<const llvm::UTF8 *>(SpecifierBegin + 1);
- const llvm::UTF8 *SE = reinterpret_cast<const llvm::UTF8 *>(FmtStrEnd);
- const char FirstByte = *SB;
- // If the invalid specifier is a multibyte UTF-8 string, return the
- // total length accordingly so that the conversion specifier can be
- // properly updated to reflect a complete UTF-8 specifier.
- unsigned NumBytes = llvm::getNumBytesForUTF8(FirstByte);
- if (NumBytes == 1)
- return false;
- if (SB + NumBytes > SE)
- return false;
- Len = NumBytes + 1;
- return true;
- }
- //===----------------------------------------------------------------------===//
- // Methods on ArgType.
- //===----------------------------------------------------------------------===//
- clang::analyze_format_string::ArgType::MatchKind
- ArgType::matchesType(ASTContext &C, QualType argTy) const {
- if (Ptr) {
- // It has to be a pointer.
- const PointerType *PT = argTy->getAs<PointerType>();
- if (!PT)
- return NoMatch;
- // We cannot write through a const qualified pointer.
- if (PT->getPointeeType().isConstQualified())
- return NoMatch;
- argTy = PT->getPointeeType();
- }
- switch (K) {
- case InvalidTy:
- llvm_unreachable("ArgType must be valid");
- case UnknownTy:
- return Match;
- case AnyCharTy: {
- if (const EnumType *ETy = argTy->getAs<EnumType>()) {
- // If the enum is incomplete we know nothing about the underlying type.
- // Assume that it's 'int'.
- if (!ETy->getDecl()->isComplete())
- return NoMatch;
- argTy = ETy->getDecl()->getIntegerType();
- }
- if (const BuiltinType *BT = argTy->getAs<BuiltinType>())
- switch (BT->getKind()) {
- default:
- break;
- case BuiltinType::Char_S:
- case BuiltinType::SChar:
- case BuiltinType::UChar:
- case BuiltinType::Char_U:
- case BuiltinType::Bool:
- return Match;
- }
- return NoMatch;
- }
- case SpecificTy: {
- if (const EnumType *ETy = argTy->getAs<EnumType>()) {
- // If the enum is incomplete we know nothing about the underlying type.
- // Assume that it's 'int'.
- if (!ETy->getDecl()->isComplete())
- argTy = C.IntTy;
- else
- argTy = ETy->getDecl()->getIntegerType();
- }
- argTy = C.getCanonicalType(argTy).getUnqualifiedType();
- if (T == argTy)
- return Match;
- // Check for "compatible types".
- if (const BuiltinType *BT = argTy->getAs<BuiltinType>())
- switch (BT->getKind()) {
- default:
- break;
- case BuiltinType::Char_S:
- case BuiltinType::SChar:
- case BuiltinType::Char_U:
- case BuiltinType::UChar:
- case BuiltinType::Bool:
- if (T == C.UnsignedShortTy || T == C.ShortTy)
- return NoMatchTypeConfusion;
- return T == C.UnsignedCharTy || T == C.SignedCharTy ? Match
- : NoMatch;
- case BuiltinType::Short:
- return T == C.UnsignedShortTy ? Match : NoMatch;
- case BuiltinType::UShort:
- return T == C.ShortTy ? Match : NoMatch;
- case BuiltinType::Int:
- return T == C.UnsignedIntTy ? Match : NoMatch;
- case BuiltinType::UInt:
- return T == C.IntTy ? Match : NoMatch;
- case BuiltinType::Long:
- return T == C.UnsignedLongTy ? Match : NoMatch;
- case BuiltinType::ULong:
- return T == C.LongTy ? Match : NoMatch;
- case BuiltinType::LongLong:
- return T == C.UnsignedLongLongTy ? Match : NoMatch;
- case BuiltinType::ULongLong:
- return T == C.LongLongTy ? Match : NoMatch;
- }
- return NoMatch;
- }
- case CStrTy: {
- const PointerType *PT = argTy->getAs<PointerType>();
- if (!PT)
- return NoMatch;
- QualType pointeeTy = PT->getPointeeType();
- if (const BuiltinType *BT = pointeeTy->getAs<BuiltinType>())
- switch (BT->getKind()) {
- case BuiltinType::Void:
- case BuiltinType::Char_U:
- case BuiltinType::UChar:
- case BuiltinType::Char_S:
- case BuiltinType::SChar:
- return Match;
- default:
- break;
- }
- return NoMatch;
- }
- case WCStrTy: {
- const PointerType *PT = argTy->getAs<PointerType>();
- if (!PT)
- return NoMatch;
- QualType pointeeTy =
- C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType();
- return pointeeTy == C.getWideCharType() ? Match : NoMatch;
- }
- case WIntTy: {
- QualType WInt = C.getCanonicalType(C.getWIntType()).getUnqualifiedType();
- if (C.getCanonicalType(argTy).getUnqualifiedType() == WInt)
- return Match;
- QualType PromoArg = argTy->isPromotableIntegerType()
- ? C.getPromotedIntegerType(argTy)
- : argTy;
- PromoArg = C.getCanonicalType(PromoArg).getUnqualifiedType();
- // If the promoted argument is the corresponding signed type of the
- // wint_t type, then it should match.
- if (PromoArg->hasSignedIntegerRepresentation() &&
- C.getCorrespondingUnsignedType(PromoArg) == WInt)
- return Match;
- return WInt == PromoArg ? Match : NoMatch;
- }
- case CPointerTy:
- if (argTy->isVoidPointerType()) {
- return Match;
- } if (argTy->isPointerType() || argTy->isObjCObjectPointerType() ||
- argTy->isBlockPointerType() || argTy->isNullPtrType()) {
- return NoMatchPedantic;
- } else {
- return NoMatch;
- }
- case ObjCPointerTy: {
- if (argTy->getAs<ObjCObjectPointerType>() ||
- argTy->getAs<BlockPointerType>())
- return Match;
- // Handle implicit toll-free bridging.
- if (const PointerType *PT = argTy->getAs<PointerType>()) {
- // Things such as CFTypeRef are really just opaque pointers
- // to C structs representing CF types that can often be bridged
- // to Objective-C objects. Since the compiler doesn't know which
- // structs can be toll-free bridged, we just accept them all.
- QualType pointee = PT->getPointeeType();
- if (pointee->getAsStructureType() || pointee->isVoidType())
- return Match;
- }
- return NoMatch;
- }
- }
- llvm_unreachable("Invalid ArgType Kind!");
- }
- ArgType ArgType::makeVectorType(ASTContext &C, unsigned NumElts) const {
- // Check for valid vector element types.
- if (T.isNull())
- return ArgType::Invalid();
- QualType Vec = C.getExtVectorType(T, NumElts);
- return ArgType(Vec, Name);
- }
- QualType ArgType::getRepresentativeType(ASTContext &C) const {
- QualType Res;
- switch (K) {
- case InvalidTy:
- llvm_unreachable("No representative type for Invalid ArgType");
- case UnknownTy:
- llvm_unreachable("No representative type for Unknown ArgType");
- case AnyCharTy:
- Res = C.CharTy;
- break;
- case SpecificTy:
- Res = T;
- break;
- case CStrTy:
- Res = C.getPointerType(C.CharTy);
- break;
- case WCStrTy:
- Res = C.getPointerType(C.getWideCharType());
- break;
- case ObjCPointerTy:
- Res = C.ObjCBuiltinIdTy;
- break;
- case CPointerTy:
- Res = C.VoidPtrTy;
- break;
- case WIntTy: {
- Res = C.getWIntType();
- break;
- }
- }
- if (Ptr)
- Res = C.getPointerType(Res);
- return Res;
- }
- std::string ArgType::getRepresentativeTypeName(ASTContext &C) const {
- std::string S = getRepresentativeType(C).getAsString();
- std::string Alias;
- if (Name) {
- // Use a specific name for this type, e.g. "size_t".
- Alias = Name;
- if (Ptr) {
- // If ArgType is actually a pointer to T, append an asterisk.
- Alias += (Alias[Alias.size()-1] == '*') ? "*" : " *";
- }
- // If Alias is the same as the underlying type, e.g. wchar_t, then drop it.
- if (S == Alias)
- Alias.clear();
- }
- if (!Alias.empty())
- return std::string("'") + Alias + "' (aka '" + S + "')";
- return std::string("'") + S + "'";
- }
- //===----------------------------------------------------------------------===//
- // Methods on OptionalAmount.
- //===----------------------------------------------------------------------===//
- ArgType
- analyze_format_string::OptionalAmount::getArgType(ASTContext &Ctx) const {
- return Ctx.IntTy;
- }
- //===----------------------------------------------------------------------===//
- // Methods on LengthModifier.
- //===----------------------------------------------------------------------===//
- const char *
- analyze_format_string::LengthModifier::toString() const {
- switch (kind) {
- case AsChar:
- return "hh";
- case AsShort:
- return "h";
- case AsShortLong:
- return "hl";
- case AsLong: // or AsWideChar
- return "l";
- case AsLongLong:
- return "ll";
- case AsQuad:
- return "q";
- case AsIntMax:
- return "j";
- case AsSizeT:
- return "z";
- case AsPtrDiff:
- return "t";
- case AsInt32:
- return "I32";
- case AsInt3264:
- return "I";
- case AsInt64:
- return "I64";
- case AsLongDouble:
- return "L";
- case AsAllocate:
- return "a";
- case AsMAllocate:
- return "m";
- case AsWide:
- return "w";
- case None:
- return "";
- }
- return nullptr;
- }
- //===----------------------------------------------------------------------===//
- // Methods on ConversionSpecifier.
- //===----------------------------------------------------------------------===//
- const char *ConversionSpecifier::toString() const {
- switch (kind) {
- case dArg: return "d";
- case DArg: return "D";
- case iArg: return "i";
- case oArg: return "o";
- case OArg: return "O";
- case uArg: return "u";
- case UArg: return "U";
- case xArg: return "x";
- case XArg: return "X";
- case fArg: return "f";
- case FArg: return "F";
- case eArg: return "e";
- case EArg: return "E";
- case gArg: return "g";
- case GArg: return "G";
- case aArg: return "a";
- case AArg: return "A";
- case cArg: return "c";
- case sArg: return "s";
- case pArg: return "p";
- case PArg:
- return "P";
- case nArg: return "n";
- case PercentArg: return "%";
- case ScanListArg: return "[";
- case InvalidSpecifier: return nullptr;
- // POSIX unicode extensions.
- case CArg: return "C";
- case SArg: return "S";
- // Objective-C specific specifiers.
- case ObjCObjArg: return "@";
- // FreeBSD kernel specific specifiers.
- case FreeBSDbArg: return "b";
- case FreeBSDDArg: return "D";
- case FreeBSDrArg: return "r";
- case FreeBSDyArg: return "y";
- // GlibC specific specifiers.
- case PrintErrno: return "m";
- // MS specific specifiers.
- case ZArg: return "Z";
- }
- return nullptr;
- }
- Optional<ConversionSpecifier>
- ConversionSpecifier::getStandardSpecifier() const {
- ConversionSpecifier::Kind NewKind;
- switch (getKind()) {
- default:
- return None;
- case DArg:
- NewKind = dArg;
- break;
- case UArg:
- NewKind = uArg;
- break;
- case OArg:
- NewKind = oArg;
- break;
- }
- ConversionSpecifier FixedCS(*this);
- FixedCS.setKind(NewKind);
- return FixedCS;
- }
- //===----------------------------------------------------------------------===//
- // Methods on OptionalAmount.
- //===----------------------------------------------------------------------===//
- void OptionalAmount::toString(raw_ostream &os) const {
- switch (hs) {
- case Invalid:
- case NotSpecified:
- return;
- case Arg:
- if (UsesDotPrefix)
- os << ".";
- if (usesPositionalArg())
- os << "*" << getPositionalArgIndex() << "$";
- else
- os << "*";
- break;
- case Constant:
- if (UsesDotPrefix)
- os << ".";
- os << amt;
- break;
- }
- }
- bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target,
- const LangOptions &LO) const {
- switch (LM.getKind()) {
- case LengthModifier::None:
- return true;
- // Handle most integer flags
- case LengthModifier::AsShort:
- // Length modifier only applies to FP vectors.
- if (LO.OpenCL && CS.isDoubleArg())
- return !VectorNumElts.isInvalid();
- if (Target.getTriple().isOSMSVCRT()) {
- switch (CS.getKind()) {
- case ConversionSpecifier::cArg:
- case ConversionSpecifier::CArg:
- case ConversionSpecifier::sArg:
- case ConversionSpecifier::SArg:
- case ConversionSpecifier::ZArg:
- return true;
- default:
- break;
- }
- }
- LLVM_FALLTHROUGH;
- case LengthModifier::AsChar:
- case LengthModifier::AsLongLong:
- case LengthModifier::AsQuad:
- case LengthModifier::AsIntMax:
- case LengthModifier::AsSizeT:
- case LengthModifier::AsPtrDiff:
- switch (CS.getKind()) {
- case ConversionSpecifier::dArg:
- case ConversionSpecifier::DArg:
- case ConversionSpecifier::iArg:
- case ConversionSpecifier::oArg:
- case ConversionSpecifier::OArg:
- case ConversionSpecifier::uArg:
- case ConversionSpecifier::UArg:
- case ConversionSpecifier::xArg:
- case ConversionSpecifier::XArg:
- case ConversionSpecifier::nArg:
- return true;
- case ConversionSpecifier::FreeBSDrArg:
- case ConversionSpecifier::FreeBSDyArg:
- return Target.getTriple().isOSFreeBSD() || Target.getTriple().isPS4();
- default:
- return false;
- }
- case LengthModifier::AsShortLong:
- return LO.OpenCL && !VectorNumElts.isInvalid();
- // Handle 'l' flag
- case LengthModifier::AsLong: // or AsWideChar
- if (CS.isDoubleArg()) {
- // Invalid for OpenCL FP scalars.
- if (LO.OpenCL && VectorNumElts.isInvalid())
- return false;
- return true;
- }
- switch (CS.getKind()) {
- case ConversionSpecifier::dArg:
- case ConversionSpecifier::DArg:
- case ConversionSpecifier::iArg:
- case ConversionSpecifier::oArg:
- case ConversionSpecifier::OArg:
- case ConversionSpecifier::uArg:
- case ConversionSpecifier::UArg:
- case ConversionSpecifier::xArg:
- case ConversionSpecifier::XArg:
- case ConversionSpecifier::nArg:
- case ConversionSpecifier::cArg:
- case ConversionSpecifier::sArg:
- case ConversionSpecifier::ScanListArg:
- case ConversionSpecifier::ZArg:
- return true;
- case ConversionSpecifier::FreeBSDrArg:
- case ConversionSpecifier::FreeBSDyArg:
- return Target.getTriple().isOSFreeBSD() || Target.getTriple().isPS4();
- default:
- return false;
- }
- case LengthModifier::AsLongDouble:
- switch (CS.getKind()) {
- case ConversionSpecifier::aArg:
- case ConversionSpecifier::AArg:
- case ConversionSpecifier::fArg:
- case ConversionSpecifier::FArg:
- case ConversionSpecifier::eArg:
- case ConversionSpecifier::EArg:
- case ConversionSpecifier::gArg:
- case ConversionSpecifier::GArg:
- return true;
- // GNU libc extension.
- case ConversionSpecifier::dArg:
- case ConversionSpecifier::iArg:
- case ConversionSpecifier::oArg:
- case ConversionSpecifier::uArg:
- case ConversionSpecifier::xArg:
- case ConversionSpecifier::XArg:
- return !Target.getTriple().isOSDarwin() &&
- !Target.getTriple().isOSWindows();
- default:
- return false;
- }
- case LengthModifier::AsAllocate:
- switch (CS.getKind()) {
- case ConversionSpecifier::sArg:
- case ConversionSpecifier::SArg:
- case ConversionSpecifier::ScanListArg:
- return true;
- default:
- return false;
- }
- case LengthModifier::AsMAllocate:
- switch (CS.getKind()) {
- case ConversionSpecifier::cArg:
- case ConversionSpecifier::CArg:
- case ConversionSpecifier::sArg:
- case ConversionSpecifier::SArg:
- case ConversionSpecifier::ScanListArg:
- return true;
- default:
- return false;
- }
- case LengthModifier::AsInt32:
- case LengthModifier::AsInt3264:
- case LengthModifier::AsInt64:
- switch (CS.getKind()) {
- case ConversionSpecifier::dArg:
- case ConversionSpecifier::iArg:
- case ConversionSpecifier::oArg:
- case ConversionSpecifier::uArg:
- case ConversionSpecifier::xArg:
- case ConversionSpecifier::XArg:
- return Target.getTriple().isOSMSVCRT();
- default:
- return false;
- }
- case LengthModifier::AsWide:
- switch (CS.getKind()) {
- case ConversionSpecifier::cArg:
- case ConversionSpecifier::CArg:
- case ConversionSpecifier::sArg:
- case ConversionSpecifier::SArg:
- case ConversionSpecifier::ZArg:
- return Target.getTriple().isOSMSVCRT();
- default:
- return false;
- }
- }
- llvm_unreachable("Invalid LengthModifier Kind!");
- }
- bool FormatSpecifier::hasStandardLengthModifier() const {
- switch (LM.getKind()) {
- case LengthModifier::None:
- case LengthModifier::AsChar:
- case LengthModifier::AsShort:
- case LengthModifier::AsLong:
- case LengthModifier::AsLongLong:
- case LengthModifier::AsIntMax:
- case LengthModifier::AsSizeT:
- case LengthModifier::AsPtrDiff:
- case LengthModifier::AsLongDouble:
- return true;
- case LengthModifier::AsAllocate:
- case LengthModifier::AsMAllocate:
- case LengthModifier::AsQuad:
- case LengthModifier::AsInt32:
- case LengthModifier::AsInt3264:
- case LengthModifier::AsInt64:
- case LengthModifier::AsWide:
- case LengthModifier::AsShortLong: // ???
- return false;
- }
- llvm_unreachable("Invalid LengthModifier Kind!");
- }
- bool FormatSpecifier::hasStandardConversionSpecifier(
- const LangOptions &LangOpt) const {
- switch (CS.getKind()) {
- case ConversionSpecifier::cArg:
- case ConversionSpecifier::dArg:
- case ConversionSpecifier::iArg:
- case ConversionSpecifier::oArg:
- case ConversionSpecifier::uArg:
- case ConversionSpecifier::xArg:
- case ConversionSpecifier::XArg:
- case ConversionSpecifier::fArg:
- case ConversionSpecifier::FArg:
- case ConversionSpecifier::eArg:
- case ConversionSpecifier::EArg:
- case ConversionSpecifier::gArg:
- case ConversionSpecifier::GArg:
- case ConversionSpecifier::aArg:
- case ConversionSpecifier::AArg:
- case ConversionSpecifier::sArg:
- case ConversionSpecifier::pArg:
- case ConversionSpecifier::nArg:
- case ConversionSpecifier::ObjCObjArg:
- case ConversionSpecifier::ScanListArg:
- case ConversionSpecifier::PercentArg:
- case ConversionSpecifier::PArg:
- return true;
- case ConversionSpecifier::CArg:
- case ConversionSpecifier::SArg:
- return LangOpt.ObjC;
- case ConversionSpecifier::InvalidSpecifier:
- case ConversionSpecifier::FreeBSDbArg:
- case ConversionSpecifier::FreeBSDDArg:
- case ConversionSpecifier::FreeBSDrArg:
- case ConversionSpecifier::FreeBSDyArg:
- case ConversionSpecifier::PrintErrno:
- case ConversionSpecifier::DArg:
- case ConversionSpecifier::OArg:
- case ConversionSpecifier::UArg:
- case ConversionSpecifier::ZArg:
- return false;
- }
- llvm_unreachable("Invalid ConversionSpecifier Kind!");
- }
- bool FormatSpecifier::hasStandardLengthConversionCombination() const {
- if (LM.getKind() == LengthModifier::AsLongDouble) {
- switch(CS.getKind()) {
- case ConversionSpecifier::dArg:
- case ConversionSpecifier::iArg:
- case ConversionSpecifier::oArg:
- case ConversionSpecifier::uArg:
- case ConversionSpecifier::xArg:
- case ConversionSpecifier::XArg:
- return false;
- default:
- return true;
- }
- }
- return true;
- }
- Optional<LengthModifier> FormatSpecifier::getCorrectedLengthModifier() const {
- if (CS.isAnyIntArg() || CS.getKind() == ConversionSpecifier::nArg) {
- if (LM.getKind() == LengthModifier::AsLongDouble ||
- LM.getKind() == LengthModifier::AsQuad) {
- LengthModifier FixedLM(LM);
- FixedLM.setKind(LengthModifier::AsLongLong);
- return FixedLM;
- }
- }
- return None;
- }
- bool FormatSpecifier::namedTypeToLengthModifier(QualType QT,
- LengthModifier &LM) {
- assert(isa<TypedefType>(QT) && "Expected a TypedefType");
- const TypedefNameDecl *Typedef = cast<TypedefType>(QT)->getDecl();
- for (;;) {
- const IdentifierInfo *Identifier = Typedef->getIdentifier();
- if (Identifier->getName() == "size_t") {
- LM.setKind(LengthModifier::AsSizeT);
- return true;
- } else if (Identifier->getName() == "ssize_t") {
- // Not C99, but common in Unix.
- LM.setKind(LengthModifier::AsSizeT);
- return true;
- } else if (Identifier->getName() == "intmax_t") {
- LM.setKind(LengthModifier::AsIntMax);
- return true;
- } else if (Identifier->getName() == "uintmax_t") {
- LM.setKind(LengthModifier::AsIntMax);
- return true;
- } else if (Identifier->getName() == "ptrdiff_t") {
- LM.setKind(LengthModifier::AsPtrDiff);
- return true;
- }
- QualType T = Typedef->getUnderlyingType();
- if (!isa<TypedefType>(T))
- break;
- Typedef = cast<TypedefType>(T)->getDecl();
- }
- return false;
- }
|