This patch adds support for the FreeBSD-specific -fformat-extension option, which enables additional printf modifiers for the kernel. Introduced here: http://svnweb.freebsd.org/changeset/base/208987 Index: tools/clang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- tools/clang/lib/Frontend/CompilerInvocation.cpp +++ tools/clang/lib/Frontend/CompilerInvocation.cpp @@ -1319,6 +1319,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgLi Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar); Opts.ShortEnums = Args.hasArg(OPT_fshort_enums); Opts.Freestanding = Args.hasArg(OPT_ffreestanding); + Opts.FormatExtensions = Args.hasArg(OPT_fformat_extensions); Opts.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding; Opts.NoMathBuiltin = Args.hasArg(OPT_fno_math_builtin); Opts.AssumeSaneOperatorNew = !Args.hasArg(OPT_fno_assume_sane_operator_new); Index: tools/clang/lib/Analysis/FormatString.cpp =================================================================== --- tools/clang/lib/Analysis/FormatString.cpp +++ tools/clang/lib/Analysis/FormatString.cpp @@ -548,6 +548,11 @@ const char *ConversionSpecifier::toString() const // Objective-C specific specifiers. case ObjCObjArg: return "@"; + // FreeBSD specific specifiers. + case FreeBSDbArg: return "b"; + case FreeBSDDArg: return "D"; + case FreeBSDrArg: return "r"; + // GlibC specific specifiers. case PrintErrno: return "m"; } @@ -626,6 +631,7 @@ bool FormatSpecifier::hasValidLengthModifier(const case ConversionSpecifier::xArg: case ConversionSpecifier::XArg: case ConversionSpecifier::nArg: + case ConversionSpecifier::FreeBSDrArg: return true; default: return false; @@ -654,6 +660,7 @@ bool FormatSpecifier::hasValidLengthModifier(const case ConversionSpecifier::nArg: case ConversionSpecifier::cArg: case ConversionSpecifier::sArg: + case ConversionSpecifier::FreeBSDrArg: case ConversionSpecifier::ScanListArg: return true; default: @@ -774,6 +781,9 @@ bool FormatSpecifier::hasStandardConversionSpecifi case ConversionSpecifier::SArg: return LangOpt.ObjC1 || LangOpt.ObjC2; case ConversionSpecifier::InvalidSpecifier: + case ConversionSpecifier::FreeBSDbArg: + case ConversionSpecifier::FreeBSDDArg: + case ConversionSpecifier::FreeBSDrArg: case ConversionSpecifier::PrintErrno: case ConversionSpecifier::DArg: case ConversionSpecifier::OArg: Index: tools/clang/lib/Analysis/PrintfFormatString.cpp =================================================================== --- tools/clang/lib/Analysis/PrintfFormatString.cpp +++ tools/clang/lib/Analysis/PrintfFormatString.cpp @@ -198,10 +198,25 @@ static PrintfSpecifierResult ParsePrintfSpecifier( case '@': k = ConversionSpecifier::ObjCObjArg; break; // Glibc specific. case 'm': k = ConversionSpecifier::PrintErrno; break; + // FreeBSD format extensions + case 'b': + if (LO.FormatExtensions) + k = ConversionSpecifier::FreeBSDbArg; // int followed by char * + break; + case 'r': + if (LO.FormatExtensions) + k = ConversionSpecifier::FreeBSDrArg; + break; + case 'y': + if (LO.FormatExtensions) + k = ConversionSpecifier::iArg; + break; // Apple-specific case 'D': if (Target.getTriple().isOSDarwin()) k = ConversionSpecifier::DArg; + else if (LO.FormatExtensions) + k = ConversionSpecifier::FreeBSDDArg; // u_char * followed by char * break; case 'O': if (Target.getTriple().isOSDarwin()) @@ -216,6 +231,10 @@ static PrintfSpecifierResult ParsePrintfSpecifier( FS.setConversionSpecifier(CS); if (CS.consumesDataArgument() && !FS.usesPositionalArg()) FS.setArgIndex(argIndex++); + // FreeBSD extension + if (k == ConversionSpecifier::FreeBSDbArg || + k == ConversionSpecifier::FreeBSDDArg) + argIndex++; if (k == ConversionSpecifier::InvalidSpecifier) { // Assume the conversion takes one argument. @@ -618,6 +637,7 @@ bool PrintfSpecifier::hasValidPlusPrefix() const { case ConversionSpecifier::GArg: case ConversionSpecifier::aArg: case ConversionSpecifier::AArg: + case ConversionSpecifier::FreeBSDrArg: return true; default: @@ -643,6 +663,7 @@ bool PrintfSpecifier::hasValidAlternativeForm() co case ConversionSpecifier::FArg: case ConversionSpecifier::gArg: case ConversionSpecifier::GArg: + case ConversionSpecifier::FreeBSDrArg: return true; default: Index: tools/clang/lib/Sema/SemaChecking.cpp =================================================================== --- tools/clang/lib/Sema/SemaChecking.cpp +++ tools/clang/lib/Sema/SemaChecking.cpp @@ -2980,6 +2980,42 @@ CheckPrintfHandler::HandlePrintfSpecifier(const an CoveredArgs.set(argIndex); } + // FreeBSD kernel extensions. + if (CS.getKind() == ConversionSpecifier::FreeBSDbArg || + CS.getKind() == ConversionSpecifier::FreeBSDDArg) { + // We need at least two arguments. + if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex + 1)) + return false; + + // Claim the second argument. + CoveredArgs.set(argIndex + 1); + + // Type check the first argument (int for %b, pointer for %D) + const Expr *Ex = getDataArg(argIndex); + const analyze_printf::ArgType &AT = + (CS.getKind() == ConversionSpecifier::FreeBSDbArg) ? + ArgType(S.Context.IntTy) : ArgType::CPointerTy; + if (AT.isValid() && !AT.matchesType(S.Context, Ex->getType())) + S.Diag(getLocationOfByte(CS.getStart()), + diag::warn_printf_conversion_argument_type_mismatch) + << AT.getRepresentativeType(S.Context) << Ex->getType() + << getSpecifierRange(startSpecifier, specifierLen) + << Ex->getSourceRange(); + + // Type check the second argument (char * for both %b and %D) + Ex = getDataArg(argIndex + 1); + const analyze_printf::ArgType &AT2 = ArgType::CStrTy; + if (AT2.isValid() && !AT2.matchesType(S.Context, Ex->getType())) + S.Diag(getLocationOfByte(CS.getStart()), + diag::warn_printf_conversion_argument_type_mismatch) + << AT2.getRepresentativeType(S.Context) << Ex->getType() + << getSpecifierRange(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 (!ObjCContext && CS.isObjCArg()) { Index: tools/clang/lib/Driver/Tools.cpp =================================================================== --- tools/clang/lib/Driver/Tools.cpp +++ tools/clang/lib/Driver/Tools.cpp @@ -2984,6 +2984,7 @@ void Clang::ConstructJob(Compilation &C, const Job // Forward -f (flag) options which we can pass directly. Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls); + Args.AddLastArg(CmdArgs, options::OPT_fformat_extensions); Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions); Args.AddLastArg(CmdArgs, options::OPT_flimit_debug_info); Args.AddLastArg(CmdArgs, options::OPT_fno_limit_debug_info); Index: tools/clang/include/clang/Basic/LangOptions.def =================================================================== --- tools/clang/include/clang/Basic/LangOptions.def +++ tools/clang/include/clang/Basic/LangOptions.def @@ -84,6 +84,7 @@ LANGOPT(TraditionalCPP , 1, 0, "traditional CPP LANGOPT(RTTI , 1, 1, "run-time type information") LANGOPT(MSBitfields , 1, 0, "Microsoft-compatible structure layout") LANGOPT(Freestanding, 1, 0, "freestanding implementation") +LANGOPT(FormatExtensions , 1, 0, "FreeBSD format extensions") LANGOPT(NoBuiltin , 1, 0, "disable builtin functions") LANGOPT(NoMathBuiltin , 1, 0, "disable math builtin functions") Index: tools/clang/include/clang/Analysis/Analyses/FormatString.h =================================================================== --- tools/clang/include/clang/Analysis/Analyses/FormatString.h +++ tools/clang/include/clang/Analysis/Analyses/FormatString.h @@ -158,6 +158,11 @@ class ConversionSpecifier { ObjCObjArg, // '@' ObjCBeg = ObjCObjArg, ObjCEnd = ObjCObjArg, + // FreeBSD specific specifiers + FreeBSDbArg, + FreeBSDDArg, + FreeBSDrArg, + // GlibC specific specifiers. PrintErrno, // 'm' Index: tools/clang/include/clang/Driver/Options.td =================================================================== --- tools/clang/include/clang/Driver/Options.td +++ tools/clang/include/clang/Driver/Options.td @@ -530,6 +530,8 @@ def fno_rewrite_includes : Flag<["-"], "fno-rewrit def ffreestanding : Flag<["-"], "ffreestanding">, Group, Flags<[CC1Option]>, HelpText<"Assert that the compilation takes place in a freestanding environment">; +def fformat_extensions: Flag<["-"], "fformat-extensions">, Group, Flags<[CC1Option]>, + HelpText<"Enable FreeBSD kernel specific format string extensions">; def fgnu_keywords : Flag<["-"], "fgnu-keywords">, Group, Flags<[CC1Option]>, HelpText<"Allow GNU-extension keywords regardless of language standard">; def fgnu89_inline : Flag<["-"], "fgnu89-inline">, Group, Flags<[CC1Option]>,