[llvm-branch-commits] [clang] [llvm] Add format string handling (PR #196568)
Abhina Sree via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Aug 11 06:03:32 PDT 2026
https://github.com/abhina-sree updated https://github.com/llvm/llvm-project/pull/196568
>From 334cfafb88e683840eaa4117703b567caf4784b7 Mon Sep 17 00:00:00 2001
From: Abhina Sreeskantharajan <Abhina.Sreeskantharajan at ibm.com>
Date: Fri, 8 May 2026 12:19:11 -0400
Subject: [PATCH 1/5] Add format string handling
---
clang/include/clang/AST/FormatString.h | 12 ++--
clang/lib/AST/FormatString.cpp | 86 ++++++++++++-----------
clang/lib/AST/FormatStringParsing.h | 36 +++++++---
clang/lib/AST/PrintfFormatString.cpp | 89 +++++++++++++++---------
clang/lib/AST/ScanfFormatString.cpp | 23 +++---
clang/lib/Basic/TargetInfo.cpp | 3 +-
clang/lib/Sema/SemaChecking.cpp | 54 ++++++++------
llvm/include/llvm/Support/TextEncoding.h | 10 +++
llvm/lib/Support/TextEncoding.cpp | 19 +++++
9 files changed, 215 insertions(+), 117 deletions(-)
diff --git a/clang/include/clang/AST/FormatString.h b/clang/include/clang/AST/FormatString.h
index 2c91e18491b1e..740b41d0b7743 100644
--- a/clang/include/clang/AST/FormatString.h
+++ b/clang/include/clang/AST/FormatString.h
@@ -20,6 +20,7 @@
#include "clang/AST/CanonicalType.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/TextEncoding.h"
#include <optional>
namespace clang {
@@ -764,7 +765,8 @@ class FormatStringHandler {
virtual bool HandleInvalidPrintfConversionSpecifier(
const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier,
- unsigned specifierLen) {
+ unsigned specifierLen,
+ const llvm::TextEncodingConverter &FormatStrConverter) {
return true;
}
@@ -780,10 +782,10 @@ class FormatStringHandler {
// Scanf-specific handlers.
- virtual bool
- HandleInvalidScanfConversionSpecifier(const analyze_scanf::ScanfSpecifier &FS,
- const char *startSpecifier,
- unsigned specifierLen) {
+ virtual bool HandleInvalidScanfConversionSpecifier(
+ const analyze_scanf::ScanfSpecifier &FS, const char *startSpecifier,
+ unsigned specifierLen,
+ const llvm::TextEncodingConverter &FormatStrConverter) {
return true;
}
diff --git a/clang/lib/AST/FormatString.cpp b/clang/lib/AST/FormatString.cpp
index a7569701352b3..54c3ff18bdfe5 100644
--- a/clang/lib/AST/FormatString.cpp
+++ b/clang/lib/AST/FormatString.cpp
@@ -34,8 +34,9 @@ FormatStringHandler::~FormatStringHandler() {}
// scanf format strings.
//===----------------------------------------------------------------------===//
-OptionalAmount clang::analyze_format_string::ParseAmount(const char *&Beg,
- const char *E) {
+OptionalAmount clang::analyze_format_string::ParseAmount(
+ const char *&Beg, const char *E,
+ const llvm::TextEncodingConverter &FormatStrConverter) {
const char *I = Beg;
UpdateOnReturn<const char *> UpdateBeg(Beg, I);
@@ -43,7 +44,7 @@ OptionalAmount clang::analyze_format_string::ParseAmount(const char *&Beg,
bool hasDigits = false;
for (; I != E; ++I) {
- char c = *I;
+ char c = FormatStrConverter.convert(*I);
if (c >= '0' && c <= '9') {
hasDigits = true;
accumulator = (accumulator * 10) + (c - '0');
@@ -76,21 +77,22 @@ static bool ParseWidthModifier(const char *&I, const char *E,
}
OptionalAmount clang::analyze_format_string::ParseNonPositionAmount(
- const char *&Beg, const char *E, unsigned &argIndex) {
- if (*Beg == '*') {
+ const char *&Beg, const char *E, unsigned &argIndex,
+ const llvm::TextEncodingConverter &FormatStrConverter) {
+ if (FormatStrConverter.convert(*Beg) == '*') {
++Beg;
return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg, 0, false);
}
- return ParseAmount(Beg, E);
+ return ParseAmount(Beg, E, FormatStrConverter);
}
OptionalAmount clang::analyze_format_string::ParsePositionAmount(
FormatStringHandler &H, const char *Start, const char *&Beg, const char *E,
- PositionContext p) {
- if (*Beg == '*') {
+ PositionContext p, const llvm::TextEncodingConverter &FormatStrConverter) {
+ if (FormatStrConverter.convert(*Beg) == '*') {
const char *I = Beg + 1;
- const OptionalAmount &Amt = ParseAmount(I, E);
+ const OptionalAmount &Amt = ParseAmount(I, E, FormatStrConverter);
if (Amt.getHowSpecified() == OptionalAmount::NotSpecified) {
H.HandleInvalidPosition(Beg, I - Beg, p);
@@ -105,7 +107,7 @@ OptionalAmount clang::analyze_format_string::ParsePositionAmount(
assert(Amt.getHowSpecified() == OptionalAmount::Constant);
- if (*I == '$') {
+ if (FormatStrConverter.convert(*I) == '$') {
// Handle positional arguments
// Special case: '*0$', since this is an easy mistake.
@@ -125,18 +127,21 @@ OptionalAmount clang::analyze_format_string::ParsePositionAmount(
return OptionalAmount(false);
}
- return ParseAmount(Beg, E);
+ return ParseAmount(Beg, E, FormatStrConverter);
}
bool clang::analyze_format_string::ParseFieldWidth(
FormatStringHandler &H, FormatSpecifier &CS, const char *Start,
- const char *&Beg, const char *E, unsigned *argIndex) {
+ const char *&Beg, const char *E, unsigned *argIndex,
+ const llvm::TextEncodingConverter &FormatStrConverter) {
// FIXME: Support negative field widths.
if (argIndex) {
- CS.setFieldWidth(ParseNonPositionAmount(Beg, E, *argIndex));
+ CS.setFieldWidth(
+ ParseNonPositionAmount(Beg, E, *argIndex, FormatStrConverter));
} else {
const OptionalAmount Amt = ParsePositionAmount(
- H, Start, Beg, E, analyze_format_string::FieldWidthPos);
+ H, Start, Beg, E, analyze_format_string::FieldWidthPos,
+ FormatStrConverter);
if (Amt.isInvalid())
return true;
@@ -145,14 +150,13 @@ bool clang::analyze_format_string::ParseFieldWidth(
return false;
}
-bool clang::analyze_format_string::ParseArgPosition(FormatStringHandler &H,
- FormatSpecifier &FS,
- const char *Start,
- const char *&Beg,
- const char *E) {
+bool clang::analyze_format_string::ParseArgPosition(
+ FormatStringHandler &H, FormatSpecifier &FS, const char *Start,
+ const char *&Beg, const char *E,
+ const llvm::TextEncodingConverter &FormatStrConverter) {
const char *I = Beg;
- const OptionalAmount &Amt = ParseAmount(I, E);
+ const OptionalAmount &Amt = ParseAmount(I, E, FormatStrConverter);
if (I == E) {
// No more characters left?
@@ -160,7 +164,8 @@ bool clang::analyze_format_string::ParseArgPosition(FormatStringHandler &H,
return true;
}
- if (Amt.getHowSpecified() == OptionalAmount::Constant && *(I++) == '$') {
+ if (Amt.getHowSpecified() == OptionalAmount::Constant &&
+ FormatStrConverter.convert(*(I++)) == '$') {
// Warn that positional arguments are non-standard.
H.HandlePosition(Start, I - Start);
@@ -181,16 +186,15 @@ bool clang::analyze_format_string::ParseArgPosition(FormatStringHandler &H,
return false;
}
-bool clang::analyze_format_string::ParseVectorModifier(FormatStringHandler &H,
- FormatSpecifier &FS,
- const char *&I,
- const char *E,
- const LangOptions &LO) {
+bool clang::analyze_format_string::ParseVectorModifier(
+ FormatStringHandler &H, FormatSpecifier &FS, const char *&I, const char *E,
+ const LangOptions &LO,
+ const llvm::TextEncodingConverter &FormatStrConverter) {
if (!LO.OpenCL)
return false;
const char *Start = I;
- if (*I == 'v') {
+ if (FormatStrConverter.convert(*I) == 'v') {
++I;
if (I == E) {
@@ -198,7 +202,7 @@ bool clang::analyze_format_string::ParseVectorModifier(FormatStringHandler &H,
return true;
}
- OptionalAmount NumElts = ParseAmount(I, E);
+ OptionalAmount NumElts = ParseAmount(I, E, FormatStrConverter);
if (NumElts.getHowSpecified() != OptionalAmount::Constant) {
H.HandleIncompleteSpecifier(Start, E - Start);
return true;
@@ -210,22 +214,20 @@ bool clang::analyze_format_string::ParseVectorModifier(FormatStringHandler &H,
return false;
}
-bool clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,
- const char *&I,
- const char *E,
- const LangOptions &LO,
- bool IsScanf) {
+bool clang::analyze_format_string::ParseLengthModifier(
+ FormatSpecifier &FS, const char *&I, const char *E, const LangOptions &LO,
+ const llvm::TextEncodingConverter &FormatStrConverter, bool IsScanf) {
LengthModifier::Kind lmKind = LengthModifier::None;
const char *lmPosition = I;
- switch (*I) {
+ switch (FormatStrConverter.convert(*I)) {
default:
return false;
case 'h':
++I;
- if (I != E && *I == 'h') {
+ if (I != E && FormatStrConverter.convert(*I) == 'h') {
++I;
lmKind = LengthModifier::AsChar;
- } else if (I != E && *I == 'l' && LO.OpenCL) {
+ } else if (I != E && FormatStrConverter.convert(*I) == 'l' && LO.OpenCL) {
++I;
lmKind = LengthModifier::AsShortLong;
} else {
@@ -234,7 +236,7 @@ bool clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,
break;
case 'l':
++I;
- if (I != E && *I == 'l') {
+ if (I != E && FormatStrConverter.convert(*I) == 'l') {
++I;
lmKind = LengthModifier::AsLongLong;
} else {
@@ -267,7 +269,9 @@ bool clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,
// 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 == '[')) {
+ if (I != E && (FormatStrConverter.convert(*I) == 's' ||
+ FormatStrConverter.convert(*I) == 'S' ||
+ FormatStrConverter.convert(*I) == '[')) {
lmKind = LengthModifier::AsAllocate;
break;
}
@@ -285,7 +289,8 @@ bool clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,
// scanf: AsInt64
case 'I':
if (I + 1 != E && I + 2 != E) {
- if (I[1] == '6' && I[2] == '4') {
+ if (FormatStrConverter.convert(I[1]) == '6' &&
+ FormatStrConverter.convert(I[2]) == '4') {
I += 3;
lmKind = LengthModifier::AsInt64;
break;
@@ -293,7 +298,8 @@ bool clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,
if (IsScanf)
return false;
- if (I[1] == '3' && I[2] == '2') {
+ if (FormatStrConverter.convert(I[1]) == '3' &&
+ FormatStrConverter.convert(I[2]) == '2') {
I += 3;
lmKind = LengthModifier::AsInt32;
break;
diff --git a/clang/lib/AST/FormatStringParsing.h b/clang/lib/AST/FormatStringParsing.h
index 401528481a9d6..531bc291e0b5b 100644
--- a/clang/lib/AST/FormatStringParsing.h
+++ b/clang/lib/AST/FormatStringParsing.h
@@ -35,29 +35,43 @@ template <typename T> class UpdateOnReturn {
namespace analyze_format_string {
-OptionalAmount ParseAmount(const char *&Beg, const char *E);
-OptionalAmount ParseNonPositionAmount(const char *&Beg, const char *E,
- unsigned &argIndex);
+OptionalAmount
+ParseAmount(const char *&Beg, const char *E,
+ const llvm::TextEncodingConverter &FormatStrConverter);
-OptionalAmount ParsePositionAmount(FormatStringHandler &H, const char *Start,
- const char *&Beg, const char *E,
- PositionContext p);
+OptionalAmount
+ParseNonPositionAmount(const char *&Beg, const char *E, unsigned &argIndex,
+ const llvm::TextEncodingConverter &FormatStrConverter);
+
+OptionalAmount
+ParsePositionAmount(FormatStringHandler &H, const char *Start, const char *&Beg,
+ const char *E, PositionContext p,
+ const llvm::TextEncodingConverter &FormatStrConverter);
+
+OptionalAmount
+ParsePositionAmount(FormatStringHandler &H, const char *Start, const char *&Beg,
+ const char *E, PositionContext p,
+ const llvm::TextEncodingConverter &FormatStrConverter);
bool ParseFieldWidth(FormatStringHandler &H, FormatSpecifier &CS,
const char *Start, const char *&Beg, const char *E,
- unsigned *argIndex);
+ unsigned *argIndex,
+ const llvm::TextEncodingConverter &FormatStrConverter);
bool ParseArgPosition(FormatStringHandler &H, FormatSpecifier &CS,
- const char *Start, const char *&Beg, const char *E);
+ const char *Start, const char *&Beg, const char *E,
+ const llvm::TextEncodingConverter &FormatStrConverter);
bool ParseVectorModifier(FormatStringHandler &H, FormatSpecifier &FS,
- const char *&Beg, const char *E,
- const LangOptions &LO);
+ const char *&Beg, const char *E, const LangOptions &LO,
+ const llvm::TextEncodingConverter &FormatStrConverter);
/// Returns true if a LengthModifier was parsed and installed in the
/// FormatSpecifier& argument, and false otherwise.
bool ParseLengthModifier(FormatSpecifier &FS, const char *&Beg, const char *E,
- const LangOptions &LO, bool IsScanf = false);
+ const LangOptions &LO,
+ const llvm::TextEncodingConverter &FormatStrConverter,
+ bool IsScanf = false);
/// Returns true if the invalid specifier in \p SpecifierBegin is a UTF-8
/// string; check that it won't go further than \p FmtStrEnd and write
diff --git a/clang/lib/AST/PrintfFormatString.cpp b/clang/lib/AST/PrintfFormatString.cpp
index 4b56157d64a5d..be6247cd7bd28 100644
--- a/clang/lib/AST/PrintfFormatString.cpp
+++ b/clang/lib/AST/PrintfFormatString.cpp
@@ -35,14 +35,17 @@ typedef clang::analyze_format_string::SpecifierResult<PrintfSpecifier>
using analyze_format_string::ParseNonPositionAmount;
-static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS,
- const char *Start, const char *&Beg, const char *E,
- unsigned *argIndex) {
+static bool
+ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS, const char *Start,
+ const char *&Beg, const char *E, unsigned *argIndex,
+ const llvm::TextEncodingConverter &FormatStrConverter) {
if (argIndex) {
- FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex));
+ FS.setPrecision(
+ ParseNonPositionAmount(Beg, E, *argIndex, FormatStrConverter));
} else {
const OptionalAmount Amt = ParsePositionAmount(
- H, Start, Beg, E, analyze_format_string::PrecisionPos);
+ H, Start, Beg, E, analyze_format_string::PrecisionPos,
+ FormatStrConverter);
if (Amt.isInvalid())
return true;
FS.setPrecision(Amt);
@@ -50,11 +53,14 @@ static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS,
return false;
}
-static bool ParseObjCFlags(FormatStringHandler &H, PrintfSpecifier &FS,
- const char *FlagBeg, const char *E, bool Warn) {
+static bool
+ParseObjCFlags(FormatStringHandler &H, PrintfSpecifier &FS, const char *FlagBeg,
+ const char *E, bool Warn,
+ const llvm::TextEncodingConverter &FormatStrConverter) {
StringRef Flag(FlagBeg, E - FlagBeg);
// Currently there is only one flag.
- if (Flag == "tt") {
+ if (Flag.size() == 2 && FormatStrConverter.convert(FlagBeg[0]) == 't' &&
+ FormatStrConverter.convert(FlagBeg[1]) == 't') {
FS.setHasObjCTechnicalTerm(FlagBeg);
return false;
}
@@ -81,6 +87,8 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
const char *Start = nullptr;
UpdateOnReturn<const char *> UpdateBeg(Beg, I);
+ const llvm::TextEncodingConverter &FormatStrConverter =
+ *Target.FormatStrConverter;
// Look for a '%' character that indicates the start of a format specifier.
for (; I != E; ++I) {
char c = *I;
@@ -89,7 +97,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
H.HandleNullChar(I);
return true;
}
- if (c == '%') {
+ if (FormatStrConverter.convert(c) == '%') {
Start = I++; // Record the start of the format specifier.
break;
}
@@ -107,7 +115,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
}
PrintfSpecifier FS;
- if (ParseArgPosition(H, FS, Start, I, E))
+ if (ParseArgPosition(H, FS, Start, I, E, FormatStrConverter))
return true;
if (I == E) {
@@ -117,13 +125,17 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
return true;
}
- if (*I == '{') {
+ if (FormatStrConverter.convert(*I) == '{') {
++I;
unsigned char PrivacyFlags = 0;
StringRef MatchedStr;
do {
- StringRef Str(I, E - I);
+ const char *II;
+ std::string S(I, E - I);
+ for (unsigned long i = 0; i < S.length(); ++i)
+ S[i] = FormatStrConverter.convert(S[i]);
+ StringRef Str(S);
std::string Match = "^[[:space:]]*"
"(private|public|sensitive|mask\\.[^[:space:],}]*)"
"[[:space:]]*(,|})";
@@ -132,25 +144,38 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
if (R.match(Str, &Matches)) {
MatchedStr = Matches[1];
+ II = I;
I += Matches[0].size();
+ while (FormatStrConverter.convert(*II) == ' ')
+ ++II;
+
// Set the privacy flag if the privacy annotation in the
// comma-delimited segment is at least as strict as the privacy
// annotations in previous comma-delimited segments.
if (MatchedStr.starts_with("mask")) {
- StringRef MaskType = MatchedStr.substr(sizeof("mask.") - 1);
+ StringRef MaskType(II + sizeof("mask.") - 1,
+ MatchedStr.size() - sizeof("mask.") + 1);
unsigned Size = MaskType.size();
+
if (Warn && (Size == 0 || Size > 8))
H.handleInvalidMaskType(MaskType);
FS.setMaskType(MaskType);
- } else if (MatchedStr == "sensitive")
+ } else if (MatchedStr == "sensitive") {
+ StringRef ProxyMatchedStr(II, sizeof("sensitive") - 1);
+ MatchedStr = ProxyMatchedStr;
PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsSensitive;
- else if (PrivacyFlags !=
- clang::analyze_os_log::OSLogBufferItem::IsSensitive &&
- MatchedStr == "private")
+ } else if (PrivacyFlags !=
+ clang::analyze_os_log::OSLogBufferItem::IsSensitive &&
+ MatchedStr == "private") {
+ StringRef ProxyMatchedStr(II, sizeof("private") - 1);
+ MatchedStr = ProxyMatchedStr;
PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPrivate;
- else if (PrivacyFlags == 0 && MatchedStr == "public")
+ } else if (PrivacyFlags == 0 && MatchedStr == "public") {
+ StringRef ProxyMatchedStr(II, sizeof("public") - 1);
+ MatchedStr = ProxyMatchedStr;
PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPublic;
+ }
} else {
size_t CommaOrBracePos =
Str.find_if([](char c) { return c == ',' || c == '}'; });
@@ -165,7 +190,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
I += CommaOrBracePos + 1;
}
// Continue until the closing brace is found.
- } while (*(I - 1) == ',');
+ } while (FormatStrConverter.convert(*(I - 1)) == ',');
// Set the privacy flag.
switch (PrivacyFlags) {
@@ -188,7 +213,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
// Look for flags (if any).
bool hasMore = true;
for (; I != E; ++I) {
- switch (*I) {
+ switch (FormatStrConverter.convert(*I)) {
default:
hasMore = false;
break;
@@ -225,7 +250,8 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
// Look for the field width (if any).
if (ParseFieldWidth(H, FS, Start, I, E,
- FS.usesPositionalArg() ? nullptr : &argIndex))
+ FS.usesPositionalArg() ? nullptr : &argIndex,
+ FormatStrConverter))
return true;
if (I == E) {
@@ -236,7 +262,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
}
// Look for the precision (if any).
- if (*I == '.') {
+ if (FormatStrConverter.convert(*I) == '.') {
++I;
if (I == E) {
if (Warn)
@@ -245,7 +271,8 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
}
if (ParsePrecision(H, FS, Start, I, E,
- FS.usesPositionalArg() ? nullptr : &argIndex))
+ FS.usesPositionalArg() ? nullptr : &argIndex,
+ FormatStrConverter))
return true;
if (I == E) {
@@ -256,11 +283,11 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
}
}
- if (ParseVectorModifier(H, FS, I, E, LO))
+ if (ParseVectorModifier(H, FS, I, E, LO, FormatStrConverter))
return true;
// Look for the length modifier.
- if (ParseLengthModifier(FS, I, E, LO) && I == E) {
+ if (ParseLengthModifier(FS, I, E, LO, FormatStrConverter) && I == E) {
// No more characters left?
if (Warn)
H.HandleIncompleteSpecifier(Start, E - Start);
@@ -274,7 +301,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
// enables better recovery, and we don't know if
// these flags are applicable until later.
const char *ObjCModifierFlagsStart = nullptr, *ObjCModifierFlagsEnd = nullptr;
- if (*I == '[') {
+ if (FormatStrConverter.convert(*I) == '[') {
ObjCModifierFlagsStart = I;
++I;
auto flagStart = I;
@@ -286,8 +313,8 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
return true;
}
// Did we find the closing ']'?
- if (*I == ']') {
- if (ParseObjCFlags(H, FS, flagStart, I, Warn))
+ if (FormatStrConverter.convert(*I) == ']') {
+ if (ParseObjCFlags(H, FS, flagStart, I, Warn, FormatStrConverter))
return true;
++I;
break;
@@ -307,7 +334,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
// Finally, look for the conversion specifier.
const char *conversionPosition = I++;
ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier;
- switch (*conversionPosition) {
+ switch (FormatStrConverter.convert(*conversionPosition)) {
default:
break;
// C99: 7.19.6.1 (section 8).
@@ -470,7 +497,8 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
FS.setConversionSpecifier(CS);
}
// Assume the conversion takes one argument.
- return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, Len);
+ return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, Len,
+ FormatStrConverter);
}
return PrintfSpecifierResult(Start, FS);
}
@@ -480,7 +508,6 @@ bool clang::analyze_format_string::ParsePrintfString(
const TargetInfo &Target, bool isFreeBSDKPrintf) {
unsigned argIndex = 0;
-
// Keep looking for a format specifier until we have exhausted the string.
while (I != E) {
const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(
diff --git a/clang/lib/AST/ScanfFormatString.cpp b/clang/lib/AST/ScanfFormatString.cpp
index 5e1622e95277b..8a1404a7fa0cd 100644
--- a/clang/lib/AST/ScanfFormatString.cpp
+++ b/clang/lib/AST/ScanfFormatString.cpp
@@ -81,7 +81,8 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
const char *I = Beg;
const char *Start = nullptr;
UpdateOnReturn<const char *> UpdateBeg(Beg, I);
-
+ const llvm::TextEncodingConverter &FormatStrConverter =
+ *Target.FormatStrConverter;
// Look for a '%' character that indicates the start of a format specifier.
for (; I != E; ++I) {
char c = *I;
@@ -90,7 +91,9 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
H.HandleNullChar(I);
return true;
}
- if (c == '%') {
+ SmallString<1> ConvertedChar;
+ FormatStrConverter.convert(StringRef(&c, 1), ConvertedChar);
+ if (ConvertedChar[0] == '%') {
Start = I++; // Record the start of the format specifier.
break;
}
@@ -107,7 +110,7 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
}
ScanfSpecifier FS;
- if (ParseArgPosition(H, FS, Start, I, E))
+ if (ParseArgPosition(H, FS, Start, I, E, FormatStrConverter))
return true;
if (I == E) {
@@ -117,7 +120,7 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
}
// Look for '*' flag if it is present.
- if (*I == '*') {
+ if (FormatStrConverter.convert(*I) == '*') {
FS.setSuppressAssignment(I);
if (++I == E) {
H.HandleIncompleteSpecifier(Start, E - Start);
@@ -127,7 +130,8 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
// Look for the field width (if any). Unlike printf, this is either
// a fixed integer or isn't present.
- const OptionalAmount &Amt = clang::analyze_format_string::ParseAmount(I, E);
+ const OptionalAmount &Amt =
+ clang::analyze_format_string::ParseAmount(I, E, FormatStrConverter);
if (Amt.getHowSpecified() != OptionalAmount::NotSpecified) {
assert(Amt.getHowSpecified() == OptionalAmount::Constant);
FS.setFieldWidth(Amt);
@@ -140,7 +144,9 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
}
// Look for the length modifier.
- if (ParseLengthModifier(FS, I, E, LO, /*IsScanf=*/true) && I == E) {
+ if (ParseLengthModifier(FS, I, E, LO, FormatStrConverter,
+ /*IsScanf=*/true) &&
+ I == E) {
// No more characters left?
H.HandleIncompleteSpecifier(Start, E - Start);
return true;
@@ -155,7 +161,7 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
// Finally, look for the conversion specifier.
const char *conversionPosition = I++;
ScanfConversionSpecifier::Kind k = ScanfConversionSpecifier::InvalidSpecifier;
- switch (*conversionPosition) {
+ switch (FormatStrConverter.convert(*conversionPosition)) {
default:
break;
case '%':
@@ -262,7 +268,8 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
FS.setConversionSpecifier(CS);
}
// Assume the conversion takes one argument.
- return !H.HandleInvalidScanfConversionSpecifier(FS, Beg, Len);
+ return !H.HandleInvalidScanfConversionSpecifier(FS, Beg, Len,
+ FormatStrConverter);
}
return ScanfSpecifierResult(Start, FS);
}
diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp
index c318f2cfc40b3..5d2b1d26e3a08 100644
--- a/clang/lib/Basic/TargetInfo.cpp
+++ b/clang/lib/Basic/TargetInfo.cpp
@@ -195,7 +195,8 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : Triple(T) {
MaxBitIntWidth.reset();
- FromSystemEncodingConverter = nullptr;
+ FromSystemEncodingConverter = new llvm::TextEncodingConverter(
+ std::move(*llvm::TextEncodingConverter::createNoopConverter()));
}
// Out of line virtual dtor for TargetInfo.
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 01b1f4c26f017..6364440aff64e 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -104,6 +104,7 @@
#include "llvm/Support/Locale.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/SaveAndRestore.h"
+#include "llvm/Support/TextEncoding.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TargetParser/RISCVTargetParser.h"
#include "llvm/TargetParser/Triple.h"
@@ -8095,10 +8096,10 @@ class CheckFormatHandler : public analyze_format_string::FormatStringHandler {
ArrayRef<FixItHint> Fixit = {});
protected:
- bool HandleInvalidConversionSpecifier(unsigned argIndex, SourceLocation Loc,
- const char *startSpec,
- unsigned specifierLen,
- const char *csStart, unsigned csLen);
+ bool HandleInvalidConversionSpecifier(
+ unsigned argIndex, SourceLocation Loc, const char *startSpec,
+ unsigned specifierLen, const char *csStart, unsigned csLen,
+ const llvm::TextEncodingConverter &FormatStrConverter);
void HandlePositionalNonpositionalArgs(SourceLocation Loc,
const char *startSpec,
@@ -8345,7 +8346,8 @@ void UncoveredArgHandler::Diagnose(Sema &S, bool IsFunctionCall,
bool CheckFormatHandler::HandleInvalidConversionSpecifier(
unsigned argIndex, SourceLocation Loc, const char *startSpec,
- unsigned specifierLen, const char *csStart, unsigned csLen) {
+ unsigned specifierLen, const char *csStart, unsigned csLen,
+ const llvm::TextEncodingConverter &FormatStrConverter) {
bool keepGoing = true;
if (argIndex < NumDataArgs) {
// Consider the argument coverered, even though the specifier doesn't
@@ -8360,7 +8362,13 @@ bool CheckFormatHandler::HandleInvalidConversionSpecifier(
keepGoing = false;
}
- StringRef Specifier(csStart, csLen);
+ // The csStart points to a character that has already been converted to the
+ // exec charset, so we have to reverse the conversion to allow diagnostic
+ // message to match an expected value when using -verify option,
+ std::string RS(csStart, csLen);
+ for (unsigned int i = 0; i < RS.size(); ++i)
+ RS[i] = FormatStrConverter.convert(RS[i]);
+ StringRef Specifier(RS);
// If the specifier in non-printable, it could be the first byte of a UTF-8
// sequence. In that case, print the UTF-8 code point. If not, print the byte
@@ -8514,7 +8522,8 @@ class CheckPrintfHandler : public CheckFormatHandler {
bool HandleInvalidPrintfConversionSpecifier(
const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier,
- unsigned specifierLen) override;
+ unsigned specifierLen,
+ const llvm::TextEncodingConverter &FormatStrConverter) override;
void handleInvalidMaskType(StringRef MaskType) override;
@@ -8654,13 +8663,14 @@ class DecomposePrintfHandler : public CheckPrintfHandler {
bool CheckPrintfHandler::HandleInvalidPrintfConversionSpecifier(
const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier,
- unsigned specifierLen) {
+ unsigned specifierLen,
+ const llvm::TextEncodingConverter &FormatStrConverter) {
const analyze_printf::PrintfConversionSpecifier &CS =
FS.getConversionSpecifier();
return HandleInvalidConversionSpecifier(
FS.getArgIndex(), getLocationOfByte(CS.getStart()), startSpecifier,
- specifierLen, CS.getStart(), CS.getLength());
+ specifierLen, CS.getStart(), CS.getLength(), FormatStrConverter);
}
void CheckPrintfHandler::handleInvalidMaskType(StringRef MaskType) {
@@ -9168,15 +9178,15 @@ bool CheckPrintfHandler::HandlePrintfSpecifier(
// Check for using an Objective-C specific conversion specifier
// in a non-ObjC literal.
if (!allowsObjCArg() && CS.isObjCArg()) {
- return HandleInvalidPrintfConversionSpecifier(FS, startSpecifier,
- specifierLen);
+ return HandleInvalidPrintfConversionSpecifier(
+ FS, startSpecifier, specifierLen, *Target.FormatStrConverter);
}
// %P can only be used with os_log.
if (FSType != FormatStringType::OSLog &&
CS.getKind() == ConversionSpecifier::PArg) {
- return HandleInvalidPrintfConversionSpecifier(FS, startSpecifier,
- specifierLen);
+ return HandleInvalidPrintfConversionSpecifier(
+ FS, startSpecifier, specifierLen, *Target.FormatStrConverter);
}
// %n is not allowed with os_log.
@@ -9195,8 +9205,8 @@ bool CheckPrintfHandler::HandlePrintfSpecifier(
(CS.getKind() == ConversionSpecifier::PArg ||
CS.getKind() == ConversionSpecifier::sArg ||
CS.getKind() == ConversionSpecifier::ObjCObjArg)) {
- return HandleInvalidPrintfConversionSpecifier(FS, startSpecifier,
- specifierLen);
+ return HandleInvalidPrintfConversionSpecifier(
+ FS, startSpecifier, specifierLen, *Target.FormatStrConverter);
}
// Check for use of public/private annotation outside of os_log().
@@ -9872,10 +9882,10 @@ class CheckScanfHandler : public CheckFormatHandler {
const char *startSpecifier,
unsigned specifierLen) override;
- bool
- HandleInvalidScanfConversionSpecifier(const analyze_scanf::ScanfSpecifier &FS,
- const char *startSpecifier,
- unsigned specifierLen) override;
+ bool HandleInvalidScanfConversionSpecifier(
+ const analyze_scanf::ScanfSpecifier &FS, const char *startSpecifier,
+ unsigned specifierLen,
+ const llvm::TextEncodingConverter &FormatStrConverter) override;
void HandleIncompleteScanList(const char *start, const char *end) override;
};
@@ -9891,13 +9901,15 @@ void CheckScanfHandler::HandleIncompleteScanList(const char *start,
bool CheckScanfHandler::HandleInvalidScanfConversionSpecifier(
const analyze_scanf::ScanfSpecifier &FS, const char *startSpecifier,
- unsigned specifierLen) {
+ unsigned specifierLen,
+ const llvm::TextEncodingConverter &FormatStrConverter) {
+
const analyze_scanf::ScanfConversionSpecifier &CS =
FS.getConversionSpecifier();
return HandleInvalidConversionSpecifier(
FS.getArgIndex(), getLocationOfByte(CS.getStart()), startSpecifier,
- specifierLen, CS.getStart(), CS.getLength());
+ specifierLen, CS.getStart(), CS.getLength(), FormatStrConverter);
}
bool CheckScanfHandler::HandleScanfSpecifier(
diff --git a/llvm/include/llvm/Support/TextEncoding.h b/llvm/include/llvm/Support/TextEncoding.h
index 6e7eb95464eff..734972b892ecc 100644
--- a/llvm/include/llvm/Support/TextEncoding.h
+++ b/llvm/include/llvm/Support/TextEncoding.h
@@ -104,6 +104,8 @@ class TextEncodingConverter {
LLVM_ABI static ErrorOr<TextEncodingConverter> create(StringRef From,
StringRef To);
+ LLVM_ABI static ErrorOr<TextEncodingConverter> createNoopConverter();
+
TextEncodingConverter(const TextEncodingConverter &) = delete;
TextEncodingConverter &operator=(const TextEncodingConverter &) = delete;
@@ -134,6 +136,14 @@ class TextEncodingConverter {
return std::string(Result);
return EC;
}
+
+ char convert(char SingleChar) const {
+ SmallString<1> Result;
+ auto EC = Converter->convert(StringRef(&SingleChar, 1), Result);
+ if (!EC)
+ return Result[0];
+ return '\0';
+ }
};
} // namespace llvm
diff --git a/llvm/lib/Support/TextEncoding.cpp b/llvm/lib/Support/TextEncoding.cpp
index c44bf78ea9fba..9672cba006a2c 100644
--- a/llvm/lib/Support/TextEncoding.cpp
+++ b/llvm/lib/Support/TextEncoding.cpp
@@ -357,3 +357,22 @@ ErrorOr<TextEncodingConverter> TextEncodingConverter::create(StringRef From,
return std::make_error_code(std::errc::invalid_argument);
#endif
}
+
+class TextEncodingConverterNoop final
+ : public details::TextEncodingConverterImplBase {
+
+public:
+ TextEncodingConverterNoop() {}
+
+ std::error_code convertString(StringRef Source,
+ SmallVectorImpl<char> &Result) override {
+ Result.assign(Source.begin(), Source.end());
+ return std::error_code();
+ }
+
+ void reset() override {}
+};
+
+ErrorOr<TextEncodingConverter> TextEncodingConverter::createNoopConverter() {
+ return TextEncodingConverter(std::make_unique<TextEncodingConverterNoop>());
+}
>From 4ef301bba052c7dd918571de652fd34d21259201 Mon Sep 17 00:00:00 2001
From: Abhina Sreeskantharajan <Abhina.Sreeskantharajan at ibm.com>
Date: Thu, 28 May 2026 15:16:49 -0400
Subject: [PATCH 2/5] do not convert character by character
---
clang/include/clang/AST/FormatString.h | 4 +-
clang/lib/AST/FormatString.cpp | 65 ++++++++++++++------------
clang/lib/AST/FormatStringParsing.h | 54 ++++++++++-----------
clang/lib/AST/PrintfFormatString.cpp | 55 +++++++++++-----------
clang/lib/AST/ScanfFormatString.cpp | 22 ++++-----
clang/lib/Basic/TargetInfo.cpp | 2 +-
clang/lib/Sema/SemaChecking.cpp | 32 +++++++------
7 files changed, 122 insertions(+), 112 deletions(-)
diff --git a/clang/include/clang/AST/FormatString.h b/clang/include/clang/AST/FormatString.h
index 740b41d0b7743..760056dabfc80 100644
--- a/clang/include/clang/AST/FormatString.h
+++ b/clang/include/clang/AST/FormatString.h
@@ -766,7 +766,7 @@ class FormatStringHandler {
virtual bool HandleInvalidPrintfConversionSpecifier(
const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier,
unsigned specifierLen,
- const llvm::TextEncodingConverter &FormatStrConverter) {
+ const llvm::TextEncodingConverter &FromSystemEncodingConverter) {
return true;
}
@@ -785,7 +785,7 @@ class FormatStringHandler {
virtual bool HandleInvalidScanfConversionSpecifier(
const analyze_scanf::ScanfSpecifier &FS, const char *startSpecifier,
unsigned specifierLen,
- const llvm::TextEncodingConverter &FormatStrConverter) {
+ const llvm::TextEncodingConverter &FromSystemEncodingConverter) {
return true;
}
diff --git a/clang/lib/AST/FormatString.cpp b/clang/lib/AST/FormatString.cpp
index 54c3ff18bdfe5..e804aafa8a9e1 100644
--- a/clang/lib/AST/FormatString.cpp
+++ b/clang/lib/AST/FormatString.cpp
@@ -36,7 +36,7 @@ FormatStringHandler::~FormatStringHandler() {}
OptionalAmount clang::analyze_format_string::ParseAmount(
const char *&Beg, const char *E,
- const llvm::TextEncodingConverter &FormatStrConverter) {
+ const llvm::TextEncodingConverter &FromSystemEncodingConverter) {
const char *I = Beg;
UpdateOnReturn<const char *> UpdateBeg(Beg, I);
@@ -44,7 +44,7 @@ OptionalAmount clang::analyze_format_string::ParseAmount(
bool hasDigits = false;
for (; I != E; ++I) {
- char c = FormatStrConverter.convert(*I);
+ char c = FromSystemEncodingConverter.convert(*I);
if (c >= '0' && c <= '9') {
hasDigits = true;
accumulator = (accumulator * 10) + (c - '0');
@@ -78,21 +78,22 @@ static bool ParseWidthModifier(const char *&I, const char *E,
OptionalAmount clang::analyze_format_string::ParseNonPositionAmount(
const char *&Beg, const char *E, unsigned &argIndex,
- const llvm::TextEncodingConverter &FormatStrConverter) {
- if (FormatStrConverter.convert(*Beg) == '*') {
+ const llvm::TextEncodingConverter &FromSystemEncodingConverter) {
+ if (FromSystemEncodingConverter.convert(*Beg) == '*') {
++Beg;
return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg, 0, false);
}
- return ParseAmount(Beg, E, FormatStrConverter);
+ return ParseAmount(Beg, E, FromSystemEncodingConverter);
}
OptionalAmount clang::analyze_format_string::ParsePositionAmount(
FormatStringHandler &H, const char *Start, const char *&Beg, const char *E,
- PositionContext p, const llvm::TextEncodingConverter &FormatStrConverter) {
- if (FormatStrConverter.convert(*Beg) == '*') {
+ PositionContext p,
+ const llvm::TextEncodingConverter &FromSystemEncodingConverter) {
+ if (FromSystemEncodingConverter.convert(*Beg) == '*') {
const char *I = Beg + 1;
- const OptionalAmount &Amt = ParseAmount(I, E, FormatStrConverter);
+ const OptionalAmount &Amt = ParseAmount(I, E, FromSystemEncodingConverter);
if (Amt.getHowSpecified() == OptionalAmount::NotSpecified) {
H.HandleInvalidPosition(Beg, I - Beg, p);
@@ -107,7 +108,7 @@ OptionalAmount clang::analyze_format_string::ParsePositionAmount(
assert(Amt.getHowSpecified() == OptionalAmount::Constant);
- if (FormatStrConverter.convert(*I) == '$') {
+ if (FromSystemEncodingConverter.convert(*I) == '$') {
// Handle positional arguments
// Special case: '*0$', since this is an easy mistake.
@@ -127,21 +128,21 @@ OptionalAmount clang::analyze_format_string::ParsePositionAmount(
return OptionalAmount(false);
}
- return ParseAmount(Beg, E, FormatStrConverter);
+ return ParseAmount(Beg, E, FromSystemEncodingConverter);
}
bool clang::analyze_format_string::ParseFieldWidth(
FormatStringHandler &H, FormatSpecifier &CS, const char *Start,
const char *&Beg, const char *E, unsigned *argIndex,
- const llvm::TextEncodingConverter &FormatStrConverter) {
+ const llvm::TextEncodingConverter &FromSystemEncodingConverter) {
// FIXME: Support negative field widths.
if (argIndex) {
CS.setFieldWidth(
- ParseNonPositionAmount(Beg, E, *argIndex, FormatStrConverter));
+ ParseNonPositionAmount(Beg, E, *argIndex, FromSystemEncodingConverter));
} else {
const OptionalAmount Amt = ParsePositionAmount(
H, Start, Beg, E, analyze_format_string::FieldWidthPos,
- FormatStrConverter);
+ FromSystemEncodingConverter);
if (Amt.isInvalid())
return true;
@@ -153,10 +154,10 @@ bool clang::analyze_format_string::ParseFieldWidth(
bool clang::analyze_format_string::ParseArgPosition(
FormatStringHandler &H, FormatSpecifier &FS, const char *Start,
const char *&Beg, const char *E,
- const llvm::TextEncodingConverter &FormatStrConverter) {
+ const llvm::TextEncodingConverter &FromSystemEncodingConverter) {
const char *I = Beg;
- const OptionalAmount &Amt = ParseAmount(I, E, FormatStrConverter);
+ const OptionalAmount &Amt = ParseAmount(I, E, FromSystemEncodingConverter);
if (I == E) {
// No more characters left?
@@ -165,7 +166,7 @@ bool clang::analyze_format_string::ParseArgPosition(
}
if (Amt.getHowSpecified() == OptionalAmount::Constant &&
- FormatStrConverter.convert(*(I++)) == '$') {
+ FromSystemEncodingConverter.convert(*(I++)) == '$') {
// Warn that positional arguments are non-standard.
H.HandlePosition(Start, I - Start);
@@ -189,12 +190,12 @@ bool clang::analyze_format_string::ParseArgPosition(
bool clang::analyze_format_string::ParseVectorModifier(
FormatStringHandler &H, FormatSpecifier &FS, const char *&I, const char *E,
const LangOptions &LO,
- const llvm::TextEncodingConverter &FormatStrConverter) {
+ const llvm::TextEncodingConverter &FromSystemEncodingConverter) {
if (!LO.OpenCL)
return false;
const char *Start = I;
- if (FormatStrConverter.convert(*I) == 'v') {
+ if (FromSystemEncodingConverter.convert(*I) == 'v') {
++I;
if (I == E) {
@@ -202,7 +203,7 @@ bool clang::analyze_format_string::ParseVectorModifier(
return true;
}
- OptionalAmount NumElts = ParseAmount(I, E, FormatStrConverter);
+ OptionalAmount NumElts = ParseAmount(I, E, FromSystemEncodingConverter);
if (NumElts.getHowSpecified() != OptionalAmount::Constant) {
H.HandleIncompleteSpecifier(Start, E - Start);
return true;
@@ -216,18 +217,20 @@ bool clang::analyze_format_string::ParseVectorModifier(
bool clang::analyze_format_string::ParseLengthModifier(
FormatSpecifier &FS, const char *&I, const char *E, const LangOptions &LO,
- const llvm::TextEncodingConverter &FormatStrConverter, bool IsScanf) {
+ const llvm::TextEncodingConverter &FromSystemEncodingConverter,
+ bool IsScanf) {
LengthModifier::Kind lmKind = LengthModifier::None;
const char *lmPosition = I;
- switch (FormatStrConverter.convert(*I)) {
+ switch (FromSystemEncodingConverter.convert(*I)) {
default:
return false;
case 'h':
++I;
- if (I != E && FormatStrConverter.convert(*I) == 'h') {
+ if (I != E && FromSystemEncodingConverter.convert(*I) == 'h') {
++I;
lmKind = LengthModifier::AsChar;
- } else if (I != E && FormatStrConverter.convert(*I) == 'l' && LO.OpenCL) {
+ } else if (I != E && FromSystemEncodingConverter.convert(*I) == 'l' &&
+ LO.OpenCL) {
++I;
lmKind = LengthModifier::AsShortLong;
} else {
@@ -236,7 +239,7 @@ bool clang::analyze_format_string::ParseLengthModifier(
break;
case 'l':
++I;
- if (I != E && FormatStrConverter.convert(*I) == 'l') {
+ if (I != E && FromSystemEncodingConverter.convert(*I) == 'l') {
++I;
lmKind = LengthModifier::AsLongLong;
} else {
@@ -269,9 +272,9 @@ bool clang::analyze_format_string::ParseLengthModifier(
// be parsed as the GNU extension 'a' length modifier. If not, this
// will be parsed as a conversion specifier.
++I;
- if (I != E && (FormatStrConverter.convert(*I) == 's' ||
- FormatStrConverter.convert(*I) == 'S' ||
- FormatStrConverter.convert(*I) == '[')) {
+ if (I != E && (FromSystemEncodingConverter.convert(*I) == 's' ||
+ FromSystemEncodingConverter.convert(*I) == 'S' ||
+ FromSystemEncodingConverter.convert(*I) == '[')) {
lmKind = LengthModifier::AsAllocate;
break;
}
@@ -289,8 +292,8 @@ bool clang::analyze_format_string::ParseLengthModifier(
// scanf: AsInt64
case 'I':
if (I + 1 != E && I + 2 != E) {
- if (FormatStrConverter.convert(I[1]) == '6' &&
- FormatStrConverter.convert(I[2]) == '4') {
+ if (FromSystemEncodingConverter.convert(I[1]) == '6' &&
+ FromSystemEncodingConverter.convert(I[2]) == '4') {
I += 3;
lmKind = LengthModifier::AsInt64;
break;
@@ -298,8 +301,8 @@ bool clang::analyze_format_string::ParseLengthModifier(
if (IsScanf)
return false;
- if (FormatStrConverter.convert(I[1]) == '3' &&
- FormatStrConverter.convert(I[2]) == '2') {
+ if (FromSystemEncodingConverter.convert(I[1]) == '3' &&
+ FromSystemEncodingConverter.convert(I[2]) == '2') {
I += 3;
lmKind = LengthModifier::AsInt32;
break;
diff --git a/clang/lib/AST/FormatStringParsing.h b/clang/lib/AST/FormatStringParsing.h
index 531bc291e0b5b..164efb9d847b9 100644
--- a/clang/lib/AST/FormatStringParsing.h
+++ b/clang/lib/AST/FormatStringParsing.h
@@ -37,41 +37,43 @@ namespace analyze_format_string {
OptionalAmount
ParseAmount(const char *&Beg, const char *E,
- const llvm::TextEncodingConverter &FormatStrConverter);
+ const llvm::TextEncodingConverter &FromSystemEncodingConverter);
-OptionalAmount
-ParseNonPositionAmount(const char *&Beg, const char *E, unsigned &argIndex,
- const llvm::TextEncodingConverter &FormatStrConverter);
+OptionalAmount ParseNonPositionAmount(
+ const char *&Beg, const char *E, unsigned &argIndex,
+ const llvm::TextEncodingConverter &FromSystemEncodingConverter);
-OptionalAmount
-ParsePositionAmount(FormatStringHandler &H, const char *Start, const char *&Beg,
- const char *E, PositionContext p,
- const llvm::TextEncodingConverter &FormatStrConverter);
+OptionalAmount ParsePositionAmount(
+ FormatStringHandler &H, const char *Start, const char *&Beg, const char *E,
+ PositionContext p,
+ const llvm::TextEncodingConverter &FromSystemEncodingConverter);
-OptionalAmount
-ParsePositionAmount(FormatStringHandler &H, const char *Start, const char *&Beg,
- const char *E, PositionContext p,
- const llvm::TextEncodingConverter &FormatStrConverter);
+OptionalAmount ParsePositionAmount(
+ FormatStringHandler &H, const char *Start, const char *&Beg, const char *E,
+ PositionContext p,
+ const llvm::TextEncodingConverter &FromSystemEncodingConverter);
-bool ParseFieldWidth(FormatStringHandler &H, FormatSpecifier &CS,
- const char *Start, const char *&Beg, const char *E,
- unsigned *argIndex,
- const llvm::TextEncodingConverter &FormatStrConverter);
+bool ParseFieldWidth(
+ FormatStringHandler &H, FormatSpecifier &CS, const char *Start,
+ const char *&Beg, const char *E, unsigned *argIndex,
+ const llvm::TextEncodingConverter &FromSystemEncodingConverter);
-bool ParseArgPosition(FormatStringHandler &H, FormatSpecifier &CS,
- const char *Start, const char *&Beg, const char *E,
- const llvm::TextEncodingConverter &FormatStrConverter);
+bool ParseArgPosition(
+ FormatStringHandler &H, FormatSpecifier &CS, const char *Start,
+ const char *&Beg, const char *E,
+ const llvm::TextEncodingConverter &FromSystemEncodingConverter);
-bool ParseVectorModifier(FormatStringHandler &H, FormatSpecifier &FS,
- const char *&Beg, const char *E, const LangOptions &LO,
- const llvm::TextEncodingConverter &FormatStrConverter);
+bool ParseVectorModifier(
+ FormatStringHandler &H, FormatSpecifier &FS, const char *&Beg,
+ const char *E, const LangOptions &LO,
+ const llvm::TextEncodingConverter &FromSystemEncodingConverter);
/// Returns true if a LengthModifier was parsed and installed in the
/// FormatSpecifier& argument, and false otherwise.
-bool ParseLengthModifier(FormatSpecifier &FS, const char *&Beg, const char *E,
- const LangOptions &LO,
- const llvm::TextEncodingConverter &FormatStrConverter,
- bool IsScanf = false);
+bool ParseLengthModifier(
+ FormatSpecifier &FS, const char *&Beg, const char *E, const LangOptions &LO,
+ const llvm::TextEncodingConverter &FromSystemEncodingConverter,
+ bool IsScanf = false);
/// Returns true if the invalid specifier in \p SpecifierBegin is a UTF-8
/// string; check that it won't go further than \p FmtStrEnd and write
diff --git a/clang/lib/AST/PrintfFormatString.cpp b/clang/lib/AST/PrintfFormatString.cpp
index be6247cd7bd28..a9755bb13006c 100644
--- a/clang/lib/AST/PrintfFormatString.cpp
+++ b/clang/lib/AST/PrintfFormatString.cpp
@@ -38,14 +38,14 @@ using analyze_format_string::ParseNonPositionAmount;
static bool
ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS, const char *Start,
const char *&Beg, const char *E, unsigned *argIndex,
- const llvm::TextEncodingConverter &FormatStrConverter) {
+ const llvm::TextEncodingConverter &FromSystemEncodingConverter) {
if (argIndex) {
FS.setPrecision(
- ParseNonPositionAmount(Beg, E, *argIndex, FormatStrConverter));
+ ParseNonPositionAmount(Beg, E, *argIndex, FromSystemEncodingConverter));
} else {
const OptionalAmount Amt = ParsePositionAmount(
H, Start, Beg, E, analyze_format_string::PrecisionPos,
- FormatStrConverter);
+ FromSystemEncodingConverter);
if (Amt.isInvalid())
return true;
FS.setPrecision(Amt);
@@ -56,11 +56,12 @@ ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS, const char *Start,
static bool
ParseObjCFlags(FormatStringHandler &H, PrintfSpecifier &FS, const char *FlagBeg,
const char *E, bool Warn,
- const llvm::TextEncodingConverter &FormatStrConverter) {
+ const llvm::TextEncodingConverter &FromSystemEncodingConverter) {
StringRef Flag(FlagBeg, E - FlagBeg);
// Currently there is only one flag.
- if (Flag.size() == 2 && FormatStrConverter.convert(FlagBeg[0]) == 't' &&
- FormatStrConverter.convert(FlagBeg[1]) == 't') {
+ if (Flag.size() == 2 &&
+ FromSystemEncodingConverter.convert(FlagBeg[0]) == 't' &&
+ FromSystemEncodingConverter.convert(FlagBeg[1]) == 't') {
FS.setHasObjCTechnicalTerm(FlagBeg);
return false;
}
@@ -87,8 +88,8 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
const char *Start = nullptr;
UpdateOnReturn<const char *> UpdateBeg(Beg, I);
- const llvm::TextEncodingConverter &FormatStrConverter =
- *Target.FormatStrConverter;
+ const llvm::TextEncodingConverter &FromSystemEncodingConverter =
+ *Target.FromSystemEncodingConverter;
// Look for a '%' character that indicates the start of a format specifier.
for (; I != E; ++I) {
char c = *I;
@@ -97,7 +98,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
H.HandleNullChar(I);
return true;
}
- if (FormatStrConverter.convert(c) == '%') {
+ if (FromSystemEncodingConverter.convert(c) == '%') {
Start = I++; // Record the start of the format specifier.
break;
}
@@ -115,7 +116,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
}
PrintfSpecifier FS;
- if (ParseArgPosition(H, FS, Start, I, E, FormatStrConverter))
+ if (ParseArgPosition(H, FS, Start, I, E, FromSystemEncodingConverter))
return true;
if (I == E) {
@@ -125,7 +126,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
return true;
}
- if (FormatStrConverter.convert(*I) == '{') {
+ if (FromSystemEncodingConverter.convert(*I) == '{') {
++I;
unsigned char PrivacyFlags = 0;
StringRef MatchedStr;
@@ -134,7 +135,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
const char *II;
std::string S(I, E - I);
for (unsigned long i = 0; i < S.length(); ++i)
- S[i] = FormatStrConverter.convert(S[i]);
+ S[i] = FromSystemEncodingConverter.convert(S[i]);
StringRef Str(S);
std::string Match = "^[[:space:]]*"
"(private|public|sensitive|mask\\.[^[:space:],}]*)"
@@ -147,7 +148,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
II = I;
I += Matches[0].size();
- while (FormatStrConverter.convert(*II) == ' ')
+ while (FromSystemEncodingConverter.convert(*II) == ' ')
++II;
// Set the privacy flag if the privacy annotation in the
@@ -190,7 +191,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
I += CommaOrBracePos + 1;
}
// Continue until the closing brace is found.
- } while (FormatStrConverter.convert(*(I - 1)) == ',');
+ } while (FromSystemEncodingConverter.convert(*(I - 1)) == ',');
// Set the privacy flag.
switch (PrivacyFlags) {
@@ -213,7 +214,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
// Look for flags (if any).
bool hasMore = true;
for (; I != E; ++I) {
- switch (FormatStrConverter.convert(*I)) {
+ switch (FromSystemEncodingConverter.convert(*I)) {
default:
hasMore = false;
break;
@@ -251,7 +252,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
// Look for the field width (if any).
if (ParseFieldWidth(H, FS, Start, I, E,
FS.usesPositionalArg() ? nullptr : &argIndex,
- FormatStrConverter))
+ FromSystemEncodingConverter))
return true;
if (I == E) {
@@ -262,7 +263,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
}
// Look for the precision (if any).
- if (FormatStrConverter.convert(*I) == '.') {
+ if (FromSystemEncodingConverter.convert(*I) == '.') {
++I;
if (I == E) {
if (Warn)
@@ -272,7 +273,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
if (ParsePrecision(H, FS, Start, I, E,
FS.usesPositionalArg() ? nullptr : &argIndex,
- FormatStrConverter))
+ FromSystemEncodingConverter))
return true;
if (I == E) {
@@ -283,11 +284,12 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
}
}
- if (ParseVectorModifier(H, FS, I, E, LO, FormatStrConverter))
+ if (ParseVectorModifier(H, FS, I, E, LO, FromSystemEncodingConverter))
return true;
// Look for the length modifier.
- if (ParseLengthModifier(FS, I, E, LO, FormatStrConverter) && I == E) {
+ if (ParseLengthModifier(FS, I, E, LO, FromSystemEncodingConverter) &&
+ I == E) {
// No more characters left?
if (Warn)
H.HandleIncompleteSpecifier(Start, E - Start);
@@ -301,7 +303,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
// enables better recovery, and we don't know if
// these flags are applicable until later.
const char *ObjCModifierFlagsStart = nullptr, *ObjCModifierFlagsEnd = nullptr;
- if (FormatStrConverter.convert(*I) == '[') {
+ if (FromSystemEncodingConverter.convert(*I) == '[') {
ObjCModifierFlagsStart = I;
++I;
auto flagStart = I;
@@ -313,8 +315,9 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
return true;
}
// Did we find the closing ']'?
- if (FormatStrConverter.convert(*I) == ']') {
- if (ParseObjCFlags(H, FS, flagStart, I, Warn, FormatStrConverter))
+ if (FromSystemEncodingConverter.convert(*I) == ']') {
+ if (ParseObjCFlags(H, FS, flagStart, I, Warn,
+ FromSystemEncodingConverter))
return true;
++I;
break;
@@ -334,7 +337,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
// Finally, look for the conversion specifier.
const char *conversionPosition = I++;
ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier;
- switch (FormatStrConverter.convert(*conversionPosition)) {
+ switch (FromSystemEncodingConverter.convert(*conversionPosition)) {
default:
break;
// C99: 7.19.6.1 (section 8).
@@ -497,8 +500,8 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
FS.setConversionSpecifier(CS);
}
// Assume the conversion takes one argument.
- return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, Len,
- FormatStrConverter);
+ return !H.HandleInvalidPrintfConversionSpecifier(
+ FS, Start, Len, FromSystemEncodingConverter);
}
return PrintfSpecifierResult(Start, FS);
}
diff --git a/clang/lib/AST/ScanfFormatString.cpp b/clang/lib/AST/ScanfFormatString.cpp
index 8a1404a7fa0cd..9fa40de74ecfd 100644
--- a/clang/lib/AST/ScanfFormatString.cpp
+++ b/clang/lib/AST/ScanfFormatString.cpp
@@ -81,8 +81,8 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
const char *I = Beg;
const char *Start = nullptr;
UpdateOnReturn<const char *> UpdateBeg(Beg, I);
- const llvm::TextEncodingConverter &FormatStrConverter =
- *Target.FormatStrConverter;
+ const llvm::TextEncodingConverter &FromSystemEncodingConverter =
+ *Target.FromSystemEncodingConverter;
// Look for a '%' character that indicates the start of a format specifier.
for (; I != E; ++I) {
char c = *I;
@@ -92,7 +92,7 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
return true;
}
SmallString<1> ConvertedChar;
- FormatStrConverter.convert(StringRef(&c, 1), ConvertedChar);
+ FromSystemEncodingConverter.convert(StringRef(&c, 1), ConvertedChar);
if (ConvertedChar[0] == '%') {
Start = I++; // Record the start of the format specifier.
break;
@@ -110,7 +110,7 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
}
ScanfSpecifier FS;
- if (ParseArgPosition(H, FS, Start, I, E, FormatStrConverter))
+ if (ParseArgPosition(H, FS, Start, I, E, FromSystemEncodingConverter))
return true;
if (I == E) {
@@ -120,7 +120,7 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
}
// Look for '*' flag if it is present.
- if (FormatStrConverter.convert(*I) == '*') {
+ if (FromSystemEncodingConverter.convert(*I) == '*') {
FS.setSuppressAssignment(I);
if (++I == E) {
H.HandleIncompleteSpecifier(Start, E - Start);
@@ -130,8 +130,8 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
// Look for the field width (if any). Unlike printf, this is either
// a fixed integer or isn't present.
- const OptionalAmount &Amt =
- clang::analyze_format_string::ParseAmount(I, E, FormatStrConverter);
+ const OptionalAmount &Amt = clang::analyze_format_string::ParseAmount(
+ I, E, FromSystemEncodingConverter);
if (Amt.getHowSpecified() != OptionalAmount::NotSpecified) {
assert(Amt.getHowSpecified() == OptionalAmount::Constant);
FS.setFieldWidth(Amt);
@@ -144,7 +144,7 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
}
// Look for the length modifier.
- if (ParseLengthModifier(FS, I, E, LO, FormatStrConverter,
+ if (ParseLengthModifier(FS, I, E, LO, FromSystemEncodingConverter,
/*IsScanf=*/true) &&
I == E) {
// No more characters left?
@@ -161,7 +161,7 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
// Finally, look for the conversion specifier.
const char *conversionPosition = I++;
ScanfConversionSpecifier::Kind k = ScanfConversionSpecifier::InvalidSpecifier;
- switch (FormatStrConverter.convert(*conversionPosition)) {
+ switch (FromSystemEncodingConverter.convert(*conversionPosition)) {
default:
break;
case '%':
@@ -268,8 +268,8 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
FS.setConversionSpecifier(CS);
}
// Assume the conversion takes one argument.
- return !H.HandleInvalidScanfConversionSpecifier(FS, Beg, Len,
- FormatStrConverter);
+ return !H.HandleInvalidScanfConversionSpecifier(
+ FS, Beg, Len, FromSystemEncodingConverter);
}
return ScanfSpecifierResult(Start, FS);
}
diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp
index 5d2b1d26e3a08..848a13d7343e7 100644
--- a/clang/lib/Basic/TargetInfo.cpp
+++ b/clang/lib/Basic/TargetInfo.cpp
@@ -195,7 +195,7 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : Triple(T) {
MaxBitIntWidth.reset();
- FromSystemEncodingConverter = new llvm::TextEncodingConverter(
+ FromSystemEncodingConverter = std::make_unique<llvm::TextEncodingConverter>(
std::move(*llvm::TextEncodingConverter::createNoopConverter()));
}
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 6364440aff64e..0d0574feeb05d 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -8099,7 +8099,7 @@ class CheckFormatHandler : public analyze_format_string::FormatStringHandler {
bool HandleInvalidConversionSpecifier(
unsigned argIndex, SourceLocation Loc, const char *startSpec,
unsigned specifierLen, const char *csStart, unsigned csLen,
- const llvm::TextEncodingConverter &FormatStrConverter);
+ const llvm::TextEncodingConverter &FromSystemEncodingConverter);
void HandlePositionalNonpositionalArgs(SourceLocation Loc,
const char *startSpec,
@@ -8347,7 +8347,7 @@ void UncoveredArgHandler::Diagnose(Sema &S, bool IsFunctionCall,
bool CheckFormatHandler::HandleInvalidConversionSpecifier(
unsigned argIndex, SourceLocation Loc, const char *startSpec,
unsigned specifierLen, const char *csStart, unsigned csLen,
- const llvm::TextEncodingConverter &FormatStrConverter) {
+ const llvm::TextEncodingConverter &FromSystemEncodingConverter) {
bool keepGoing = true;
if (argIndex < NumDataArgs) {
// Consider the argument coverered, even though the specifier doesn't
@@ -8365,10 +8365,12 @@ bool CheckFormatHandler::HandleInvalidConversionSpecifier(
// The csStart points to a character that has already been converted to the
// exec charset, so we have to reverse the conversion to allow diagnostic
// message to match an expected value when using -verify option,
- std::string RS(csStart, csLen);
- for (unsigned int i = 0; i < RS.size(); ++i)
- RS[i] = FormatStrConverter.convert(RS[i]);
- StringRef Specifier(RS);
+ SmallString<4> RS;
+ auto EC = FromSystemEncodingConverter.convert(StringRef(csStart, csLen), RS);
+ if (EC) {
+ keepGoing = false;
+ }
+ llvm::StringRef Specifier(RS);
// If the specifier in non-printable, it could be the first byte of a UTF-8
// sequence. In that case, print the UTF-8 code point. If not, print the byte
@@ -8523,7 +8525,7 @@ class CheckPrintfHandler : public CheckFormatHandler {
bool HandleInvalidPrintfConversionSpecifier(
const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier,
unsigned specifierLen,
- const llvm::TextEncodingConverter &FormatStrConverter) override;
+ const llvm::TextEncodingConverter &FromSystemEncodingConverter) override;
void handleInvalidMaskType(StringRef MaskType) override;
@@ -8664,13 +8666,13 @@ class DecomposePrintfHandler : public CheckPrintfHandler {
bool CheckPrintfHandler::HandleInvalidPrintfConversionSpecifier(
const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier,
unsigned specifierLen,
- const llvm::TextEncodingConverter &FormatStrConverter) {
+ const llvm::TextEncodingConverter &FromSystemEncodingConverter) {
const analyze_printf::PrintfConversionSpecifier &CS =
FS.getConversionSpecifier();
return HandleInvalidConversionSpecifier(
FS.getArgIndex(), getLocationOfByte(CS.getStart()), startSpecifier,
- specifierLen, CS.getStart(), CS.getLength(), FormatStrConverter);
+ specifierLen, CS.getStart(), CS.getLength(), FromSystemEncodingConverter);
}
void CheckPrintfHandler::handleInvalidMaskType(StringRef MaskType) {
@@ -9179,14 +9181,14 @@ bool CheckPrintfHandler::HandlePrintfSpecifier(
// in a non-ObjC literal.
if (!allowsObjCArg() && CS.isObjCArg()) {
return HandleInvalidPrintfConversionSpecifier(
- FS, startSpecifier, specifierLen, *Target.FormatStrConverter);
+ FS, startSpecifier, specifierLen, *Target.FromSystemEncodingConverter);
}
// %P can only be used with os_log.
if (FSType != FormatStringType::OSLog &&
CS.getKind() == ConversionSpecifier::PArg) {
return HandleInvalidPrintfConversionSpecifier(
- FS, startSpecifier, specifierLen, *Target.FormatStrConverter);
+ FS, startSpecifier, specifierLen, *Target.FromSystemEncodingConverter);
}
// %n is not allowed with os_log.
@@ -9206,7 +9208,7 @@ bool CheckPrintfHandler::HandlePrintfSpecifier(
CS.getKind() == ConversionSpecifier::sArg ||
CS.getKind() == ConversionSpecifier::ObjCObjArg)) {
return HandleInvalidPrintfConversionSpecifier(
- FS, startSpecifier, specifierLen, *Target.FormatStrConverter);
+ FS, startSpecifier, specifierLen, *Target.FromSystemEncodingConverter);
}
// Check for use of public/private annotation outside of os_log().
@@ -9885,7 +9887,7 @@ class CheckScanfHandler : public CheckFormatHandler {
bool HandleInvalidScanfConversionSpecifier(
const analyze_scanf::ScanfSpecifier &FS, const char *startSpecifier,
unsigned specifierLen,
- const llvm::TextEncodingConverter &FormatStrConverter) override;
+ const llvm::TextEncodingConverter &FromSystemEncodingConverter) override;
void HandleIncompleteScanList(const char *start, const char *end) override;
};
@@ -9902,14 +9904,14 @@ void CheckScanfHandler::HandleIncompleteScanList(const char *start,
bool CheckScanfHandler::HandleInvalidScanfConversionSpecifier(
const analyze_scanf::ScanfSpecifier &FS, const char *startSpecifier,
unsigned specifierLen,
- const llvm::TextEncodingConverter &FormatStrConverter) {
+ const llvm::TextEncodingConverter &FromSystemEncodingConverter) {
const analyze_scanf::ScanfConversionSpecifier &CS =
FS.getConversionSpecifier();
return HandleInvalidConversionSpecifier(
FS.getArgIndex(), getLocationOfByte(CS.getStart()), startSpecifier,
- specifierLen, CS.getStart(), CS.getLength(), FormatStrConverter);
+ specifierLen, CS.getStart(), CS.getLength(), FromSystemEncodingConverter);
}
bool CheckScanfHandler::HandleScanfSpecifier(
>From 5cfc049ab8fc2bf343873bcb22b843c6d60b2f47 Mon Sep 17 00:00:00 2001
From: Abhina Sreeskantharajan <Abhina.Sreeskantharajan at ibm.com>
Date: Fri, 17 Jul 2026 14:23:44 -0400
Subject: [PATCH 3/5] rename char conversion function to convertBasicChar
---
clang/lib/AST/FormatString.cpp | 35 ++++++++++++------------
clang/lib/AST/PrintfFormatString.cpp | 24 ++++++++--------
clang/lib/AST/ScanfFormatString.cpp | 8 ++----
llvm/include/llvm/Support/TextEncoding.h | 4 ++-
4 files changed, 36 insertions(+), 35 deletions(-)
diff --git a/clang/lib/AST/FormatString.cpp b/clang/lib/AST/FormatString.cpp
index e804aafa8a9e1..845fb09ade998 100644
--- a/clang/lib/AST/FormatString.cpp
+++ b/clang/lib/AST/FormatString.cpp
@@ -44,7 +44,7 @@ OptionalAmount clang::analyze_format_string::ParseAmount(
bool hasDigits = false;
for (; I != E; ++I) {
- char c = FromSystemEncodingConverter.convert(*I);
+ char c = FromSystemEncodingConverter.convertBasicChar(*I);
if (c >= '0' && c <= '9') {
hasDigits = true;
accumulator = (accumulator * 10) + (c - '0');
@@ -79,7 +79,7 @@ static bool ParseWidthModifier(const char *&I, const char *E,
OptionalAmount clang::analyze_format_string::ParseNonPositionAmount(
const char *&Beg, const char *E, unsigned &argIndex,
const llvm::TextEncodingConverter &FromSystemEncodingConverter) {
- if (FromSystemEncodingConverter.convert(*Beg) == '*') {
+ if (FromSystemEncodingConverter.convertBasicChar(*Beg) == '*') {
++Beg;
return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg, 0, false);
}
@@ -91,7 +91,7 @@ OptionalAmount clang::analyze_format_string::ParsePositionAmount(
FormatStringHandler &H, const char *Start, const char *&Beg, const char *E,
PositionContext p,
const llvm::TextEncodingConverter &FromSystemEncodingConverter) {
- if (FromSystemEncodingConverter.convert(*Beg) == '*') {
+ if (FromSystemEncodingConverter.convertBasicChar(*Beg) == '*') {
const char *I = Beg + 1;
const OptionalAmount &Amt = ParseAmount(I, E, FromSystemEncodingConverter);
@@ -108,7 +108,7 @@ OptionalAmount clang::analyze_format_string::ParsePositionAmount(
assert(Amt.getHowSpecified() == OptionalAmount::Constant);
- if (FromSystemEncodingConverter.convert(*I) == '$') {
+ if (FromSystemEncodingConverter.convertBasicChar(*I) == '$') {
// Handle positional arguments
// Special case: '*0$', since this is an easy mistake.
@@ -166,7 +166,7 @@ bool clang::analyze_format_string::ParseArgPosition(
}
if (Amt.getHowSpecified() == OptionalAmount::Constant &&
- FromSystemEncodingConverter.convert(*(I++)) == '$') {
+ FromSystemEncodingConverter.convertBasicChar(*(I++)) == '$') {
// Warn that positional arguments are non-standard.
H.HandlePosition(Start, I - Start);
@@ -195,7 +195,7 @@ bool clang::analyze_format_string::ParseVectorModifier(
return false;
const char *Start = I;
- if (FromSystemEncodingConverter.convert(*I) == 'v') {
+ if (FromSystemEncodingConverter.convertBasicChar(*I) == 'v') {
++I;
if (I == E) {
@@ -221,15 +221,16 @@ bool clang::analyze_format_string::ParseLengthModifier(
bool IsScanf) {
LengthModifier::Kind lmKind = LengthModifier::None;
const char *lmPosition = I;
- switch (FromSystemEncodingConverter.convert(*I)) {
+ switch (FromSystemEncodingConverter.convertBasicChar(*I)) {
default:
return false;
case 'h':
++I;
- if (I != E && FromSystemEncodingConverter.convert(*I) == 'h') {
+ if (I != E && FromSystemEncodingConverter.convertBasicChar(*I) == 'h') {
++I;
lmKind = LengthModifier::AsChar;
- } else if (I != E && FromSystemEncodingConverter.convert(*I) == 'l' &&
+ } else if (I != E &&
+ FromSystemEncodingConverter.convertBasicChar(*I) == 'l' &&
LO.OpenCL) {
++I;
lmKind = LengthModifier::AsShortLong;
@@ -239,7 +240,7 @@ bool clang::analyze_format_string::ParseLengthModifier(
break;
case 'l':
++I;
- if (I != E && FromSystemEncodingConverter.convert(*I) == 'l') {
+ if (I != E && FromSystemEncodingConverter.convertBasicChar(*I) == 'l') {
++I;
lmKind = LengthModifier::AsLongLong;
} else {
@@ -272,9 +273,9 @@ bool clang::analyze_format_string::ParseLengthModifier(
// be parsed as the GNU extension 'a' length modifier. If not, this
// will be parsed as a conversion specifier.
++I;
- if (I != E && (FromSystemEncodingConverter.convert(*I) == 's' ||
- FromSystemEncodingConverter.convert(*I) == 'S' ||
- FromSystemEncodingConverter.convert(*I) == '[')) {
+ if (I != E && (FromSystemEncodingConverter.convertBasicChar(*I) == 's' ||
+ FromSystemEncodingConverter.convertBasicChar(*I) == 'S' ||
+ FromSystemEncodingConverter.convertBasicChar(*I) == '[')) {
lmKind = LengthModifier::AsAllocate;
break;
}
@@ -292,8 +293,8 @@ bool clang::analyze_format_string::ParseLengthModifier(
// scanf: AsInt64
case 'I':
if (I + 1 != E && I + 2 != E) {
- if (FromSystemEncodingConverter.convert(I[1]) == '6' &&
- FromSystemEncodingConverter.convert(I[2]) == '4') {
+ if (FromSystemEncodingConverter.convertBasicChar(I[1]) == '6' &&
+ FromSystemEncodingConverter.convertBasicChar(I[2]) == '4') {
I += 3;
lmKind = LengthModifier::AsInt64;
break;
@@ -301,8 +302,8 @@ bool clang::analyze_format_string::ParseLengthModifier(
if (IsScanf)
return false;
- if (FromSystemEncodingConverter.convert(I[1]) == '3' &&
- FromSystemEncodingConverter.convert(I[2]) == '2') {
+ if (FromSystemEncodingConverter.convertBasicChar(I[1]) == '3' &&
+ FromSystemEncodingConverter.convertBasicChar(I[2]) == '2') {
I += 3;
lmKind = LengthModifier::AsInt32;
break;
diff --git a/clang/lib/AST/PrintfFormatString.cpp b/clang/lib/AST/PrintfFormatString.cpp
index a9755bb13006c..1d08abe17efbc 100644
--- a/clang/lib/AST/PrintfFormatString.cpp
+++ b/clang/lib/AST/PrintfFormatString.cpp
@@ -60,8 +60,8 @@ ParseObjCFlags(FormatStringHandler &H, PrintfSpecifier &FS, const char *FlagBeg,
StringRef Flag(FlagBeg, E - FlagBeg);
// Currently there is only one flag.
if (Flag.size() == 2 &&
- FromSystemEncodingConverter.convert(FlagBeg[0]) == 't' &&
- FromSystemEncodingConverter.convert(FlagBeg[1]) == 't') {
+ FromSystemEncodingConverter.convertBasicChar(FlagBeg[0]) == 't' &&
+ FromSystemEncodingConverter.convertBasicChar(FlagBeg[1]) == 't') {
FS.setHasObjCTechnicalTerm(FlagBeg);
return false;
}
@@ -98,7 +98,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
H.HandleNullChar(I);
return true;
}
- if (FromSystemEncodingConverter.convert(c) == '%') {
+ if (FromSystemEncodingConverter.convertBasicChar(c) == '%') {
Start = I++; // Record the start of the format specifier.
break;
}
@@ -126,7 +126,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
return true;
}
- if (FromSystemEncodingConverter.convert(*I) == '{') {
+ if (FromSystemEncodingConverter.convertBasicChar(*I) == '{') {
++I;
unsigned char PrivacyFlags = 0;
StringRef MatchedStr;
@@ -135,7 +135,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
const char *II;
std::string S(I, E - I);
for (unsigned long i = 0; i < S.length(); ++i)
- S[i] = FromSystemEncodingConverter.convert(S[i]);
+ S[i] = FromSystemEncodingConverter.convertBasicChar(S[i]);
StringRef Str(S);
std::string Match = "^[[:space:]]*"
"(private|public|sensitive|mask\\.[^[:space:],}]*)"
@@ -148,7 +148,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
II = I;
I += Matches[0].size();
- while (FromSystemEncodingConverter.convert(*II) == ' ')
+ while (FromSystemEncodingConverter.convertBasicChar(*II) == ' ')
++II;
// Set the privacy flag if the privacy annotation in the
@@ -191,7 +191,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
I += CommaOrBracePos + 1;
}
// Continue until the closing brace is found.
- } while (FromSystemEncodingConverter.convert(*(I - 1)) == ',');
+ } while (FromSystemEncodingConverter.convertBasicChar(*(I - 1)) == ',');
// Set the privacy flag.
switch (PrivacyFlags) {
@@ -214,7 +214,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
// Look for flags (if any).
bool hasMore = true;
for (; I != E; ++I) {
- switch (FromSystemEncodingConverter.convert(*I)) {
+ switch (FromSystemEncodingConverter.convertBasicChar(*I)) {
default:
hasMore = false;
break;
@@ -263,7 +263,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
}
// Look for the precision (if any).
- if (FromSystemEncodingConverter.convert(*I) == '.') {
+ if (FromSystemEncodingConverter.convertBasicChar(*I) == '.') {
++I;
if (I == E) {
if (Warn)
@@ -303,7 +303,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
// enables better recovery, and we don't know if
// these flags are applicable until later.
const char *ObjCModifierFlagsStart = nullptr, *ObjCModifierFlagsEnd = nullptr;
- if (FromSystemEncodingConverter.convert(*I) == '[') {
+ if (FromSystemEncodingConverter.convertBasicChar(*I) == '[') {
ObjCModifierFlagsStart = I;
++I;
auto flagStart = I;
@@ -315,7 +315,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
return true;
}
// Did we find the closing ']'?
- if (FromSystemEncodingConverter.convert(*I) == ']') {
+ if (FromSystemEncodingConverter.convertBasicChar(*I) == ']') {
if (ParseObjCFlags(H, FS, flagStart, I, Warn,
FromSystemEncodingConverter))
return true;
@@ -337,7 +337,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
// Finally, look for the conversion specifier.
const char *conversionPosition = I++;
ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier;
- switch (FromSystemEncodingConverter.convert(*conversionPosition)) {
+ switch (FromSystemEncodingConverter.convertBasicChar(*conversionPosition)) {
default:
break;
// C99: 7.19.6.1 (section 8).
diff --git a/clang/lib/AST/ScanfFormatString.cpp b/clang/lib/AST/ScanfFormatString.cpp
index 9fa40de74ecfd..dc6078264b0b5 100644
--- a/clang/lib/AST/ScanfFormatString.cpp
+++ b/clang/lib/AST/ScanfFormatString.cpp
@@ -91,9 +91,7 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
H.HandleNullChar(I);
return true;
}
- SmallString<1> ConvertedChar;
- FromSystemEncodingConverter.convert(StringRef(&c, 1), ConvertedChar);
- if (ConvertedChar[0] == '%') {
+ if (FromSystemEncodingConverter.convertBasicChar(c) == '%') {
Start = I++; // Record the start of the format specifier.
break;
}
@@ -120,7 +118,7 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
}
// Look for '*' flag if it is present.
- if (FromSystemEncodingConverter.convert(*I) == '*') {
+ if (FromSystemEncodingConverter.convertBasicChar(*I) == '*') {
FS.setSuppressAssignment(I);
if (++I == E) {
H.HandleIncompleteSpecifier(Start, E - Start);
@@ -161,7 +159,7 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
// Finally, look for the conversion specifier.
const char *conversionPosition = I++;
ScanfConversionSpecifier::Kind k = ScanfConversionSpecifier::InvalidSpecifier;
- switch (FromSystemEncodingConverter.convert(*conversionPosition)) {
+ switch (FromSystemEncodingConverter.convertBasicChar(*conversionPosition)) {
default:
break;
case '%':
diff --git a/llvm/include/llvm/Support/TextEncoding.h b/llvm/include/llvm/Support/TextEncoding.h
index 734972b892ecc..80709e96be04b 100644
--- a/llvm/include/llvm/Support/TextEncoding.h
+++ b/llvm/include/llvm/Support/TextEncoding.h
@@ -137,7 +137,9 @@ class TextEncodingConverter {
return EC;
}
- char convert(char SingleChar) const {
+ // This method is used in format string handling and is only intended
+ // to support basic charsets, not multibyte characters.
+ char convertBasicChar(char SingleChar) const {
SmallString<1> Result;
auto EC = Converter->convert(StringRef(&SingleChar, 1), Result);
if (!EC)
>From 9651b75b6e371f2b40c37da501439f8dd575f0e5 Mon Sep 17 00:00:00 2001
From: Abhina Sreeskantharajan <Abhina.Sreeskantharajan at ibm.com>
Date: Wed, 22 Jul 2026 14:49:20 -0400
Subject: [PATCH 4/5] change char literals to u8'' to preserve behaviour in the
case the compiler is compiled with a different fexec-charset
---
clang/lib/AST/FormatString.cpp | 55 ++++++++---------
clang/lib/AST/PrintfFormatString.cpp | 88 ++++++++++++++--------------
clang/lib/AST/ScanfFormatString.cpp | 56 +++++++++---------
3 files changed, 100 insertions(+), 99 deletions(-)
diff --git a/clang/lib/AST/FormatString.cpp b/clang/lib/AST/FormatString.cpp
index 845fb09ade998..b67de85f75467 100644
--- a/clang/lib/AST/FormatString.cpp
+++ b/clang/lib/AST/FormatString.cpp
@@ -45,9 +45,9 @@ OptionalAmount clang::analyze_format_string::ParseAmount(
for (; I != E; ++I) {
char c = FromSystemEncodingConverter.convertBasicChar(*I);
- if (c >= '0' && c <= '9') {
+ if (c >= u8'0' && c <= u8'9') {
hasDigits = true;
- accumulator = (accumulator * 10) + (c - '0');
+ accumulator = (accumulator * 10) + (c - u8'0');
continue;
}
@@ -79,7 +79,7 @@ static bool ParseWidthModifier(const char *&I, const char *E,
OptionalAmount clang::analyze_format_string::ParseNonPositionAmount(
const char *&Beg, const char *E, unsigned &argIndex,
const llvm::TextEncodingConverter &FromSystemEncodingConverter) {
- if (FromSystemEncodingConverter.convertBasicChar(*Beg) == '*') {
+ if (FromSystemEncodingConverter.convertBasicChar(*Beg) == u8'*') {
++Beg;
return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg, 0, false);
}
@@ -91,7 +91,7 @@ OptionalAmount clang::analyze_format_string::ParsePositionAmount(
FormatStringHandler &H, const char *Start, const char *&Beg, const char *E,
PositionContext p,
const llvm::TextEncodingConverter &FromSystemEncodingConverter) {
- if (FromSystemEncodingConverter.convertBasicChar(*Beg) == '*') {
+ if (FromSystemEncodingConverter.convertBasicChar(*Beg) == u8'*') {
const char *I = Beg + 1;
const OptionalAmount &Amt = ParseAmount(I, E, FromSystemEncodingConverter);
@@ -108,7 +108,7 @@ OptionalAmount clang::analyze_format_string::ParsePositionAmount(
assert(Amt.getHowSpecified() == OptionalAmount::Constant);
- if (FromSystemEncodingConverter.convertBasicChar(*I) == '$') {
+ if (FromSystemEncodingConverter.convertBasicChar(*I) == u8'$') {
// Handle positional arguments
// Special case: '*0$', since this is an easy mistake.
@@ -166,7 +166,7 @@ bool clang::analyze_format_string::ParseArgPosition(
}
if (Amt.getHowSpecified() == OptionalAmount::Constant &&
- FromSystemEncodingConverter.convertBasicChar(*(I++)) == '$') {
+ FromSystemEncodingConverter.convertBasicChar(*(I++)) == u8'$') {
// Warn that positional arguments are non-standard.
H.HandlePosition(Start, I - Start);
@@ -195,7 +195,7 @@ bool clang::analyze_format_string::ParseVectorModifier(
return false;
const char *Start = I;
- if (FromSystemEncodingConverter.convertBasicChar(*I) == 'v') {
+ if (FromSystemEncodingConverter.convertBasicChar(*I) == u8'v') {
++I;
if (I == E) {
@@ -224,13 +224,13 @@ bool clang::analyze_format_string::ParseLengthModifier(
switch (FromSystemEncodingConverter.convertBasicChar(*I)) {
default:
return false;
- case 'h':
+ case u8'h':
++I;
- if (I != E && FromSystemEncodingConverter.convertBasicChar(*I) == 'h') {
+ if (I != E && FromSystemEncodingConverter.convertBasicChar(*I) == u8'h') {
++I;
lmKind = LengthModifier::AsChar;
} else if (I != E &&
- FromSystemEncodingConverter.convertBasicChar(*I) == 'l' &&
+ FromSystemEncodingConverter.convertBasicChar(*I) == u8'l' &&
LO.OpenCL) {
++I;
lmKind = LengthModifier::AsShortLong;
@@ -238,51 +238,52 @@ bool clang::analyze_format_string::ParseLengthModifier(
lmKind = LengthModifier::AsShort;
}
break;
- case 'l':
+ case u8'l':
++I;
- if (I != E && FromSystemEncodingConverter.convertBasicChar(*I) == 'l') {
+ if (I != E && FromSystemEncodingConverter.convertBasicChar(*I) == u8'l') {
++I;
lmKind = LengthModifier::AsLongLong;
} else {
lmKind = LengthModifier::AsLong;
}
break;
- case 'j':
+ case u8'j':
lmKind = LengthModifier::AsIntMax;
++I;
break;
- case 'z':
+ case u8'z':
lmKind = LengthModifier::AsSizeT;
++I;
break;
- case 't':
+ case u8't':
lmKind = LengthModifier::AsPtrDiff;
++I;
break;
- case 'L':
+ case u8'L':
lmKind = LengthModifier::AsLongDouble;
++I;
break;
- case 'q':
+ case u8'q':
lmKind = LengthModifier::AsQuad;
++I;
break;
- case 'a':
+ case u8'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 && (FromSystemEncodingConverter.convertBasicChar(*I) == 's' ||
- FromSystemEncodingConverter.convertBasicChar(*I) == 'S' ||
- FromSystemEncodingConverter.convertBasicChar(*I) == '[')) {
+ if (I != E &&
+ (FromSystemEncodingConverter.convertBasicChar(*I) == u8's' ||
+ FromSystemEncodingConverter.convertBasicChar(*I) == u8'S' ||
+ FromSystemEncodingConverter.convertBasicChar(*I) == u8'[')) {
lmKind = LengthModifier::AsAllocate;
break;
}
--I;
}
return false;
- case 'm':
+ case u8'm':
if (IsScanf) {
lmKind = LengthModifier::AsMAllocate;
++I;
@@ -291,10 +292,10 @@ bool clang::analyze_format_string::ParseLengthModifier(
return false;
// printf: AsInt64, AsInt32, AsInt3264
// scanf: AsInt64
- case 'I':
+ case u8'I':
if (I + 1 != E && I + 2 != E) {
- if (FromSystemEncodingConverter.convertBasicChar(I[1]) == '6' &&
- FromSystemEncodingConverter.convertBasicChar(I[2]) == '4') {
+ if (FromSystemEncodingConverter.convertBasicChar(I[1]) == u8'6' &&
+ FromSystemEncodingConverter.convertBasicChar(I[2]) == u8'4') {
I += 3;
lmKind = LengthModifier::AsInt64;
break;
@@ -302,8 +303,8 @@ bool clang::analyze_format_string::ParseLengthModifier(
if (IsScanf)
return false;
- if (FromSystemEncodingConverter.convertBasicChar(I[1]) == '3' &&
- FromSystemEncodingConverter.convertBasicChar(I[2]) == '2') {
+ if (FromSystemEncodingConverter.convertBasicChar(I[1]) == u8'3' &&
+ FromSystemEncodingConverter.convertBasicChar(I[2]) == u8'2') {
I += 3;
lmKind = LengthModifier::AsInt32;
break;
diff --git a/clang/lib/AST/PrintfFormatString.cpp b/clang/lib/AST/PrintfFormatString.cpp
index 1d08abe17efbc..92fdf6031ac39 100644
--- a/clang/lib/AST/PrintfFormatString.cpp
+++ b/clang/lib/AST/PrintfFormatString.cpp
@@ -60,8 +60,8 @@ ParseObjCFlags(FormatStringHandler &H, PrintfSpecifier &FS, const char *FlagBeg,
StringRef Flag(FlagBeg, E - FlagBeg);
// Currently there is only one flag.
if (Flag.size() == 2 &&
- FromSystemEncodingConverter.convertBasicChar(FlagBeg[0]) == 't' &&
- FromSystemEncodingConverter.convertBasicChar(FlagBeg[1]) == 't') {
+ FromSystemEncodingConverter.convertBasicChar(FlagBeg[0]) == u8't' &&
+ FromSystemEncodingConverter.convertBasicChar(FlagBeg[1]) == u8't') {
FS.setHasObjCTechnicalTerm(FlagBeg);
return false;
}
@@ -98,7 +98,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
H.HandleNullChar(I);
return true;
}
- if (FromSystemEncodingConverter.convertBasicChar(c) == '%') {
+ if (FromSystemEncodingConverter.convertBasicChar(c) == u8'%') {
Start = I++; // Record the start of the format specifier.
break;
}
@@ -126,7 +126,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
return true;
}
- if (FromSystemEncodingConverter.convertBasicChar(*I) == '{') {
+ if (FromSystemEncodingConverter.convertBasicChar(*I) == u8'{') {
++I;
unsigned char PrivacyFlags = 0;
StringRef MatchedStr;
@@ -148,7 +148,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
II = I;
I += Matches[0].size();
- while (FromSystemEncodingConverter.convertBasicChar(*II) == ' ')
+ while (FromSystemEncodingConverter.convertBasicChar(*II) == u8' ')
++II;
// Set the privacy flag if the privacy annotation in the
@@ -191,7 +191,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
I += CommaOrBracePos + 1;
}
// Continue until the closing brace is found.
- } while (FromSystemEncodingConverter.convertBasicChar(*(I - 1)) == ',');
+ } while (FromSystemEncodingConverter.convertBasicChar(*(I - 1)) == u8',');
// Set the privacy flag.
switch (PrivacyFlags) {
@@ -263,7 +263,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
}
// Look for the precision (if any).
- if (FromSystemEncodingConverter.convertBasicChar(*I) == '.') {
+ if (FromSystemEncodingConverter.convertBasicChar(*I) == u8'.') {
++I;
if (I == E) {
if (Warn)
@@ -303,7 +303,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
// enables better recovery, and we don't know if
// these flags are applicable until later.
const char *ObjCModifierFlagsStart = nullptr, *ObjCModifierFlagsEnd = nullptr;
- if (FromSystemEncodingConverter.convertBasicChar(*I) == '[') {
+ if (FromSystemEncodingConverter.convertBasicChar(*I) == u8'[') {
ObjCModifierFlagsStart = I;
++I;
auto flagStart = I;
@@ -315,7 +315,7 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
return true;
}
// Did we find the closing ']'?
- if (FromSystemEncodingConverter.convertBasicChar(*I) == ']') {
+ if (FromSystemEncodingConverter.convertBasicChar(*I) == u8']') {
if (ParseObjCFlags(H, FS, flagStart, I, Warn,
FromSystemEncodingConverter))
return true;
@@ -341,135 +341,135 @@ ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E,
default:
break;
// C99: 7.19.6.1 (section 8).
- case '%':
+ case u8'%':
k = ConversionSpecifier::PercentArg;
break;
- case 'A':
+ case u8'A':
k = ConversionSpecifier::AArg;
break;
- case 'E':
+ case u8'E':
k = ConversionSpecifier::EArg;
break;
- case 'F':
+ case u8'F':
k = ConversionSpecifier::FArg;
break;
- case 'G':
+ case u8'G':
k = ConversionSpecifier::GArg;
break;
- case 'X':
+ case u8'X':
k = ConversionSpecifier::XArg;
break;
- case 'a':
+ case u8'a':
k = ConversionSpecifier::aArg;
break;
- case 'c':
+ case u8'c':
k = ConversionSpecifier::cArg;
break;
- case 'd':
+ case u8'd':
k = ConversionSpecifier::dArg;
break;
- case 'e':
+ case u8'e':
k = ConversionSpecifier::eArg;
break;
- case 'f':
+ case u8'f':
k = ConversionSpecifier::fArg;
break;
- case 'g':
+ case u8'g':
k = ConversionSpecifier::gArg;
break;
- case 'i':
+ case u8'i':
k = ConversionSpecifier::iArg;
break;
- case 'n':
+ case u8'n':
// Not handled, but reserved in OpenCL.
if (!LO.OpenCL)
k = ConversionSpecifier::nArg;
break;
- case 'o':
+ case u8'o':
k = ConversionSpecifier::oArg;
break;
- case 'p':
+ case u8'p':
k = ConversionSpecifier::pArg;
break;
- case 's':
+ case u8's':
k = ConversionSpecifier::sArg;
break;
- case 'u':
+ case u8'u':
k = ConversionSpecifier::uArg;
break;
- case 'x':
+ case u8'x':
k = ConversionSpecifier::xArg;
break;
// C23.
- case 'b':
+ case u8'b':
if (isFreeBSDKPrintf)
k = ConversionSpecifier::FreeBSDbArg; // int followed by char *
else
k = ConversionSpecifier::bArg;
break;
- case 'B':
+ case u8'B':
k = ConversionSpecifier::BArg;
break;
// POSIX specific.
- case 'C':
+ case u8'C':
k = ConversionSpecifier::CArg;
break;
- case 'S':
+ case u8'S':
k = ConversionSpecifier::SArg;
break;
// Apple extension for os_log
- case 'P':
+ case u8'P':
k = ConversionSpecifier::PArg;
break;
// Objective-C.
- case '@':
+ case u8'@':
k = ConversionSpecifier::ObjCObjArg;
break;
// Glibc specific.
- case 'm':
+ case u8'm':
k = ConversionSpecifier::PrintErrno;
break;
- case 'r':
+ case u8'r':
if (isFreeBSDKPrintf)
k = ConversionSpecifier::FreeBSDrArg; // int
else if (LO.FixedPoint)
k = ConversionSpecifier::rArg;
break;
- case 'y':
+ case u8'y':
if (isFreeBSDKPrintf)
k = ConversionSpecifier::FreeBSDyArg; // int
break;
// Apple-specific.
- case 'D':
+ case u8'D':
if (isFreeBSDKPrintf)
k = ConversionSpecifier::FreeBSDDArg; // void * followed by char *
else if (Target.getTriple().isOSDarwin())
k = ConversionSpecifier::DArg;
break;
- case 'O':
+ case u8'O':
if (Target.getTriple().isOSDarwin())
k = ConversionSpecifier::OArg;
break;
- case 'U':
+ case u8'U':
if (Target.getTriple().isOSDarwin())
k = ConversionSpecifier::UArg;
break;
// MS specific.
- case 'Z':
+ case u8'Z':
if (Target.getTriple().isOSMSVCRT())
k = ConversionSpecifier::ZArg;
break;
// ISO/IEC TR 18037 (fixed-point) specific.
// NOTE: 'r' is handled up above since FreeBSD also supports %r.
- case 'k':
+ case u8'k':
if (LO.FixedPoint)
k = ConversionSpecifier::kArg;
break;
- case 'K':
+ case u8'K':
if (LO.FixedPoint)
k = ConversionSpecifier::KArg;
break;
- case 'R':
+ case u8'R':
if (LO.FixedPoint)
k = ConversionSpecifier::RArg;
break;
diff --git a/clang/lib/AST/ScanfFormatString.cpp b/clang/lib/AST/ScanfFormatString.cpp
index dc6078264b0b5..5a4f0d051919f 100644
--- a/clang/lib/AST/ScanfFormatString.cpp
+++ b/clang/lib/AST/ScanfFormatString.cpp
@@ -91,7 +91,7 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
H.HandleNullChar(I);
return true;
}
- if (FromSystemEncodingConverter.convertBasicChar(c) == '%') {
+ if (FromSystemEncodingConverter.convertBasicChar(c) == u8'%') {
Start = I++; // Record the start of the format specifier.
break;
}
@@ -118,7 +118,7 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
}
// Look for '*' flag if it is present.
- if (FromSystemEncodingConverter.convertBasicChar(*I) == '*') {
+ if (FromSystemEncodingConverter.convertBasicChar(*I) == u8'*') {
FS.setSuppressAssignment(I);
if (++I == E) {
H.HandleIncompleteSpecifier(Start, E - Start);
@@ -162,86 +162,86 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
switch (FromSystemEncodingConverter.convertBasicChar(*conversionPosition)) {
default:
break;
- case '%':
+ case u8'%':
k = ConversionSpecifier::PercentArg;
break;
- case 'b':
+ case u8'b':
k = ConversionSpecifier::bArg;
break;
- case 'A':
+ case u8'A':
k = ConversionSpecifier::AArg;
break;
- case 'E':
+ case u8'E':
k = ConversionSpecifier::EArg;
break;
- case 'F':
+ case u8'F':
k = ConversionSpecifier::FArg;
break;
- case 'G':
+ case u8'G':
k = ConversionSpecifier::GArg;
break;
- case 'X':
+ case u8'X':
k = ConversionSpecifier::XArg;
break;
- case 'a':
+ case u8'a':
k = ConversionSpecifier::aArg;
break;
- case 'd':
+ case u8'd':
k = ConversionSpecifier::dArg;
break;
- case 'e':
+ case u8'e':
k = ConversionSpecifier::eArg;
break;
- case 'f':
+ case u8'f':
k = ConversionSpecifier::fArg;
break;
- case 'g':
+ case u8'g':
k = ConversionSpecifier::gArg;
break;
- case 'i':
+ case u8'i':
k = ConversionSpecifier::iArg;
break;
- case 'n':
+ case u8'n':
k = ConversionSpecifier::nArg;
break;
- case 'c':
+ case u8'c':
k = ConversionSpecifier::cArg;
break;
- case 'C':
+ case u8'C':
k = ConversionSpecifier::CArg;
break;
- case 'S':
+ case u8'S':
k = ConversionSpecifier::SArg;
break;
- case '[':
+ case u8'[':
k = ConversionSpecifier::ScanListArg;
break;
- case 'u':
+ case u8'u':
k = ConversionSpecifier::uArg;
break;
- case 'x':
+ case u8'x':
k = ConversionSpecifier::xArg;
break;
- case 'o':
+ case u8'o':
k = ConversionSpecifier::oArg;
break;
- case 's':
+ case u8's':
k = ConversionSpecifier::sArg;
break;
- case 'p':
+ case u8'p':
k = ConversionSpecifier::pArg;
break;
// Apple extensions
// Apple-specific
- case 'D':
+ case u8'D':
if (Target.getTriple().isOSDarwin())
k = ConversionSpecifier::DArg;
break;
- case 'O':
+ case u8'O':
if (Target.getTriple().isOSDarwin())
k = ConversionSpecifier::OArg;
break;
- case 'U':
+ case u8'U':
if (Target.getTriple().isOSDarwin())
k = ConversionSpecifier::UArg;
break;
>From 9067ecf3570d7814677ee9ceb7f01571e838fffd Mon Sep 17 00:00:00 2001
From: Abhina Sreeskantharajan <Abhina.Sreeskantharajan at ibm.com>
Date: Tue, 11 Aug 2026 08:58:50 -0400
Subject: [PATCH 5/5] Add isNoop to avoid conversion code in
ActOnGCCAsmStmtString
---
clang/lib/Sema/SemaStmtAsm.cpp | 3 ++-
llvm/include/llvm/Support/TextEncoding.h | 7 +++++++
llvm/lib/Support/TextEncoding.cpp | 2 ++
3 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp
index e0c3f7c7fd84f..eafb2076c8e01 100644
--- a/clang/lib/Sema/SemaStmtAsm.cpp
+++ b/clang/lib/Sema/SemaStmtAsm.cpp
@@ -245,7 +245,7 @@ ExprResult Sema::ActOnGCCAsmStmtString(Expr *Expr, bool ForAsmLabel) {
Diag(Expr->getBeginLoc(), diag::err_asm_operand_empty_string)
<< SL->getSourceRange();
}
- if (Context.getTargetInfo().FromSystemEncodingConverter != nullptr) {
+ if (!Context.getTargetInfo().FromSystemEncodingConverter->isNoop()) {
SmallString<16> ConvertedAsm;
Context.getTargetInfo().FromSystemEncodingConverter->convert(
SL->getString(), ConvertedAsm);
@@ -257,6 +257,7 @@ ExprResult Sema::ActOnGCCAsmStmtString(Expr *Expr, bool ForAsmLabel) {
}
return SL;
}
+
if (DiagnoseUnexpandedParameterPack(Expr))
return ExprError();
if (Expr->getDependence() != ExprDependence::None)
diff --git a/llvm/include/llvm/Support/TextEncoding.h b/llvm/include/llvm/Support/TextEncoding.h
index 80709e96be04b..7ea1a6e1ff28b 100644
--- a/llvm/include/llvm/Support/TextEncoding.h
+++ b/llvm/include/llvm/Support/TextEncoding.h
@@ -59,6 +59,10 @@ class TextEncodingConverterImplBase {
public:
virtual ~TextEncodingConverterImplBase() = default;
+ /// Returns true if this converter performs no conversion (UTF-8 to
+ /// UTF-8).
+ virtual bool isNoop() const { return false; }
+
/// Converts a string and resets the converter to the initial state.
std::error_code convert(StringRef Source, SmallVectorImpl<char> &Result) {
auto EC = convertString(Source, Result);
@@ -137,6 +141,9 @@ class TextEncodingConverter {
return EC;
}
+ /// Returns true if this converter performs no conversion.
+ bool isNoop() const { return Converter->isNoop(); }
+
// This method is used in format string handling and is only intended
// to support basic charsets, not multibyte characters.
char convertBasicChar(char SingleChar) const {
diff --git a/llvm/lib/Support/TextEncoding.cpp b/llvm/lib/Support/TextEncoding.cpp
index 9672cba006a2c..bf77a4369179c 100644
--- a/llvm/lib/Support/TextEncoding.cpp
+++ b/llvm/lib/Support/TextEncoding.cpp
@@ -371,6 +371,8 @@ class TextEncodingConverterNoop final
}
void reset() override {}
+
+ bool isNoop() const override { return true; }
};
ErrorOr<TextEncodingConverter> TextEncodingConverter::createNoopConverter() {
More information about the llvm-branch-commits
mailing list