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