1*67e74705SXin Li //===--- Warnings.cpp - C-Language Front-end ------------------------------===//
2*67e74705SXin Li //
3*67e74705SXin Li // The LLVM Compiler Infrastructure
4*67e74705SXin Li //
5*67e74705SXin Li // This file is distributed under the University of Illinois Open Source
6*67e74705SXin Li // License. See LICENSE.TXT for details.
7*67e74705SXin Li //
8*67e74705SXin Li //===----------------------------------------------------------------------===//
9*67e74705SXin Li //
10*67e74705SXin Li // Command line warning options handler.
11*67e74705SXin Li //
12*67e74705SXin Li //===----------------------------------------------------------------------===//
13*67e74705SXin Li //
14*67e74705SXin Li // This file is responsible for handling all warning options. This includes
15*67e74705SXin Li // a number of -Wfoo options and their variants, which are driven by TableGen-
16*67e74705SXin Li // generated data, and the special cases -pedantic, -pedantic-errors, -w,
17*67e74705SXin Li // -Werror and -Wfatal-errors.
18*67e74705SXin Li //
19*67e74705SXin Li // Each warning option controls any number of actual warnings.
20*67e74705SXin Li // Given a warning option 'foo', the following are valid:
21*67e74705SXin Li // -Wfoo, -Wno-foo, -Werror=foo, -Wfatal-errors=foo
22*67e74705SXin Li //
23*67e74705SXin Li // Remark options are also handled here, analogously, except that they are much
24*67e74705SXin Li // simpler because a remark can't be promoted to an error.
25*67e74705SXin Li #include "clang/Basic/AllDiagnostics.h"
26*67e74705SXin Li #include "clang/Basic/Diagnostic.h"
27*67e74705SXin Li #include "clang/Basic/DiagnosticOptions.h"
28*67e74705SXin Li #include <algorithm>
29*67e74705SXin Li #include <cstring>
30*67e74705SXin Li #include <utility>
31*67e74705SXin Li using namespace clang;
32*67e74705SXin Li
33*67e74705SXin Li // EmitUnknownDiagWarning - Emit a warning and typo hint for unknown warning
34*67e74705SXin Li // opts
EmitUnknownDiagWarning(DiagnosticsEngine & Diags,diag::Flavor Flavor,StringRef Prefix,StringRef Opt)35*67e74705SXin Li static void EmitUnknownDiagWarning(DiagnosticsEngine &Diags,
36*67e74705SXin Li diag::Flavor Flavor, StringRef Prefix,
37*67e74705SXin Li StringRef Opt) {
38*67e74705SXin Li StringRef Suggestion = DiagnosticIDs::getNearestOption(Flavor, Opt);
39*67e74705SXin Li Diags.Report(diag::warn_unknown_diag_option)
40*67e74705SXin Li << (Flavor == diag::Flavor::WarningOrError ? 0 : 1) << (Prefix.str() += Opt)
41*67e74705SXin Li << !Suggestion.empty() << (Prefix.str() += Suggestion);
42*67e74705SXin Li }
43*67e74705SXin Li
ProcessWarningOptions(DiagnosticsEngine & Diags,const DiagnosticOptions & Opts,bool ReportDiags)44*67e74705SXin Li void clang::ProcessWarningOptions(DiagnosticsEngine &Diags,
45*67e74705SXin Li const DiagnosticOptions &Opts,
46*67e74705SXin Li bool ReportDiags) {
47*67e74705SXin Li Diags.setSuppressSystemWarnings(true); // Default to -Wno-system-headers
48*67e74705SXin Li Diags.setIgnoreAllWarnings(Opts.IgnoreWarnings);
49*67e74705SXin Li Diags.setShowOverloads(Opts.getShowOverloads());
50*67e74705SXin Li
51*67e74705SXin Li Diags.setElideType(Opts.ElideType);
52*67e74705SXin Li Diags.setPrintTemplateTree(Opts.ShowTemplateTree);
53*67e74705SXin Li Diags.setShowColors(Opts.ShowColors);
54*67e74705SXin Li
55*67e74705SXin Li // Handle -ferror-limit
56*67e74705SXin Li if (Opts.ErrorLimit)
57*67e74705SXin Li Diags.setErrorLimit(Opts.ErrorLimit);
58*67e74705SXin Li if (Opts.TemplateBacktraceLimit)
59*67e74705SXin Li Diags.setTemplateBacktraceLimit(Opts.TemplateBacktraceLimit);
60*67e74705SXin Li if (Opts.ConstexprBacktraceLimit)
61*67e74705SXin Li Diags.setConstexprBacktraceLimit(Opts.ConstexprBacktraceLimit);
62*67e74705SXin Li
63*67e74705SXin Li // If -pedantic or -pedantic-errors was specified, then we want to map all
64*67e74705SXin Li // extension diagnostics onto WARNING or ERROR unless the user has futz'd
65*67e74705SXin Li // around with them explicitly.
66*67e74705SXin Li if (Opts.PedanticErrors)
67*67e74705SXin Li Diags.setExtensionHandlingBehavior(diag::Severity::Error);
68*67e74705SXin Li else if (Opts.Pedantic)
69*67e74705SXin Li Diags.setExtensionHandlingBehavior(diag::Severity::Warning);
70*67e74705SXin Li else
71*67e74705SXin Li Diags.setExtensionHandlingBehavior(diag::Severity::Ignored);
72*67e74705SXin Li
73*67e74705SXin Li SmallVector<diag::kind, 10> _Diags;
74*67e74705SXin Li const IntrusiveRefCntPtr< DiagnosticIDs > DiagIDs =
75*67e74705SXin Li Diags.getDiagnosticIDs();
76*67e74705SXin Li // We parse the warning options twice. The first pass sets diagnostic state,
77*67e74705SXin Li // while the second pass reports warnings/errors. This has the effect that
78*67e74705SXin Li // we follow the more canonical "last option wins" paradigm when there are
79*67e74705SXin Li // conflicting options.
80*67e74705SXin Li for (unsigned Report = 0, ReportEnd = 2; Report != ReportEnd; ++Report) {
81*67e74705SXin Li bool SetDiagnostic = (Report == 0);
82*67e74705SXin Li
83*67e74705SXin Li // If we've set the diagnostic state and are not reporting diagnostics then
84*67e74705SXin Li // we're done.
85*67e74705SXin Li if (!SetDiagnostic && !ReportDiags)
86*67e74705SXin Li break;
87*67e74705SXin Li
88*67e74705SXin Li for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i) {
89*67e74705SXin Li const auto Flavor = diag::Flavor::WarningOrError;
90*67e74705SXin Li StringRef Opt = Opts.Warnings[i];
91*67e74705SXin Li StringRef OrigOpt = Opts.Warnings[i];
92*67e74705SXin Li
93*67e74705SXin Li // Treat -Wformat=0 as an alias for -Wno-format.
94*67e74705SXin Li if (Opt == "format=0")
95*67e74705SXin Li Opt = "no-format";
96*67e74705SXin Li
97*67e74705SXin Li // Check to see if this warning starts with "no-", if so, this is a
98*67e74705SXin Li // negative form of the option.
99*67e74705SXin Li bool isPositive = true;
100*67e74705SXin Li if (Opt.startswith("no-")) {
101*67e74705SXin Li isPositive = false;
102*67e74705SXin Li Opt = Opt.substr(3);
103*67e74705SXin Li }
104*67e74705SXin Li
105*67e74705SXin Li // Figure out how this option affects the warning. If -Wfoo, map the
106*67e74705SXin Li // diagnostic to a warning, if -Wno-foo, map it to ignore.
107*67e74705SXin Li diag::Severity Mapping =
108*67e74705SXin Li isPositive ? diag::Severity::Warning : diag::Severity::Ignored;
109*67e74705SXin Li
110*67e74705SXin Li // -Wsystem-headers is a special case, not driven by the option table. It
111*67e74705SXin Li // cannot be controlled with -Werror.
112*67e74705SXin Li if (Opt == "system-headers") {
113*67e74705SXin Li if (SetDiagnostic)
114*67e74705SXin Li Diags.setSuppressSystemWarnings(!isPositive);
115*67e74705SXin Li continue;
116*67e74705SXin Li }
117*67e74705SXin Li
118*67e74705SXin Li // -Weverything is a special case as well. It implicitly enables all
119*67e74705SXin Li // warnings, including ones not explicitly in a warning group.
120*67e74705SXin Li if (Opt == "everything") {
121*67e74705SXin Li if (SetDiagnostic) {
122*67e74705SXin Li if (isPositive) {
123*67e74705SXin Li Diags.setEnableAllWarnings(true);
124*67e74705SXin Li } else {
125*67e74705SXin Li Diags.setEnableAllWarnings(false);
126*67e74705SXin Li Diags.setSeverityForAll(Flavor, diag::Severity::Ignored);
127*67e74705SXin Li }
128*67e74705SXin Li }
129*67e74705SXin Li continue;
130*67e74705SXin Li }
131*67e74705SXin Li
132*67e74705SXin Li // -Werror/-Wno-error is a special case, not controlled by the option
133*67e74705SXin Li // table. It also has the "specifier" form of -Werror=foo and -Werror-foo.
134*67e74705SXin Li if (Opt.startswith("error")) {
135*67e74705SXin Li StringRef Specifier;
136*67e74705SXin Li if (Opt.size() > 5) { // Specifier must be present.
137*67e74705SXin Li if ((Opt[5] != '=' && Opt[5] != '-') || Opt.size() == 6) {
138*67e74705SXin Li if (Report)
139*67e74705SXin Li Diags.Report(diag::warn_unknown_warning_specifier)
140*67e74705SXin Li << "-Werror" << ("-W" + OrigOpt.str());
141*67e74705SXin Li continue;
142*67e74705SXin Li }
143*67e74705SXin Li Specifier = Opt.substr(6);
144*67e74705SXin Li }
145*67e74705SXin Li
146*67e74705SXin Li if (Specifier.empty()) {
147*67e74705SXin Li if (SetDiagnostic)
148*67e74705SXin Li Diags.setWarningsAsErrors(isPositive);
149*67e74705SXin Li continue;
150*67e74705SXin Li }
151*67e74705SXin Li
152*67e74705SXin Li if (SetDiagnostic) {
153*67e74705SXin Li // Set the warning as error flag for this specifier.
154*67e74705SXin Li Diags.setDiagnosticGroupWarningAsError(Specifier, isPositive);
155*67e74705SXin Li } else if (DiagIDs->getDiagnosticsInGroup(Flavor, Specifier, _Diags)) {
156*67e74705SXin Li EmitUnknownDiagWarning(Diags, Flavor, "-Werror=", Specifier);
157*67e74705SXin Li }
158*67e74705SXin Li continue;
159*67e74705SXin Li }
160*67e74705SXin Li
161*67e74705SXin Li // -Wfatal-errors is yet another special case.
162*67e74705SXin Li if (Opt.startswith("fatal-errors")) {
163*67e74705SXin Li StringRef Specifier;
164*67e74705SXin Li if (Opt.size() != 12) {
165*67e74705SXin Li if ((Opt[12] != '=' && Opt[12] != '-') || Opt.size() == 13) {
166*67e74705SXin Li if (Report)
167*67e74705SXin Li Diags.Report(diag::warn_unknown_warning_specifier)
168*67e74705SXin Li << "-Wfatal-errors" << ("-W" + OrigOpt.str());
169*67e74705SXin Li continue;
170*67e74705SXin Li }
171*67e74705SXin Li Specifier = Opt.substr(13);
172*67e74705SXin Li }
173*67e74705SXin Li
174*67e74705SXin Li if (Specifier.empty()) {
175*67e74705SXin Li if (SetDiagnostic)
176*67e74705SXin Li Diags.setErrorsAsFatal(isPositive);
177*67e74705SXin Li continue;
178*67e74705SXin Li }
179*67e74705SXin Li
180*67e74705SXin Li if (SetDiagnostic) {
181*67e74705SXin Li // Set the error as fatal flag for this specifier.
182*67e74705SXin Li Diags.setDiagnosticGroupErrorAsFatal(Specifier, isPositive);
183*67e74705SXin Li } else if (DiagIDs->getDiagnosticsInGroup(Flavor, Specifier, _Diags)) {
184*67e74705SXin Li EmitUnknownDiagWarning(Diags, Flavor, "-Wfatal-errors=", Specifier);
185*67e74705SXin Li }
186*67e74705SXin Li continue;
187*67e74705SXin Li }
188*67e74705SXin Li
189*67e74705SXin Li if (Report) {
190*67e74705SXin Li if (DiagIDs->getDiagnosticsInGroup(Flavor, Opt, _Diags))
191*67e74705SXin Li EmitUnknownDiagWarning(Diags, Flavor, isPositive ? "-W" : "-Wno-",
192*67e74705SXin Li Opt);
193*67e74705SXin Li } else {
194*67e74705SXin Li Diags.setSeverityForGroup(Flavor, Opt, Mapping);
195*67e74705SXin Li }
196*67e74705SXin Li }
197*67e74705SXin Li
198*67e74705SXin Li for (unsigned i = 0, e = Opts.Remarks.size(); i != e; ++i) {
199*67e74705SXin Li StringRef Opt = Opts.Remarks[i];
200*67e74705SXin Li const auto Flavor = diag::Flavor::Remark;
201*67e74705SXin Li
202*67e74705SXin Li // Check to see if this warning starts with "no-", if so, this is a
203*67e74705SXin Li // negative form of the option.
204*67e74705SXin Li bool IsPositive = !Opt.startswith("no-");
205*67e74705SXin Li if (!IsPositive) Opt = Opt.substr(3);
206*67e74705SXin Li
207*67e74705SXin Li auto Severity = IsPositive ? diag::Severity::Remark
208*67e74705SXin Li : diag::Severity::Ignored;
209*67e74705SXin Li
210*67e74705SXin Li // -Reverything sets the state of all remarks. Note that all remarks are
211*67e74705SXin Li // in remark groups, so we don't need a separate 'all remarks enabled'
212*67e74705SXin Li // flag.
213*67e74705SXin Li if (Opt == "everything") {
214*67e74705SXin Li if (SetDiagnostic)
215*67e74705SXin Li Diags.setSeverityForAll(Flavor, Severity);
216*67e74705SXin Li continue;
217*67e74705SXin Li }
218*67e74705SXin Li
219*67e74705SXin Li if (Report) {
220*67e74705SXin Li if (DiagIDs->getDiagnosticsInGroup(Flavor, Opt, _Diags))
221*67e74705SXin Li EmitUnknownDiagWarning(Diags, Flavor, IsPositive ? "-R" : "-Rno-",
222*67e74705SXin Li Opt);
223*67e74705SXin Li } else {
224*67e74705SXin Li Diags.setSeverityForGroup(Flavor, Opt,
225*67e74705SXin Li IsPositive ? diag::Severity::Remark
226*67e74705SXin Li : diag::Severity::Ignored);
227*67e74705SXin Li }
228*67e74705SXin Li }
229*67e74705SXin Li }
230*67e74705SXin Li }
231