Warnings.cpp revision 302408
1231200Smm//===--- Warnings.cpp - C-Language Front-end ------------------------------===// 2231200Smm// 3231200Smm// The LLVM Compiler Infrastructure 4231200Smm// 5231200Smm// This file is distributed under the University of Illinois Open Source 6231200Smm// License. See LICENSE.TXT for details. 7231200Smm// 8231200Smm//===----------------------------------------------------------------------===// 9231200Smm// 10231200Smm// Command line warning options handler. 11231200Smm// 12231200Smm//===----------------------------------------------------------------------===// 13231200Smm// 14231200Smm// This file is responsible for handling all warning options. This includes 15231200Smm// a number of -Wfoo options and their variants, which are driven by TableGen- 16231200Smm// generated data, and the special cases -pedantic, -pedantic-errors, -w, 17231200Smm// -Werror and -Wfatal-errors. 18231200Smm// 19231200Smm// Each warning option controls any number of actual warnings. 20231200Smm// Given a warning option 'foo', the following are valid: 21231200Smm// -Wfoo, -Wno-foo, -Werror=foo, -Wfatal-errors=foo 22231200Smm// 23231200Smm// Remark options are also handled here, analogously, except that they are much 24231200Smm// simpler because a remark can't be promoted to an error. 25231200Smm#include "clang/Basic/AllDiagnostics.h" 26231200Smm#include "clang/Basic/Diagnostic.h" 27231200Smm#include "clang/Basic/DiagnosticOptions.h" 28231200Smm#include <algorithm> 29231200Smm#include <cstring> 30231200Smm#include <utility> 31231200Smmusing namespace clang; 32231200Smm 33231200Smm// EmitUnknownDiagWarning - Emit a warning and typo hint for unknown warning 34231200Smm// opts 35231200Smmstatic void EmitUnknownDiagWarning(DiagnosticsEngine &Diags, 36231200Smm diag::Flavor Flavor, StringRef Prefix, 37231200Smm StringRef Opt) { 38231200Smm StringRef Suggestion = DiagnosticIDs::getNearestOption(Flavor, Opt); 39231200Smm Diags.Report(diag::warn_unknown_diag_option) 40231200Smm << (Flavor == diag::Flavor::WarningOrError ? 0 : 1) << (Prefix.str() += Opt) 41231200Smm << !Suggestion.empty() << (Prefix.str() += Suggestion); 42231200Smm} 43231200Smm 44231200Smmvoid clang::ProcessWarningOptions(DiagnosticsEngine &Diags, 45231200Smm const DiagnosticOptions &Opts, 46231200Smm bool ReportDiags) { 47231200Smm Diags.setSuppressSystemWarnings(true); // Default to -Wno-system-headers 48231200Smm Diags.setIgnoreAllWarnings(Opts.IgnoreWarnings); 49231200Smm Diags.setShowOverloads(Opts.getShowOverloads()); 50231200Smm 51231200Smm Diags.setElideType(Opts.ElideType); 52231200Smm Diags.setPrintTemplateTree(Opts.ShowTemplateTree); 53231200Smm Diags.setShowColors(Opts.ShowColors); 54231200Smm 55231200Smm // Handle -ferror-limit 56231200Smm if (Opts.ErrorLimit) 57231200Smm Diags.setErrorLimit(Opts.ErrorLimit); 58231200Smm if (Opts.TemplateBacktraceLimit) 59231200Smm Diags.setTemplateBacktraceLimit(Opts.TemplateBacktraceLimit); 60231200Smm if (Opts.ConstexprBacktraceLimit) 61231200Smm Diags.setConstexprBacktraceLimit(Opts.ConstexprBacktraceLimit); 62231200Smm 63231200Smm // If -pedantic or -pedantic-errors was specified, then we want to map all 64231200Smm // extension diagnostics onto WARNING or ERROR unless the user has futz'd 65231200Smm // around with them explicitly. 66231200Smm if (Opts.PedanticErrors) 67231200Smm Diags.setExtensionHandlingBehavior(diag::Severity::Error); 68231200Smm else if (Opts.Pedantic) 69231200Smm Diags.setExtensionHandlingBehavior(diag::Severity::Warning); 70231200Smm else 71231200Smm Diags.setExtensionHandlingBehavior(diag::Severity::Ignored); 72231200Smm 73231200Smm SmallVector<diag::kind, 10> _Diags; 74231200Smm const IntrusiveRefCntPtr< DiagnosticIDs > DiagIDs = 75231200Smm Diags.getDiagnosticIDs(); 76231200Smm // We parse the warning options twice. The first pass sets diagnostic state, 77231200Smm // while the second pass reports warnings/errors. This has the effect that 78231200Smm // we follow the more canonical "last option wins" paradigm when there are 79231200Smm // conflicting options. 80231200Smm for (unsigned Report = 0, ReportEnd = 2; Report != ReportEnd; ++Report) { 81231200Smm bool SetDiagnostic = (Report == 0); 82231200Smm 83231200Smm // If we've set the diagnostic state and are not reporting diagnostics then 84231200Smm // we're done. 85231200Smm if (!SetDiagnostic && !ReportDiags) 86231200Smm break; 87231200Smm 88231200Smm for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i) { 89231200Smm const auto Flavor = diag::Flavor::WarningOrError; 90231200Smm StringRef Opt = Opts.Warnings[i]; 91231200Smm StringRef OrigOpt = Opts.Warnings[i]; 92231200Smm 93231200Smm // Treat -Wformat=0 as an alias for -Wno-format. 94231200Smm if (Opt == "format=0") 95231200Smm Opt = "no-format"; 96231200Smm 97231200Smm // Check to see if this warning starts with "no-", if so, this is a 98231200Smm // negative form of the option. 99231200Smm bool isPositive = true; 100231200Smm if (Opt.startswith("no-")) { 101231200Smm isPositive = false; 102231200Smm Opt = Opt.substr(3); 103231200Smm } 104231200Smm 105231200Smm // Figure out how this option affects the warning. If -Wfoo, map the 106231200Smm // diagnostic to a warning, if -Wno-foo, map it to ignore. 107231200Smm diag::Severity Mapping = 108231200Smm isPositive ? diag::Severity::Warning : diag::Severity::Ignored; 109231200Smm 110231200Smm // -Wsystem-headers is a special case, not driven by the option table. It 111231200Smm // cannot be controlled with -Werror. 112231200Smm if (Opt == "system-headers") { 113231200Smm if (SetDiagnostic) 114231200Smm Diags.setSuppressSystemWarnings(!isPositive); 115231200Smm continue; 116231200Smm } 117231200Smm 118231200Smm // -Weverything is a special case as well. It implicitly enables all 119231200Smm // warnings, including ones not explicitly in a warning group. 120231200Smm if (Opt == "everything") { 121231200Smm if (SetDiagnostic) { 122231200Smm if (isPositive) { 123231200Smm Diags.setEnableAllWarnings(true); 124231200Smm } else { 125231200Smm Diags.setEnableAllWarnings(false); 126231200Smm Diags.setSeverityForAll(Flavor, diag::Severity::Ignored); 127231200Smm } 128231200Smm } 129231200Smm continue; 130231200Smm } 131231200Smm 132231200Smm // -Werror/-Wno-error is a special case, not controlled by the option 133231200Smm // table. It also has the "specifier" form of -Werror=foo and -Werror-foo. 134231200Smm if (Opt.startswith("error")) { 135231200Smm StringRef Specifier; 136231200Smm if (Opt.size() > 5) { // Specifier must be present. 137231200Smm if ((Opt[5] != '=' && Opt[5] != '-') || Opt.size() == 6) { 138231200Smm if (Report) 139231200Smm Diags.Report(diag::warn_unknown_warning_specifier) 140231200Smm << "-Werror" << ("-W" + OrigOpt.str()); 141231200Smm continue; 142231200Smm } 143231200Smm Specifier = Opt.substr(6); 144231200Smm } 145231200Smm 146231200Smm if (Specifier.empty()) { 147231200Smm if (SetDiagnostic) 148231200Smm Diags.setWarningsAsErrors(isPositive); 149231200Smm continue; 150231200Smm } 151231200Smm 152231200Smm if (SetDiagnostic) { 153231200Smm // Set the warning as error flag for this specifier. 154231200Smm Diags.setDiagnosticGroupWarningAsError(Specifier, isPositive); 155232153Smm } else if (DiagIDs->getDiagnosticsInGroup(Flavor, Specifier, _Diags)) { 156232153Smm EmitUnknownDiagWarning(Diags, Flavor, "-Werror=", Specifier); 157231200Smm } 158231200Smm continue; 159 } 160 161 // -Wfatal-errors is yet another special case. 162 if (Opt.startswith("fatal-errors")) { 163 StringRef Specifier; 164 if (Opt.size() != 12) { 165 if ((Opt[12] != '=' && Opt[12] != '-') || Opt.size() == 13) { 166 if (Report) 167 Diags.Report(diag::warn_unknown_warning_specifier) 168 << "-Wfatal-errors" << ("-W" + OrigOpt.str()); 169 continue; 170 } 171 Specifier = Opt.substr(13); 172 } 173 174 if (Specifier.empty()) { 175 if (SetDiagnostic) 176 Diags.setErrorsAsFatal(isPositive); 177 continue; 178 } 179 180 if (SetDiagnostic) { 181 // Set the error as fatal flag for this specifier. 182 Diags.setDiagnosticGroupErrorAsFatal(Specifier, isPositive); 183 } else if (DiagIDs->getDiagnosticsInGroup(Flavor, Specifier, _Diags)) { 184 EmitUnknownDiagWarning(Diags, Flavor, "-Wfatal-errors=", Specifier); 185 } 186 continue; 187 } 188 189 if (Report) { 190 if (DiagIDs->getDiagnosticsInGroup(Flavor, Opt, _Diags)) 191 EmitUnknownDiagWarning(Diags, Flavor, isPositive ? "-W" : "-Wno-", 192 Opt); 193 } else { 194 Diags.setSeverityForGroup(Flavor, Opt, Mapping); 195 } 196 } 197 198 for (unsigned i = 0, e = Opts.Remarks.size(); i != e; ++i) { 199 StringRef Opt = Opts.Remarks[i]; 200 const auto Flavor = diag::Flavor::Remark; 201 202 // Check to see if this warning starts with "no-", if so, this is a 203 // negative form of the option. 204 bool IsPositive = !Opt.startswith("no-"); 205 if (!IsPositive) Opt = Opt.substr(3); 206 207 auto Severity = IsPositive ? diag::Severity::Remark 208 : diag::Severity::Ignored; 209 210 // -Reverything sets the state of all remarks. Note that all remarks are 211 // in remark groups, so we don't need a separate 'all remarks enabled' 212 // flag. 213 if (Opt == "everything") { 214 if (SetDiagnostic) 215 Diags.setSeverityForAll(Flavor, Severity); 216 continue; 217 } 218 219 if (Report) { 220 if (DiagIDs->getDiagnosticsInGroup(Flavor, Opt, _Diags)) 221 EmitUnknownDiagWarning(Diags, Flavor, IsPositive ? "-R" : "-Rno-", 222 Opt); 223 } else { 224 Diags.setSeverityForGroup(Flavor, Opt, 225 IsPositive ? diag::Severity::Remark 226 : diag::Severity::Ignored); 227 } 228 } 229 } 230} 231