patch-r208987-format-extensions.diff revision 269012
1This patch adds support for the FreeBSD-specific -fformat-extension option,
2which enables additional printf modifiers for the kernel.
3
4Introduced here: http://svnweb.freebsd.org/changeset/base/208987
5
6Index: tools/clang/lib/Frontend/CompilerInvocation.cpp
7===================================================================
8--- tools/clang/lib/Frontend/CompilerInvocation.cpp
9+++ tools/clang/lib/Frontend/CompilerInvocation.cpp
10@@ -1319,6 +1319,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgLi
11   Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar);
12   Opts.ShortEnums = Args.hasArg(OPT_fshort_enums);
13   Opts.Freestanding = Args.hasArg(OPT_ffreestanding);
14+  Opts.FormatExtensions = Args.hasArg(OPT_fformat_extensions);
15   Opts.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding;
16   Opts.NoMathBuiltin = Args.hasArg(OPT_fno_math_builtin);
17   Opts.AssumeSaneOperatorNew = !Args.hasArg(OPT_fno_assume_sane_operator_new);
18Index: tools/clang/lib/Analysis/FormatString.cpp
19===================================================================
20--- tools/clang/lib/Analysis/FormatString.cpp
21+++ tools/clang/lib/Analysis/FormatString.cpp
22@@ -548,6 +548,11 @@ const char *ConversionSpecifier::toString() const
23   // Objective-C specific specifiers.
24   case ObjCObjArg: return "@";
25 
26+  // FreeBSD specific specifiers.
27+  case FreeBSDbArg: return "b";
28+  case FreeBSDDArg: return "D";
29+  case FreeBSDrArg: return "r";
30+
31   // GlibC specific specifiers.
32   case PrintErrno: return "m";
33   }
34@@ -626,6 +631,7 @@ bool FormatSpecifier::hasValidLengthModifier(const
35         case ConversionSpecifier::xArg:
36         case ConversionSpecifier::XArg:
37         case ConversionSpecifier::nArg:
38+        case ConversionSpecifier::FreeBSDrArg:
39           return true;
40         default:
41           return false;
42@@ -654,6 +660,7 @@ bool FormatSpecifier::hasValidLengthModifier(const
43         case ConversionSpecifier::nArg:
44         case ConversionSpecifier::cArg:
45         case ConversionSpecifier::sArg:
46+        case ConversionSpecifier::FreeBSDrArg:
47         case ConversionSpecifier::ScanListArg:
48           return true;
49         default:
50@@ -774,6 +781,9 @@ bool FormatSpecifier::hasStandardConversionSpecifi
51     case ConversionSpecifier::SArg:
52       return LangOpt.ObjC1 || LangOpt.ObjC2;
53     case ConversionSpecifier::InvalidSpecifier:
54+    case ConversionSpecifier::FreeBSDbArg:
55+    case ConversionSpecifier::FreeBSDDArg:
56+    case ConversionSpecifier::FreeBSDrArg:
57     case ConversionSpecifier::PrintErrno:
58     case ConversionSpecifier::DArg:
59     case ConversionSpecifier::OArg:
60Index: tools/clang/lib/Analysis/PrintfFormatString.cpp
61===================================================================
62--- tools/clang/lib/Analysis/PrintfFormatString.cpp
63+++ tools/clang/lib/Analysis/PrintfFormatString.cpp
64@@ -198,10 +198,25 @@ static PrintfSpecifierResult ParsePrintfSpecifier(
65     case '@': k = ConversionSpecifier::ObjCObjArg; break;
66     // Glibc specific.
67     case 'm': k = ConversionSpecifier::PrintErrno; break;
68+    // FreeBSD format extensions
69+    case 'b':
70+      if (LO.FormatExtensions)
71+        k = ConversionSpecifier::FreeBSDbArg; // int followed by char *
72+      break;
73+    case 'r':
74+      if (LO.FormatExtensions)
75+        k = ConversionSpecifier::FreeBSDrArg;
76+      break;
77+    case 'y':
78+      if (LO.FormatExtensions)
79+        k = ConversionSpecifier::iArg;
80+      break;
81     // Apple-specific
82     case 'D':
83       if (Target.getTriple().isOSDarwin())
84         k = ConversionSpecifier::DArg;
85+      else if (LO.FormatExtensions)
86+        k = ConversionSpecifier::FreeBSDDArg; // u_char * followed by char *
87       break;
88     case 'O':
89       if (Target.getTriple().isOSDarwin())
90@@ -216,6 +231,10 @@ static PrintfSpecifierResult ParsePrintfSpecifier(
91   FS.setConversionSpecifier(CS);
92   if (CS.consumesDataArgument() && !FS.usesPositionalArg())
93     FS.setArgIndex(argIndex++);
94+  // FreeBSD extension
95+  if (k == ConversionSpecifier::FreeBSDbArg ||
96+      k == ConversionSpecifier::FreeBSDDArg)
97+    argIndex++;
98 
99   if (k == ConversionSpecifier::InvalidSpecifier) {
100     // Assume the conversion takes one argument.
101@@ -618,6 +637,7 @@ bool PrintfSpecifier::hasValidPlusPrefix() const {
102   case ConversionSpecifier::GArg:
103   case ConversionSpecifier::aArg:
104   case ConversionSpecifier::AArg:
105+  case ConversionSpecifier::FreeBSDrArg:
106     return true;
107 
108   default:
109@@ -643,6 +663,7 @@ bool PrintfSpecifier::hasValidAlternativeForm() co
110   case ConversionSpecifier::FArg:
111   case ConversionSpecifier::gArg:
112   case ConversionSpecifier::GArg:
113+  case ConversionSpecifier::FreeBSDrArg:
114     return true;
115 
116   default:
117Index: tools/clang/lib/Sema/SemaChecking.cpp
118===================================================================
119--- tools/clang/lib/Sema/SemaChecking.cpp
120+++ tools/clang/lib/Sema/SemaChecking.cpp
121@@ -2980,6 +2980,40 @@ CheckPrintfHandler::HandlePrintfSpecifier(const an
122     CoveredArgs.set(argIndex);
123   }
124 
125+  // FreeBSD extensions
126+  if (CS.getKind() == ConversionSpecifier::FreeBSDbArg ||
127+      CS.getKind() == ConversionSpecifier::FreeBSDDArg) { 
128+    // claim the second argument
129+    CoveredArgs.set(argIndex + 1);
130+
131+    // Now type check the data expression that matches the
132+    // format specifier.
133+    const Expr *Ex = getDataArg(argIndex);
134+    const analyze_printf::ArgType &AT = 
135+      (CS.getKind() == ConversionSpecifier::FreeBSDbArg) ?
136+        ArgType(S.Context.IntTy) : ArgType::CStrTy;
137+    if (AT.isValid() && !AT.matchesType(S.Context, Ex->getType()))
138+      S.Diag(getLocationOfByte(CS.getStart()),
139+             diag::warn_printf_conversion_argument_type_mismatch)
140+        << AT.getRepresentativeType(S.Context) << Ex->getType()
141+        << getSpecifierRange(startSpecifier, specifierLen)
142+        << Ex->getSourceRange();
143+
144+    // Now type check the data expression that matches the
145+    // format specifier.
146+    Ex = getDataArg(argIndex + 1);
147+    const analyze_printf::ArgType &AT2 = ArgType::CStrTy;
148+    if (AT2.isValid() && !AT2.matchesType(S.Context, Ex->getType()))
149+      S.Diag(getLocationOfByte(CS.getStart()),
150+             diag::warn_printf_conversion_argument_type_mismatch)
151+        << AT2.getRepresentativeType(S.Context) << Ex->getType()
152+        << getSpecifierRange(startSpecifier, specifierLen)
153+        << Ex->getSourceRange();
154+
155+     return true;
156+  }
157+  // END OF FREEBSD EXTENSIONS
158+
159   // Check for using an Objective-C specific conversion specifier
160   // in a non-ObjC literal.
161   if (!ObjCContext && CS.isObjCArg()) {
162Index: tools/clang/lib/Driver/Tools.cpp
163===================================================================
164--- tools/clang/lib/Driver/Tools.cpp
165+++ tools/clang/lib/Driver/Tools.cpp
166@@ -2991,6 +2991,7 @@ void Clang::ConstructJob(Compilation &C, const Job
167 
168   // Forward -f (flag) options which we can pass directly.
169   Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls);
170+  Args.AddLastArg(CmdArgs, options::OPT_fformat_extensions);
171   Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions);
172   Args.AddLastArg(CmdArgs, options::OPT_flimit_debug_info);
173   Args.AddLastArg(CmdArgs, options::OPT_fno_limit_debug_info);
174Index: tools/clang/include/clang/Basic/LangOptions.def
175===================================================================
176--- tools/clang/include/clang/Basic/LangOptions.def
177+++ tools/clang/include/clang/Basic/LangOptions.def
178@@ -84,6 +84,7 @@ LANGOPT(TraditionalCPP    , 1, 0, "traditional CPP
179 LANGOPT(RTTI              , 1, 1, "run-time type information")
180 LANGOPT(MSBitfields       , 1, 0, "Microsoft-compatible structure layout")
181 LANGOPT(Freestanding, 1, 0, "freestanding implementation")
182+LANGOPT(FormatExtensions  , 1, 0, "FreeBSD format extensions")
183 LANGOPT(NoBuiltin         , 1, 0, "disable builtin functions")
184 LANGOPT(NoMathBuiltin     , 1, 0, "disable math builtin functions")
185 
186Index: tools/clang/include/clang/Analysis/Analyses/FormatString.h
187===================================================================
188--- tools/clang/include/clang/Analysis/Analyses/FormatString.h
189+++ tools/clang/include/clang/Analysis/Analyses/FormatString.h
190@@ -158,6 +158,11 @@ class ConversionSpecifier {
191     ObjCObjArg,  // '@'
192     ObjCBeg = ObjCObjArg, ObjCEnd = ObjCObjArg,
193 
194+    // FreeBSD specific specifiers
195+    FreeBSDbArg,
196+    FreeBSDDArg,
197+    FreeBSDrArg,
198+
199     // GlibC specific specifiers.
200     PrintErrno,   // 'm'
201 
202Index: tools/clang/include/clang/Driver/Options.td
203===================================================================
204--- tools/clang/include/clang/Driver/Options.td
205+++ tools/clang/include/clang/Driver/Options.td
206@@ -530,6 +530,8 @@ def fno_rewrite_includes : Flag<["-"], "fno-rewrit
207 
208 def ffreestanding : Flag<["-"], "ffreestanding">, Group<f_Group>, Flags<[CC1Option]>,
209   HelpText<"Assert that the compilation takes place in a freestanding environment">;
210+def fformat_extensions: Flag<["-"], "fformat-extensions">, Group<f_Group>, Flags<[CC1Option]>,
211+  HelpText<"Enable FreeBSD kernel specific format string extensions">;
212 def fgnu_keywords : Flag<["-"], "fgnu-keywords">, Group<f_Group>, Flags<[CC1Option]>,
213   HelpText<"Allow GNU-extension keywords regardless of language standard">;
214 def fgnu89_inline : Flag<["-"], "fgnu89-inline">, Group<f_Group>, Flags<[CC1Option]>,
215