Sebastian Redl | 63a9e0f | 2009-03-06 17:41:35 +0000 | [diff] [blame] | 1 | //===--- Warnings.cpp - C-Language Front-end ------------------------------===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // Command line warning options handler. |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | // |
| 14 | // This file is responsible for handling all warning options. This includes |
| 15 | // a number of -Wfoo options and their variants, which are driven by TableGen- |
| 16 | // generated data, and the special cases -pedantic, -pedantic-errors, -w and |
| 17 | // -Werror. |
| 18 | // |
| 19 | // Warning options control the handling of the warnings that Clang emits. There |
| 20 | // are three possible reactions to any given warning: |
| 21 | // ignore: Do nothing |
| 22 | // warn: Emit a message, but don't fail the compilation |
| 23 | // error: Emit a message and fail the compilation |
| 24 | // |
Sebastian Redl | c5613db | 2009-03-07 12:09:25 +0000 | [diff] [blame] | 25 | // Each warning option controls any number of actual warnings. |
Sebastian Redl | 63a9e0f | 2009-03-06 17:41:35 +0000 | [diff] [blame] | 26 | // Given a warning option 'foo', the following are valid: |
| 27 | // -Wfoo=ignore -> Ignore the controlled warnings. |
| 28 | // -Wfoo=warn -> Warn about the controlled warnings. |
| 29 | // -Wfoo=error -> Fail on the controlled warnings. |
| 30 | // -Wfoo -> alias of -Wfoo=warn |
| 31 | // -Wno-foo -> alias of -Wfoo=ignore |
| 32 | // -Werror=foo -> alias of -Wfoo=error |
| 33 | // |
| 34 | // Because of this complex handling of options, the default parser is replaced. |
| 35 | |
Chris Lattner | d613c3d | 2009-04-08 22:37:15 +0000 | [diff] [blame] | 36 | #include "clang-cc.h" |
Sebastian Redl | 63a9e0f | 2009-03-06 17:41:35 +0000 | [diff] [blame] | 37 | #include "clang/Basic/Diagnostic.h" |
| 38 | #include "clang/Sema/SemaDiagnostic.h" |
| 39 | #include "clang/Lex/LexDiagnostic.h" |
| 40 | #include "llvm/Support/CommandLine.h" |
Chris Lattner | 3c304bd | 2009-04-11 18:40:46 +0000 | [diff] [blame^] | 41 | #include <cstdio> |
Sebastian Redl | 63a9e0f | 2009-03-06 17:41:35 +0000 | [diff] [blame] | 42 | #include <utility> |
| 43 | #include <algorithm> |
Sebastian Redl | 63a9e0f | 2009-03-06 17:41:35 +0000 | [diff] [blame] | 44 | using namespace clang; |
| 45 | |
| 46 | namespace { |
| 47 | struct ParsedOption { |
| 48 | std::string Name; |
| 49 | diag::Mapping Mapping; |
| 50 | |
| 51 | ParsedOption() {} |
| 52 | // Used by -Werror, implicitly. |
| 53 | ParsedOption(const std::string& name) : Name(name), Mapping(diag::MAP_ERROR) |
| 54 | {} |
| 55 | }; |
| 56 | |
| 57 | typedef std::vector<ParsedOption> OptionsList; |
| 58 | |
| 59 | OptionsList Options; |
| 60 | |
| 61 | struct WarningParser : public llvm::cl::basic_parser<ParsedOption> { |
| 62 | diag::Mapping StrToMapping(const std::string &S) { |
| 63 | if (S == "ignore") |
| 64 | return diag::MAP_IGNORE; |
| 65 | if (S == "warn") |
| 66 | return diag::MAP_WARNING; |
| 67 | if (S == "error") |
| 68 | return diag::MAP_ERROR; |
| 69 | return diag::MAP_DEFAULT; |
| 70 | } |
| 71 | bool parse(llvm::cl::Option &O, const char *ArgName, |
| 72 | const std::string &ArgValue, ParsedOption &Val) |
| 73 | { |
| 74 | size_t Eq = ArgValue.find("="); |
| 75 | if (Eq == std::string::npos) { |
| 76 | // Could be -Wfoo or -Wno-foo |
| 77 | if (ArgValue.compare(0, 3, "no-") == 0) { |
| 78 | Val.Name = ArgValue.substr(3); |
| 79 | Val.Mapping = diag::MAP_IGNORE; |
| 80 | } else { |
| 81 | Val.Name = ArgValue; |
| 82 | Val.Mapping = diag::MAP_WARNING; |
| 83 | } |
| 84 | } else { |
| 85 | Val.Name = ArgValue.substr(0, Eq); |
| 86 | Val.Mapping = StrToMapping(ArgValue.substr(Eq+1)); |
Sebastian Redl | c5613db | 2009-03-07 12:09:25 +0000 | [diff] [blame] | 87 | if (Val.Mapping == diag::MAP_DEFAULT) { |
| 88 | fprintf(stderr, "Illegal warning option value: %s\n", |
| 89 | ArgValue.substr(Eq+1).c_str()); |
Sebastian Redl | 63a9e0f | 2009-03-06 17:41:35 +0000 | [diff] [blame] | 90 | return true; |
Sebastian Redl | c5613db | 2009-03-07 12:09:25 +0000 | [diff] [blame] | 91 | } |
Sebastian Redl | 63a9e0f | 2009-03-06 17:41:35 +0000 | [diff] [blame] | 92 | } |
| 93 | return false; |
| 94 | } |
| 95 | }; |
| 96 | } |
| 97 | |
| 98 | static llvm::cl::list<ParsedOption, OptionsList, WarningParser> |
| 99 | OptWarnings("W", llvm::cl::location(Options), llvm::cl::Prefix); |
| 100 | |
| 101 | static llvm::cl::list<ParsedOption, OptionsList, llvm::cl::parser<std::string> > |
| 102 | OptWError("Werror", llvm::cl::location(Options), llvm::cl::CommaSeparated, |
| 103 | llvm::cl::ValueOptional); |
| 104 | |
| 105 | static llvm::cl::opt<bool> OptPedantic("pedantic"); |
| 106 | static llvm::cl::opt<bool> OptPedanticErrors("pedantic-errors"); |
| 107 | static llvm::cl::opt<bool> OptNoWarnings("w"); |
| 108 | static llvm::cl::opt<bool> |
Chris Lattner | db7bc58 | 2009-03-09 20:44:22 +0000 | [diff] [blame] | 109 | OptWarnInSystemHeaders("Wsystem-headers", |
| 110 | llvm::cl::desc("Do not suppress warnings issued in system headers")); |
Sebastian Redl | 63a9e0f | 2009-03-06 17:41:35 +0000 | [diff] [blame] | 111 | |
| 112 | namespace { |
| 113 | struct WarningOption { |
| 114 | const char *Name; |
| 115 | const diag::kind *Members; |
| 116 | size_t NumMembers; |
| 117 | }; |
Sebastian Redl | 63a9e0f | 2009-03-06 17:41:35 +0000 | [diff] [blame] | 118 | } |
| 119 | #define DIAGS(a) a, (sizeof(a) / sizeof(a[0])) |
| 120 | // These tables will be TableGenerated later. |
| 121 | // First the table sets describing the diagnostics controlled by each option. |
| 122 | static const diag::kind UnusedMacrosDiags[] = { diag::pp_macro_not_used }; |
| 123 | static const diag::kind FloatEqualDiags[] = { diag::warn_floatingpoint_eq }; |
| 124 | static const diag::kind ReadOnlySetterAttrsDiags[] = { |
| 125 | diag::warn_objc_property_attr_mutually_exclusive |
| 126 | }; |
| 127 | static const diag::kind FormatNonLiteralDiags[] = { |
| 128 | diag::warn_printf_not_string_constant |
| 129 | }; |
| 130 | static const diag::kind UndefDiags[] = { diag::warn_pp_undef_identifier }; |
| 131 | static const diag::kind ImplicitFunctionDeclarationDiags[] = { |
| 132 | diag::ext_implicit_function_decl, diag::warn_implicit_function_decl |
| 133 | }; |
Eli Friedman | 757e0dd | 2009-03-30 21:19:48 +0000 | [diff] [blame] | 134 | static const diag::kind PointerSignDiags[] = { |
| 135 | diag::ext_typecheck_convert_incompatible_pointer_sign |
| 136 | }; |
Steve Naroff | 17f689f | 2009-03-31 15:00:11 +0000 | [diff] [blame] | 137 | static const diag::kind DeprecatedDeclarations[] = { diag::warn_deprecated }; |
Douglas Gregor | 8499f3f | 2009-03-31 16:35:03 +0000 | [diff] [blame] | 138 | static const diag::kind MissingPrototypesDiags[] = { |
| 139 | diag::warn_missing_prototype |
| 140 | }; |
Chris Lattner | d613c3d | 2009-04-08 22:37:15 +0000 | [diff] [blame] | 141 | static const diag::kind TrigraphsDiags[] = { |
| 142 | diag::trigraph_ignored, diag::trigraph_ignored_block_comment, |
| 143 | diag::trigraph_ends_block_comment, diag::trigraph_converted |
| 144 | }; |
Steve Naroff | 17f689f | 2009-03-31 15:00:11 +0000 | [diff] [blame] | 145 | |
Sebastian Redl | 63a9e0f | 2009-03-06 17:41:35 +0000 | [diff] [blame] | 146 | // Hmm ... this option is currently actually completely ignored. |
| 147 | //static const diag::kind StrictSelectorMatchDiags[] = { }; |
| 148 | // Second the table of options. MUST be sorted by name! Binary lookup is done. |
| 149 | static const WarningOption OptionTable[] = { |
Steve Naroff | 17f689f | 2009-03-31 15:00:11 +0000 | [diff] [blame] | 150 | { "deprecated-declarations", DIAGS(DeprecatedDeclarations) }, |
Sebastian Redl | 63a9e0f | 2009-03-06 17:41:35 +0000 | [diff] [blame] | 151 | { "float-equal", DIAGS(FloatEqualDiags) }, |
| 152 | { "format-nonliteral", DIAGS(FormatNonLiteralDiags) }, |
| 153 | { "implicit-function-declaration", DIAGS(ImplicitFunctionDeclarationDiags) }, |
Douglas Gregor | 8499f3f | 2009-03-31 16:35:03 +0000 | [diff] [blame] | 154 | { "missing-prototypes", DIAGS(MissingPrototypesDiags) }, |
Eli Friedman | 757e0dd | 2009-03-30 21:19:48 +0000 | [diff] [blame] | 155 | { "pointer-sign", DIAGS(PointerSignDiags) }, |
Sebastian Redl | 63a9e0f | 2009-03-06 17:41:35 +0000 | [diff] [blame] | 156 | { "readonly-setter-attrs", DIAGS(ReadOnlySetterAttrsDiags) }, |
Chris Lattner | d613c3d | 2009-04-08 22:37:15 +0000 | [diff] [blame] | 157 | { "trigraphs", DIAGS(TrigraphsDiags) }, |
Sebastian Redl | 63a9e0f | 2009-03-06 17:41:35 +0000 | [diff] [blame] | 158 | { "undef", DIAGS(UndefDiags) }, |
| 159 | { "unused-macros", DIAGS(UnusedMacrosDiags) }, |
| 160 | // { "strict-selector-match", DIAGS(StrictSelectorMatchDiags) } |
| 161 | }; |
| 162 | static const size_t OptionTableSize = |
| 163 | sizeof(OptionTable) / sizeof(OptionTable[0]); |
| 164 | |
Chris Lattner | d613c3d | 2009-04-08 22:37:15 +0000 | [diff] [blame] | 165 | static bool WarningOptionCompare(const WarningOption &LHS, |
| 166 | const WarningOption &RHS) { |
| 167 | return strcmp(LHS.Name, RHS.Name) < 0; |
| 168 | } |
Sebastian Redl | 63a9e0f | 2009-03-06 17:41:35 +0000 | [diff] [blame] | 169 | |
Chris Lattner | d613c3d | 2009-04-08 22:37:15 +0000 | [diff] [blame] | 170 | bool clang::ProcessWarningOptions(Diagnostic &Diags) { |
Sebastian Redl | 63a9e0f | 2009-03-06 17:41:35 +0000 | [diff] [blame] | 171 | // FIXME: These should be mapped to group options. |
| 172 | Diags.setIgnoreAllWarnings(OptNoWarnings); |
| 173 | Diags.setWarnOnExtensions(OptPedantic); |
| 174 | Diags.setErrorOnExtensions(OptPedanticErrors); |
| 175 | |
| 176 | // Set some defaults that are currently set manually. This, too, should |
| 177 | // be in the tablegen stuff later. |
| 178 | Diags.setDiagnosticMapping(diag::pp_macro_not_used, diag::MAP_IGNORE); |
| 179 | Diags.setDiagnosticMapping(diag::warn_floatingpoint_eq, diag::MAP_IGNORE); |
| 180 | Diags.setDiagnosticMapping(diag::warn_objc_property_attr_mutually_exclusive, |
| 181 | diag::MAP_IGNORE); |
| 182 | Diags.setDiagnosticMapping(diag::warn_pp_undef_identifier, diag::MAP_IGNORE); |
| 183 | Diags.setDiagnosticMapping(diag::warn_implicit_function_decl, |
| 184 | diag::MAP_IGNORE); |
| 185 | |
| 186 | Diags.setDiagnosticMapping(diag::err_pp_file_not_found, diag::MAP_FATAL); |
Douglas Gregor | 525c4b0 | 2009-03-19 18:55:06 +0000 | [diff] [blame] | 187 | Diags.setDiagnosticMapping(diag::err_template_recursion_depth_exceeded, |
| 188 | diag::MAP_FATAL); |
Douglas Gregor | 8499f3f | 2009-03-31 16:35:03 +0000 | [diff] [blame] | 189 | Diags.setDiagnosticMapping(diag::warn_missing_prototype, diag::MAP_IGNORE); |
Chris Lattner | db7bc58 | 2009-03-09 20:44:22 +0000 | [diff] [blame] | 190 | Diags.setSuppressSystemWarnings(!OptWarnInSystemHeaders); |
Sebastian Redl | 63a9e0f | 2009-03-06 17:41:35 +0000 | [diff] [blame] | 191 | |
| 192 | for (OptionsList::iterator it = Options.begin(), e = Options.end(); |
| 193 | it != e; ++it) { |
| 194 | if (it->Name.empty()) { |
| 195 | // Empty string is "everything". This way, -Werror does the right thing. |
| 196 | // FIXME: These flags do not participate in proper option overriding. |
| 197 | switch(it->Mapping) { |
| 198 | default: |
| 199 | assert(false && "Illegal mapping"); |
| 200 | break; |
| 201 | |
| 202 | case diag::MAP_IGNORE: |
| 203 | Diags.setIgnoreAllWarnings(true); |
| 204 | Diags.setWarningsAsErrors(false); |
| 205 | break; |
| 206 | |
| 207 | case diag::MAP_WARNING: |
| 208 | Diags.setIgnoreAllWarnings(false); |
| 209 | Diags.setWarningsAsErrors(false); |
| 210 | break; |
| 211 | |
| 212 | case diag::MAP_ERROR: |
| 213 | Diags.setIgnoreAllWarnings(false); |
| 214 | Diags.setWarningsAsErrors(true); |
| 215 | break; |
| 216 | } |
| 217 | continue; |
| 218 | } |
| 219 | WarningOption Key = { it->Name.c_str(), 0, 0 }; |
Chris Lattner | d613c3d | 2009-04-08 22:37:15 +0000 | [diff] [blame] | 220 | const WarningOption *Found = |
| 221 | std::lower_bound(OptionTable, OptionTable + OptionTableSize, Key, |
| 222 | WarningOptionCompare); |
Sebastian Redl | 63a9e0f | 2009-03-06 17:41:35 +0000 | [diff] [blame] | 223 | if (Found == OptionTable + OptionTableSize || |
Sebastian Redl | c5613db | 2009-03-07 12:09:25 +0000 | [diff] [blame] | 224 | strcmp(Found->Name, Key.Name) != 0) { |
| 225 | fprintf(stderr, "Unknown warning option: -W%s\n", Key.Name); |
Sebastian Redl | 63a9e0f | 2009-03-06 17:41:35 +0000 | [diff] [blame] | 226 | return true; |
Sebastian Redl | c5613db | 2009-03-07 12:09:25 +0000 | [diff] [blame] | 227 | } |
Sebastian Redl | 63a9e0f | 2009-03-06 17:41:35 +0000 | [diff] [blame] | 228 | |
| 229 | // Option exists. |
Chris Lattner | d613c3d | 2009-04-08 22:37:15 +0000 | [diff] [blame] | 230 | for (size_t i = 0, e = Found->NumMembers; i != e; ++i) |
Sebastian Redl | 63a9e0f | 2009-03-06 17:41:35 +0000 | [diff] [blame] | 231 | Diags.setDiagnosticMapping(Found->Members[i], it->Mapping); |
Sebastian Redl | 63a9e0f | 2009-03-06 17:41:35 +0000 | [diff] [blame] | 232 | } |
| 233 | return false; |
| 234 | } |