Path: blob/main/contrib/llvm-project/clang/lib/Basic/Warnings.cpp
35233 views
//===--- Warnings.cpp - C-Language Front-end ------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Command line warning options handler.9//10//===----------------------------------------------------------------------===//11//12// This file is responsible for handling all warning options. This includes13// a number of -Wfoo options and their variants, which are driven by TableGen-14// generated data, and the special cases -pedantic, -pedantic-errors, -w,15// -Werror and -Wfatal-errors.16//17// Each warning option controls any number of actual warnings.18// Given a warning option 'foo', the following are valid:19// -Wfoo, -Wno-foo, -Werror=foo, -Wfatal-errors=foo20//21// Remark options are also handled here, analogously, except that they are much22// simpler because a remark can't be promoted to an error.23#include "clang/Basic/AllDiagnostics.h"24#include "clang/Basic/Diagnostic.h"25#include "clang/Basic/DiagnosticOptions.h"26#include <algorithm>27#include <cstring>28#include <utility>29using namespace clang;3031// EmitUnknownDiagWarning - Emit a warning and typo hint for unknown warning32// opts33static void EmitUnknownDiagWarning(DiagnosticsEngine &Diags,34diag::Flavor Flavor, StringRef Prefix,35StringRef Opt) {36StringRef Suggestion = DiagnosticIDs::getNearestOption(Flavor, Opt);37Diags.Report(diag::warn_unknown_diag_option)38<< (Flavor == diag::Flavor::WarningOrError ? 0 : 1)39<< (Prefix.str() += std::string(Opt)) << !Suggestion.empty()40<< (Prefix.str() += std::string(Suggestion));41}4243void clang::ProcessWarningOptions(DiagnosticsEngine &Diags,44const DiagnosticOptions &Opts,45bool ReportDiags) {46Diags.setSuppressSystemWarnings(true); // Default to -Wno-system-headers47Diags.setIgnoreAllWarnings(Opts.IgnoreWarnings);48Diags.setShowOverloads(Opts.getShowOverloads());4950Diags.setElideType(Opts.ElideType);51Diags.setPrintTemplateTree(Opts.ShowTemplateTree);52Diags.setShowColors(Opts.ShowColors);5354// Handle -ferror-limit55if (Opts.ErrorLimit)56Diags.setErrorLimit(Opts.ErrorLimit);57if (Opts.TemplateBacktraceLimit)58Diags.setTemplateBacktraceLimit(Opts.TemplateBacktraceLimit);59if (Opts.ConstexprBacktraceLimit)60Diags.setConstexprBacktraceLimit(Opts.ConstexprBacktraceLimit);6162// If -pedantic or -pedantic-errors was specified, then we want to map all63// extension diagnostics onto WARNING or ERROR unless the user has futz'd64// around with them explicitly.65if (Opts.PedanticErrors)66Diags.setExtensionHandlingBehavior(diag::Severity::Error);67else if (Opts.Pedantic)68Diags.setExtensionHandlingBehavior(diag::Severity::Warning);69else70Diags.setExtensionHandlingBehavior(diag::Severity::Ignored);7172SmallVector<diag::kind, 10> _Diags;73const IntrusiveRefCntPtr< DiagnosticIDs > DiagIDs =74Diags.getDiagnosticIDs();75// We parse the warning options twice. The first pass sets diagnostic state,76// while the second pass reports warnings/errors. This has the effect that77// we follow the more canonical "last option wins" paradigm when there are78// conflicting options.79for (unsigned Report = 0, ReportEnd = 2; Report != ReportEnd; ++Report) {80bool SetDiagnostic = (Report == 0);8182// If we've set the diagnostic state and are not reporting diagnostics then83// we're done.84if (!SetDiagnostic && !ReportDiags)85break;8687for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i) {88const auto Flavor = diag::Flavor::WarningOrError;89StringRef Opt = Opts.Warnings[i];90StringRef OrigOpt = Opts.Warnings[i];9192// Treat -Wformat=0 as an alias for -Wno-format.93if (Opt == "format=0")94Opt = "no-format";9596// Check to see if this warning starts with "no-", if so, this is a97// negative form of the option.98bool isPositive = !Opt.consume_front("no-");99100// Figure out how this option affects the warning. If -Wfoo, map the101// diagnostic to a warning, if -Wno-foo, map it to ignore.102diag::Severity Mapping =103isPositive ? diag::Severity::Warning : diag::Severity::Ignored;104105// -Wsystem-headers is a special case, not driven by the option table. It106// cannot be controlled with -Werror.107if (Opt == "system-headers") {108if (SetDiagnostic)109Diags.setSuppressSystemWarnings(!isPositive);110continue;111}112113// -Weverything is a special case as well. It implicitly enables all114// warnings, including ones not explicitly in a warning group.115if (Opt == "everything") {116if (SetDiagnostic) {117if (isPositive) {118Diags.setEnableAllWarnings(true);119} else {120Diags.setEnableAllWarnings(false);121Diags.setSeverityForAll(Flavor, diag::Severity::Ignored);122}123}124continue;125}126127// -Werror/-Wno-error is a special case, not controlled by the option128// table. It also has the "specifier" form of -Werror=foo. GCC supports129// the deprecated -Werror-implicit-function-declaration which is used by130// a few projects.131if (Opt.starts_with("error")) {132StringRef Specifier;133if (Opt.size() > 5) { // Specifier must be present.134if (Opt[5] != '=' &&135Opt.substr(5) != "-implicit-function-declaration") {136if (Report)137Diags.Report(diag::warn_unknown_warning_specifier)138<< "-Werror" << ("-W" + OrigOpt.str());139continue;140}141Specifier = Opt.substr(6);142}143144if (Specifier.empty()) {145if (SetDiagnostic)146Diags.setWarningsAsErrors(isPositive);147continue;148}149150if (SetDiagnostic) {151// Set the warning as error flag for this specifier.152Diags.setDiagnosticGroupWarningAsError(Specifier, isPositive);153} else if (DiagIDs->getDiagnosticsInGroup(Flavor, Specifier, _Diags)) {154EmitUnknownDiagWarning(Diags, Flavor, "-Werror=", Specifier);155}156continue;157}158159// -Wfatal-errors is yet another special case.160if (Opt.starts_with("fatal-errors")) {161StringRef Specifier;162if (Opt.size() != 12) {163if ((Opt[12] != '=' && Opt[12] != '-') || Opt.size() == 13) {164if (Report)165Diags.Report(diag::warn_unknown_warning_specifier)166<< "-Wfatal-errors" << ("-W" + OrigOpt.str());167continue;168}169Specifier = Opt.substr(13);170}171172if (Specifier.empty()) {173if (SetDiagnostic)174Diags.setErrorsAsFatal(isPositive);175continue;176}177178if (SetDiagnostic) {179// Set the error as fatal flag for this specifier.180Diags.setDiagnosticGroupErrorAsFatal(Specifier, isPositive);181} else if (DiagIDs->getDiagnosticsInGroup(Flavor, Specifier, _Diags)) {182EmitUnknownDiagWarning(Diags, Flavor, "-Wfatal-errors=", Specifier);183}184continue;185}186187if (Report) {188if (DiagIDs->getDiagnosticsInGroup(Flavor, Opt, _Diags))189EmitUnknownDiagWarning(Diags, Flavor, isPositive ? "-W" : "-Wno-",190Opt);191} else {192Diags.setSeverityForGroup(Flavor, Opt, Mapping);193}194}195196for (StringRef Opt : Opts.Remarks) {197const auto Flavor = diag::Flavor::Remark;198199// Check to see if this warning starts with "no-", if so, this is a200// negative form of the option.201bool IsPositive = !Opt.consume_front("no-");202203auto Severity = IsPositive ? diag::Severity::Remark204: diag::Severity::Ignored;205206// -Reverything sets the state of all remarks. Note that all remarks are207// in remark groups, so we don't need a separate 'all remarks enabled'208// flag.209if (Opt == "everything") {210if (SetDiagnostic)211Diags.setSeverityForAll(Flavor, Severity);212continue;213}214215if (Report) {216if (DiagIDs->getDiagnosticsInGroup(Flavor, Opt, _Diags))217EmitUnknownDiagWarning(Diags, Flavor, IsPositive ? "-R" : "-Rno-",218Opt);219} else {220Diags.setSeverityForGroup(Flavor, Opt,221IsPositive ? diag::Severity::Remark222: diag::Severity::Ignored);223}224}225}226}227228229