Introduce -fformat-extensions. A local FreeBSD extension used
for additional printf modifiers in kernel. Approved by: ed (mentor)
This commit is contained in:
parent
54e57c8145
commit
a08050302b
@ -57,6 +57,7 @@ class ConversionSpecifier {
|
||||
InvalidSpecifier = 0,
|
||||
// C99 conversion specifiers.
|
||||
dArg, // 'd'
|
||||
DArg, // 'D' FreeBSD specific specifiers
|
||||
iArg, // 'i',
|
||||
oArg, // 'o',
|
||||
uArg, // 'u',
|
||||
@ -82,6 +83,7 @@ class ConversionSpecifier {
|
||||
ObjCObjArg, // '@'
|
||||
// GlibC specific specifiers.
|
||||
PrintErrno, // 'm'
|
||||
bArg, // FreeBSD specific specifiers
|
||||
// Specifier ranges.
|
||||
IntArgBeg = dArg,
|
||||
IntArgEnd = iArg,
|
||||
@ -306,7 +308,7 @@ class FormatStringHandler {
|
||||
};
|
||||
|
||||
bool ParseFormatString(FormatStringHandler &H,
|
||||
const char *beg, const char *end);
|
||||
const char *beg, const char *end, bool FormatExtensions);
|
||||
|
||||
} // end printf namespace
|
||||
} // end clang namespace
|
||||
|
@ -54,6 +54,7 @@ class LangOptions {
|
||||
|
||||
unsigned NeXTRuntime : 1; // Use NeXT runtime.
|
||||
unsigned Freestanding : 1; // Freestanding implementation
|
||||
unsigned FormatExtensions : 1; // FreeBSD format extensions (-fformat-extensions)
|
||||
unsigned NoBuiltin : 1; // Do not use builtin functions (-fno-builtin)
|
||||
|
||||
unsigned ThreadsafeStatics : 1; // Whether static initializers are protected
|
||||
|
@ -377,6 +377,8 @@ def fsjlj_exceptions : Flag<"-fsjlj-exceptions">,
|
||||
HelpText<"Use SjLj style exceptions">;
|
||||
def ffreestanding : Flag<"-ffreestanding">,
|
||||
HelpText<"Assert that the compilation takes place in a freestanding environment">;
|
||||
def fformat_extensions : Flag<"-fformat-extensions">,
|
||||
HelpText<"FreeBSD printf format extensions">;
|
||||
def fgnu_runtime : Flag<"-fgnu-runtime">,
|
||||
HelpText<"Generate output compatible with the standard GNU Objective-C runtime">;
|
||||
def std_EQ : Joined<"-std=">,
|
||||
|
@ -268,6 +268,7 @@ def fexceptions : Flag<"-fexceptions">, Group<f_Group>;
|
||||
def fextdirs_EQ : Joined<"-fextdirs=">, Group<f_Group>;
|
||||
def fhosted : Flag<"-fhosted">, Group<f_Group>;
|
||||
def ffreestanding : Flag<"-ffreestanding">, Group<f_Group>;
|
||||
def fformat_extensions: Flag<"-fformat-extensions">;
|
||||
def fgnu_keywords : Flag<"-fgnu-keywords">, Group<f_Group>;
|
||||
def fgnu_runtime : Flag<"-fgnu-runtime">, Group<f_Group>;
|
||||
def fheinous_gnu_extensions : Flag<"-fheinous-gnu-extensions">;
|
||||
|
@ -210,7 +210,8 @@ static bool ParseArgPosition(FormatStringHandler &H,
|
||||
static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H,
|
||||
const char *&Beg,
|
||||
const char *E,
|
||||
unsigned &argIndex) {
|
||||
unsigned &argIndex,
|
||||
bool FormatExtensions) {
|
||||
|
||||
using namespace clang::analyze_printf;
|
||||
|
||||
@ -369,11 +370,19 @@ static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H,
|
||||
case '@': k = ConversionSpecifier::ObjCObjArg; break;
|
||||
// Glibc specific.
|
||||
case 'm': k = ConversionSpecifier::PrintErrno; break;
|
||||
// FreeBSD format extensions
|
||||
case 'b': if (FormatExtensions) k = ConversionSpecifier::bArg; break; /* check for int and then char * */
|
||||
case 'r': if (FormatExtensions) k = ConversionSpecifier::xArg; break;
|
||||
case 'y': if (FormatExtensions) k = ConversionSpecifier::iArg; break;
|
||||
case 'D': if (FormatExtensions) k = ConversionSpecifier::DArg; break; /* check for u_char * pointer and a char * string */
|
||||
}
|
||||
ConversionSpecifier CS(conversionPosition, k);
|
||||
FS.setConversionSpecifier(CS);
|
||||
if (CS.consumesDataArgument() && !FS.usesPositionalArg())
|
||||
FS.setArgIndex(argIndex++);
|
||||
// FreeBSD extension
|
||||
if (k == ConversionSpecifier::bArg || k == ConversionSpecifier::DArg)
|
||||
argIndex++;
|
||||
|
||||
if (k == ConversionSpecifier::InvalidSpecifier) {
|
||||
// Assume the conversion takes one argument.
|
||||
@ -383,13 +392,13 @@ static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H,
|
||||
}
|
||||
|
||||
bool clang::analyze_printf::ParseFormatString(FormatStringHandler &H,
|
||||
const char *I, const char *E) {
|
||||
const char *I, const char *E, bool FormatExtensions) {
|
||||
|
||||
unsigned argIndex = 0;
|
||||
|
||||
// Keep looking for a format specifier until we have exhausted the string.
|
||||
while (I != E) {
|
||||
const FormatSpecifierResult &FSR = ParseFormatSpecifier(H, I, E, argIndex);
|
||||
const FormatSpecifierResult &FSR = ParseFormatSpecifier(H, I, E, argIndex, FormatExtensions);
|
||||
// Did a fail-stop error of any kind occur when parsing the specifier?
|
||||
// If so, don't do any more processing.
|
||||
if (FSR.shouldStop())
|
||||
|
@ -1156,6 +1156,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
Args.AddLastArg(CmdArgs, options::OPT_fcatch_undefined_behavior);
|
||||
Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls);
|
||||
Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions);
|
||||
Args.AddLastArg(CmdArgs, options::OPT_fformat_extensions);
|
||||
|
||||
// -flax-vector-conversions is default.
|
||||
if (!Args.hasFlag(options::OPT_flax_vector_conversions,
|
||||
|
@ -530,6 +530,8 @@ static void LangOptsToArgs(const LangOptions &Opts,
|
||||
Res.push_back("-fgnu-runtime");
|
||||
if (Opts.Freestanding)
|
||||
Res.push_back("-ffreestanding");
|
||||
if (Opts.FormatExtensions)
|
||||
Res.push_back("-fformat-extensions");
|
||||
if (Opts.NoBuiltin)
|
||||
Res.push_back("-fno-builtin");
|
||||
if (!Opts.AssumeSaneOperatorNew)
|
||||
@ -1245,6 +1247,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args,
|
||||
Opts.CharIsSigned = !Args.hasArg(OPT_fno_signed_char);
|
||||
Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar);
|
||||
Opts.Freestanding = Args.hasArg(OPT_ffreestanding);
|
||||
Opts.FormatExtensions = Args.hasArg(OPT_fformat_extensions);
|
||||
Opts.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding;
|
||||
Opts.AssumeSaneOperatorNew = !Args.hasArg(OPT_fno_assume_sane_operator_new);
|
||||
Opts.HeinousExtensions = Args.hasArg(OPT_fheinous_gnu_extensions);
|
||||
|
@ -1276,6 +1276,39 @@ CheckPrintfHandler::HandleFormatSpecifier(const analyze_printf::FormatSpecifier
|
||||
CoveredArgs.set(argIndex);
|
||||
}
|
||||
|
||||
// FreeBSD extensions
|
||||
if (CS.getKind() == ConversionSpecifier::bArg || CS.getKind() == ConversionSpecifier::DArg) {
|
||||
// claim the second argument
|
||||
CoveredArgs.set(argIndex + 1);
|
||||
|
||||
// Now type check the data expression that matches the
|
||||
// format specifier.
|
||||
const Expr *Ex = getDataArg(argIndex);
|
||||
QualType type = (CS.getKind() == ConversionSpecifier::bArg) ? S.Context.IntTy : S.Context.getPointerType(S.Context.UnsignedCharTy);
|
||||
//const analyze_printf::ArgTypeResult &ATR = S.Context.IntTy;
|
||||
const analyze_printf::ArgTypeResult &ATR = type;
|
||||
if (ATR.isValid() && !ATR.matchesType(S.Context, Ex->getType()))
|
||||
S.Diag(getLocationOfByte(CS.getStart()),
|
||||
diag::warn_printf_conversion_argument_type_mismatch)
|
||||
<< ATR.getRepresentativeType(S.Context) << Ex->getType()
|
||||
<< getFormatSpecifierRange(startSpecifier, specifierLen)
|
||||
<< Ex->getSourceRange();
|
||||
|
||||
// Now type check the data expression that matches the
|
||||
// format specifier.
|
||||
Ex = getDataArg(argIndex + 1);
|
||||
const analyze_printf::ArgTypeResult &ATR2 = ArgTypeResult::CStrTy;
|
||||
if (ATR2.isValid() && !ATR2.matchesType(S.Context, Ex->getType()))
|
||||
S.Diag(getLocationOfByte(CS.getStart()),
|
||||
diag::warn_printf_conversion_argument_type_mismatch)
|
||||
<< ATR2.getRepresentativeType(S.Context) << Ex->getType()
|
||||
<< getFormatSpecifierRange(startSpecifier, specifierLen)
|
||||
<< Ex->getSourceRange();
|
||||
|
||||
return true;
|
||||
}
|
||||
// END OF FREEBSD EXTENSIONS
|
||||
|
||||
// Check for using an Objective-C specific conversion specifier
|
||||
// in a non-ObjC literal.
|
||||
if (!IsObjCLiteral && CS.isObjCArg()) {
|
||||
@ -1400,7 +1433,8 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr,
|
||||
isa<ObjCStringLiteral>(OrigFormatExpr), Str,
|
||||
HasVAListArg, TheCall, format_idx);
|
||||
|
||||
if (!analyze_printf::ParseFormatString(H, Str, Str + StrLen))
|
||||
bool FormatExtensions = getLangOptions().FormatExtensions;
|
||||
if (!analyze_printf::ParseFormatString(H, Str, Str + StrLen, FormatExtensions))
|
||||
H.DoneProcessing();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user