diff options
author | Ted Kremenek <kremenek@apple.com> | 2012-07-07 05:53:30 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2012-07-07 05:53:30 +0000 |
commit | e8cf7d143446c45568bb7c9a6fbd8f32ca6ae93e (patch) | |
tree | 74441cc516babcf2ffdc1f8e76502252a793e395 | |
parent | 3b4c53259603ba389373362f476648b2b1ab9eca (diff) |
Re-apply r159875 with fixes.
- Split pedantic driver flag test into separate test file, and XFAIL on cygwin,mingw32
- Fix bug in tablegen logic where a missing '{' caused errors to be included in -Wpedantic.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@159892 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/DiagnosticGroups.td | 3 | ||||
-rw-r--r-- | include/clang/Driver/Options.td | 2 | ||||
-rw-r--r-- | lib/Driver/Tools.cpp | 3 | ||||
-rw-r--r-- | lib/Frontend/TextDiagnosticPrinter.cpp | 10 | ||||
-rw-r--r-- | test/Driver/warning-options_pedantic.cpp | 7 | ||||
-rw-r--r-- | test/Misc/show-diag-options.c | 2 | ||||
-rw-r--r-- | test/Misc/warning-flags.c | 74 | ||||
-rw-r--r-- | tools/libclang/CXStoredDiagnostic.cpp | 7 | ||||
-rw-r--r-- | utils/TableGen/ClangDiagnosticsEmitter.cpp | 239 |
9 files changed, 247 insertions, 100 deletions
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index 8753589bfb..c1f85c1ee8 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -380,6 +380,9 @@ def ThreadSafety : DiagGroup<"thread-safety", // DefaultIgnore in addition to putting it here. def : DiagGroup<"all", [Most, Parentheses, Switch]>; +// Warnings enabled by -pedantic. This is magically filled in by TableGen. +def Pedantic : DiagGroup<"pedantic">; + // Aliases. def : DiagGroup<"", [Extra]>; // -W = -Wextra def : DiagGroup<"endif-labels", [ExtraTokens]>; // -Wendif-labels=-Wendif-tokens diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index 48f9cd68b8..918718a189 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -868,6 +868,7 @@ def no_canonical_prefixes : Flag<"-no-canonical-prefixes">, Flags<[HelpHidden]>, def no_cpp_precomp : Flag<"-no-cpp-precomp">, Group<clang_ignored_f_Group>; def no_integrated_as : Flag<"-no-integrated-as">, Flags<[DriverOption]>; def no_integrated_cpp : Flag<"-no-integrated-cpp">, Flags<[DriverOption]>; +def no_pedantic : Flag<"-no-pedantic">, Group<pedantic_Group>; def no__dead__strip__inits__and__terms : Flag<"-no_dead_strip_inits_and_terms">; def nobuiltininc : Flag<"-nobuiltininc">, Flags<[CC1Option]>, HelpText<"Disable builtin #include directories">; @@ -1070,6 +1071,7 @@ def _machine_EQ : Joined<"--machine=">, Alias<m_Joined>; def _machine : Separate<"--machine">, Alias<m_Joined>; def _no_integrated_cpp : Flag<"--no-integrated-cpp">, Alias<no_integrated_cpp>; def _no_line_commands : Flag<"--no-line-commands">, Alias<P>; +def _no_pedantic : Flag<"--no-pedantic">, Alias<no_pedantic>; def _no_standard_includes : Flag<"--no-standard-includes">, Alias<nostdinc>; def _no_standard_libraries : Flag<"--no-standard-libraries">, Alias<nostdlib>; def _no_undefined : Flag<"--no-undefined">, Flags<[LinkerInput]>; diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index dd198a1e9d..66d792ffba 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -2093,7 +2093,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } Args.AddAllArgs(CmdArgs, options::OPT_W_Group); - Args.AddLastArg(CmdArgs, options::OPT_pedantic); + if (Args.hasFlag(options::OPT_pedantic, options::OPT_no_pedantic, false)) + CmdArgs.push_back("-pedantic"); Args.AddLastArg(CmdArgs, options::OPT_pedantic_errors); Args.AddLastArg(CmdArgs, options::OPT_w); diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp index d07917f234..30da72b4a9 100644 --- a/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/lib/Frontend/TextDiagnosticPrinter.cpp @@ -79,16 +79,6 @@ static void printDiagnosticOptions(raw_ostream &OS, Started = true; } - // If the diagnostic is an extension diagnostic and not enabled by default - // then it must have been turned on with -pedantic. - bool EnabledByDefault; - if (DiagnosticIDs::isBuiltinExtensionDiag(Info.getID(), - EnabledByDefault) && - !EnabledByDefault) { - OS << (Started ? "," : " [") << "-pedantic"; - Started = true; - } - StringRef Opt = DiagnosticIDs::getWarningOptionForDiag(Info.getID()); if (!Opt.empty()) { OS << (Started ? "," : " [") << "-W" << Opt; diff --git a/test/Driver/warning-options_pedantic.cpp b/test/Driver/warning-options_pedantic.cpp new file mode 100644 index 0000000000..c6d11be73d --- /dev/null +++ b/test/Driver/warning-options_pedantic.cpp @@ -0,0 +1,7 @@ +// RUN: %clang -### -pedantic -no-pedantic %s 2>&1 | FileCheck -check-prefix=NO_PEDANTIC %s +// RUN: %clang -### -pedantic -Wno-pedantic %s 2>&1 | FileCheck -check-prefix=PEDANTIC %s +// NO_PEDANTIC-NOT: -pedantic +// RUN: %clang -### -pedantic -pedantic -no-pedantic -pedantic %s 2>&1 | FileCheck -check-prefix=PEDANTIC %s +// RUN: %clang -### -pedantic -pedantic -no-pedantic -Wpedantic %s 2>&1 | FileCheck -check-prefix=NO_PEDANTIC %s +// PEDANTIC: -pedantic +// XFAIL: cygwin,mingw32 diff --git a/test/Misc/show-diag-options.c b/test/Misc/show-diag-options.c index f0404a8555..ef0a5a660d 100644 --- a/test/Misc/show-diag-options.c +++ b/test/Misc/show-diag-options.c @@ -23,5 +23,5 @@ void test(int x, int y) { // OPTION_ERROR_CATEGORY: {{.*}}: error: {{[a-z ]+}} [-Werror,-Wparentheses,Semantic Issue] // Leverage the fact that all these '//'s get warned about in C89 pedantic. - // OPTION_PEDANTIC: {{.*}}: warning: {{[/a-z ]+}} [-pedantic,-Wcomment] + // OPTION_PEDANTIC: {{.*}}: warning: {{[/a-z ]+}} [-Wcomment] } diff --git a/test/Misc/warning-flags.c b/test/Misc/warning-flags.c index 99ebf99150..15b2d27b21 100644 --- a/test/Misc/warning-flags.c +++ b/test/Misc/warning-flags.c @@ -17,66 +17,7 @@ This test serves two purposes: The list of warnings below should NEVER grow. It should gradually shrink to 0. -CHECK: Warnings without flags (229): -CHECK-NEXT: ext_anonymous_struct_union_qualified -CHECK-NEXT: ext_binary_literal -CHECK-NEXT: ext_cast_fn_obj -CHECK-NEXT: ext_delete_void_ptr_operand -CHECK-NEXT: ext_designated_init -CHECK-NEXT: ext_duplicate_declspec -CHECK-NEXT: ext_ellipsis_exception_spec -CHECK-NEXT: ext_enum_friend -CHECK-NEXT: ext_enum_value_not_int -CHECK-NEXT: ext_enumerator_list_comma -CHECK-NEXT: ext_expected_semi_decl_list -CHECK-NEXT: ext_explicit_instantiation_without_qualified_id -CHECK-NEXT: ext_explicit_specialization_storage_class -CHECK-NEXT: ext_forward_ref_enum -CHECK-NEXT: ext_freestanding_complex -CHECK-NEXT: ext_hexconstant_invalid -CHECK-NEXT: ext_ident_list_in_param -CHECK-NEXT: ext_imaginary_constant -CHECK-NEXT: ext_implicit_lib_function_decl -CHECK-NEXT: ext_in_class_initializer_non_constant -CHECK-NEXT: ext_integer_complement_complex -CHECK-NEXT: ext_integer_complex -CHECK-NEXT: ext_integer_increment_complex -CHECK-NEXT: ext_invalid_sign_spec -CHECK-NEXT: ext_missing_declspec -CHECK-NEXT: ext_missing_whitespace_after_macro_name -CHECK-NEXT: ext_new_paren_array_nonconst -CHECK-NEXT: ext_nonstandard_escape -CHECK-NEXT: ext_param_not_declared -CHECK-NEXT: ext_plain_complex -CHECK-NEXT: ext_pp_bad_vaargs_use -CHECK-NEXT: ext_pp_comma_expr -CHECK-NEXT: ext_pp_ident_directive -CHECK-NEXT: ext_pp_include_next_directive -CHECK-NEXT: ext_pp_line_too_big -CHECK-NEXT: ext_pp_macro_redef -CHECK-NEXT: ext_pp_warning_directive -CHECK-NEXT: ext_return_has_void_expr -CHECK-NEXT: ext_subscript_non_lvalue -CHECK-NEXT: ext_template_arg_extra_parens -CHECK-NEXT: ext_thread_before -CHECK-NEXT: ext_typecheck_addrof_void -CHECK-NEXT: ext_typecheck_cast_nonscalar -CHECK-NEXT: ext_typecheck_cast_to_union -CHECK-NEXT: ext_typecheck_comparison_of_distinct_pointers -CHECK-NEXT: ext_typecheck_comparison_of_distinct_pointers_nonstandard -CHECK-NEXT: ext_typecheck_comparison_of_fptr_to_void -CHECK-NEXT: ext_typecheck_comparison_of_pointer_integer -CHECK-NEXT: ext_typecheck_cond_incompatible_operands -CHECK-NEXT: ext_typecheck_cond_incompatible_operands_nonstandard -CHECK-NEXT: ext_typecheck_cond_one_void -CHECK-NEXT: ext_typecheck_convert_pointer_void_func -CHECK-NEXT: ext_typecheck_ordered_comparison_of_function_pointers -CHECK-NEXT: ext_typecheck_ordered_comparison_of_pointer_and_zero -CHECK-NEXT: ext_typecheck_ordered_comparison_of_pointer_integer -CHECK-NEXT: ext_typecheck_zero_array_size -CHECK-NEXT: ext_unknown_escape -CHECK-NEXT: ext_using_undefined_std -CHECK-NEXT: ext_vla_folded_to_constant +CHECK: Warnings without flags (158): CHECK-NEXT: pp_include_next_absolute_path CHECK-NEXT: pp_include_next_in_primary CHECK-NEXT: pp_invalid_string_literal @@ -138,9 +79,6 @@ CHECK-NEXT: warn_enum_too_large CHECK-NEXT: warn_enum_value_overflow CHECK-NEXT: warn_enumerator_too_large CHECK-NEXT: warn_exception_caught_by_earlier_handler -CHECK-NEXT: warn_excess_initializers -CHECK-NEXT: warn_excess_initializers_in_char_array_initializer -CHECK-NEXT: warn_expected_qualified_after_typename CHECK-NEXT: warn_extraneous_char_constant CHECK-NEXT: warn_fe_cc_log_diagnostics_failure CHECK-NEXT: warn_fe_cc_print_header_failure @@ -149,23 +87,17 @@ CHECK-NEXT: warn_file_asm_volatile CHECK-NEXT: warn_function_attribute_wrong_type CHECK-NEXT: warn_gc_attribute_weak_on_local CHECK-NEXT: warn_gnu_inline_attribute_requires_inline -CHECK-NEXT: warn_hex_escape_too_large CHECK-NEXT: warn_ignoring_ftabstop_value -CHECK-NEXT: warn_illegal_constant_array_size CHECK-NEXT: warn_implements_nscopying CHECK-NEXT: warn_incompatible_qualified_id -CHECK-NEXT: warn_initializer_string_for_char_array_too_long CHECK-NEXT: warn_inline_namespace_reopened_noninline CHECK-NEXT: warn_integer_too_large CHECK-NEXT: warn_integer_too_large_for_signed CHECK-NEXT: warn_invalid_asm_cast_lvalue -CHECK-NEXT: warn_many_braces_around_scalar_init CHECK-NEXT: warn_maynot_respond CHECK-NEXT: warn_member_extra_qualification CHECK-NEXT: warn_method_param_redefinition -CHECK-NEXT: warn_mismatched_exception_spec CHECK-NEXT: warn_missing_case_for_condition -CHECK-NEXT: warn_missing_dependent_template_keyword CHECK-NEXT: warn_missing_exception_specification CHECK-NEXT: warn_missing_whitespace_after_macro_name CHECK-NEXT: warn_multiple_method_decl @@ -177,10 +109,8 @@ CHECK-NEXT: warn_ns_attribute_wrong_return_type CHECK-NEXT: warn_objc_object_attribute_wrong_type CHECK-NEXT: warn_objc_property_copy_missing_on_block CHECK-NEXT: warn_objc_protocol_qualifier_missing_id -CHECK-NEXT: warn_octal_escape_too_large CHECK-NEXT: warn_odr_tag_type_inconsistent CHECK-NEXT: warn_on_superclass_use -CHECK-NEXT: warn_param_default_argument_redefinition CHECK-NEXT: warn_partial_specs_not_deducible CHECK-NEXT: warn_pointer_attribute_wrong_type CHECK-NEXT: warn_pp_convert_lhs_to_positive @@ -228,7 +158,6 @@ CHECK-NEXT: warn_second_parameter_of_va_start_not_last_named_argument CHECK-NEXT: warn_second_parameter_to_va_arg_never_compatible CHECK-NEXT: warn_standalone_specifier CHECK-NEXT: warn_static_inline_explicit_inst_ignored -CHECK-NEXT: warn_static_non_static CHECK-NEXT: warn_template_export_unsupported CHECK-NEXT: warn_template_spec_extra_headers CHECK-NEXT: warn_tentative_incomplete_array @@ -247,3 +176,4 @@ CHECK-NEXT: warn_unknown_method_family CHECK-NEXT: warn_use_out_of_scope_declaration CHECK-NEXT: warn_weak_identifier_undeclared CHECK-NEXT: warn_weak_import + diff --git a/tools/libclang/CXStoredDiagnostic.cpp b/tools/libclang/CXStoredDiagnostic.cpp index 8284dc9618..fa331de832 100644 --- a/tools/libclang/CXStoredDiagnostic.cpp +++ b/tools/libclang/CXStoredDiagnostic.cpp @@ -66,13 +66,8 @@ CXString CXStoredDiagnostic::getDiagnosticOption(CXString *Disable) const { *Disable = createCXString("-ferror-limit=0"); return createCXString("-ferror-limit="); } - - bool EnabledByDefault; - if (DiagnosticIDs::isBuiltinExtensionDiag(ID, EnabledByDefault) && - !EnabledByDefault) - return createCXString("-pedantic"); - return createCXString(""); + return createCXString(""); } unsigned CXStoredDiagnostic::getCategory() const { diff --git a/utils/TableGen/ClangDiagnosticsEmitter.cpp b/utils/TableGen/ClangDiagnosticsEmitter.cpp index 2df7ca97ce..0e3527f7c9 100644 --- a/utils/TableGen/ClangDiagnosticsEmitter.cpp +++ b/utils/TableGen/ClangDiagnosticsEmitter.cpp @@ -11,9 +11,11 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/Optional.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/TableGen/Record.h" @@ -78,7 +80,7 @@ static std::string getDiagnosticCategory(const Record *R, DiagGroupParents); if (!CatName.empty()) return CatName; } - + // If the diagnostic itself has a category, get it. return R->getValueAsString("CategoryName"); } @@ -160,6 +162,180 @@ static void groupDiagnostics(const std::vector<Record*> &Diags, } //===----------------------------------------------------------------------===// +// Infer members of -Wpedantic. +//===----------------------------------------------------------------------===// + +typedef std::vector<const Record *> RecordVec; +typedef llvm::DenseSet<const Record *> RecordSet; +typedef llvm::PointerUnion<RecordVec*, RecordSet*> VecOrSet; + +namespace { +class InferPedantic { + typedef llvm::DenseMap<const Record*, + std::pair<unsigned, llvm::Optional<unsigned> > > GMap; + + DiagGroupParentMap &DiagGroupParents; + const std::vector<Record*> &Diags; + const std::vector<Record*> DiagGroups; + std::map<std::string, GroupInfo> &DiagsInGroup; + llvm::DenseSet<const Record*> DiagsSet; + GMap GroupCount; +public: + InferPedantic(DiagGroupParentMap &DiagGroupParents, + const std::vector<Record*> &Diags, + const std::vector<Record*> &DiagGroups, + std::map<std::string, GroupInfo> &DiagsInGroup) + : DiagGroupParents(DiagGroupParents), + Diags(Diags), + DiagGroups(DiagGroups), + DiagsInGroup(DiagsInGroup) {} + + /// Compute the set of diagnostics and groups that are immediately + /// in -Wpedantic. + void compute(VecOrSet DiagsInPedantic, + VecOrSet GroupsInPedantic); + +private: + /// Determine whether a group is a subgroup of another group. + bool isSubGroupOfGroup(const Record *Group, + llvm::StringRef RootGroupName); + + /// Determine if the diagnostic is an extension. + bool isExtension(const Record *Diag); + + /// Increment the count for a group, and transitively marked + /// parent groups when appropriate. + void markGroup(const Record *Group); + + /// Return true if the diagnostic is in a pedantic group. + bool groupInPedantic(const Record *Group, bool increment = false); +}; +} // end anonymous namespace + +bool InferPedantic::isSubGroupOfGroup(const Record *Group, + llvm::StringRef GName) { + + const std::string &GroupName = Group->getValueAsString("GroupName"); + if (GName == GroupName) + return true; + + const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); + for (unsigned i = 0, e = Parents.size(); i != e; ++i) + if (isSubGroupOfGroup(Parents[i], GName)) + return true; + + return false; +} + +/// Determine if the diagnostic is an extension. +bool InferPedantic::isExtension(const Record *Diag) { + const std::string &ClsName = Diag->getValueAsDef("Class")->getName(); + return ClsName == "CLASS_EXTENSION"; +} + +bool InferPedantic::groupInPedantic(const Record *Group, bool increment) { + GMap::mapped_type &V = GroupCount[Group]; + // Lazily compute the threshold value for the group count. + if (!V.second.hasValue()) { + const GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")]; + V.second = GI.SubGroups.size() + GI.DiagsInGroup.size(); + } + + if (increment) + ++V.first; + + // Consider a group in -Wpendatic IFF if has at least one diagnostic + // or subgroup AND all of those diagnostics and subgroups are covered + // by -Wpedantic via our computation. + return V.first != 0 && V.first == V.second.getValue(); +} + +void InferPedantic::markGroup(const Record *Group) { + // If all the diagnostics and subgroups have been marked as being + // covered by -Wpedantic, increment the count of parent groups. Once the + // group's count is equal to the number of subgroups and diagnostics in + // that group, we can safely add this group to -Wpedantic. + if (groupInPedantic(Group, /* increment */ true)) { + const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); + for (unsigned i = 0, e = Parents.size(); i != e; ++i) + markGroup(Parents[i]); + } +} + +void InferPedantic::compute(VecOrSet DiagsInPedantic, + VecOrSet GroupsInPedantic) { + // All extensions are implicitly in the "pedantic" group. For those that + // aren't explicitly included in -Wpedantic, mark them for consideration + // to be included in -Wpedantic directly. + for (unsigned i = 0, e = Diags.size(); i != e; ++i) { + Record *R = Diags[i]; + if (isExtension(R)) { + DiagsSet.insert(R); + if (DefInit *Group = dynamic_cast<DefInit*>(R->getValueInit("Group"))) { + const Record *GroupRec = Group->getDef(); + if (!isSubGroupOfGroup(GroupRec, "pedantic")) { + markGroup(GroupRec); + } + } + } + } + + // Compute the set of diagnostics that are directly in -Wpedantic. We + // march through Diags a second time to ensure the results are emitted + // in deterministic order. + for (unsigned i = 0, e = Diags.size(); i != e; ++i) { + Record *R = Diags[i]; + if (!DiagsSet.count(R)) + continue; + // Check if the group is implicitly in -Wpedantic. If so, + // the diagnostic should not be directly included in the -Wpedantic + // diagnostic group. + if (DefInit *Group = dynamic_cast<DefInit*>(R->getValueInit("Group"))) + if (groupInPedantic(Group->getDef())) + continue; + + // The diagnostic is not included in a group that is (transitively) in + // -Wpedantic. Include it in -Wpedantic directly. + if (RecordVec *V = DiagsInPedantic.dyn_cast<RecordVec*>()) + V->push_back(R); + else { + DiagsInPedantic.get<RecordSet*>()->insert(R); + } + } + + if (!GroupsInPedantic) + return; + + // Compute the set of groups that are directly in -Wpedantic. We + // march through the groups to ensure the results are emitted + /// in a deterministc order. + for (unsigned i = 0, ei = DiagGroups.size(); i != ei; ++i) { + Record *Group = DiagGroups[i]; + if (!groupInPedantic(Group)) + continue; + + unsigned ParentsInPedantic = 0; + const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); + for (unsigned j = 0, ej = Parents.size(); j != ej; ++j) { + if (groupInPedantic(Parents[j])) + ++ParentsInPedantic; + } + // If all the parents are in -Wpedantic, this means that this diagnostic + // group will be indirectly included by -Wpedantic already. In that + // case, do not add it directly to -Wpedantic. If the group has no + // parents, obviously it should go into -Wpedantic. + if (Parents.size() > 0 && ParentsInPedantic == Parents.size()) + continue; + + if (RecordVec *V = GroupsInPedantic.dyn_cast<RecordVec*>()) + V->push_back(Group); + else { + GroupsInPedantic.get<RecordSet*>()->insert(Group); + } + } +} + +//===----------------------------------------------------------------------===// // Warning Tables (.inc file) generation. //===----------------------------------------------------------------------===// @@ -190,6 +366,11 @@ void EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS, DiagCategoryIDMap CategoryIDs(Records); DiagGroupParentMap DGParentMap(Records); + // Compute the set of diagnostics that are in -Wpedantic. + RecordSet DiagsInPedantic; + InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup); + inferPedantic.compute(&DiagsInPedantic, (RecordVec*)0); + for (unsigned i = 0, e = Diags.size(); i != e; ++i) { const Record &R = *Diags[i]; // Filter by component. @@ -211,6 +392,11 @@ void EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS, DiagsInGroup.find(DI->getDef()->getValueAsString("GroupName")); assert(I != DiagsInGroup.end()); OS << ", " << I->second.IDNo; + } else if (DiagsInPedantic.count(&R)) { + std::map<std::string, GroupInfo>::iterator I = + DiagsInGroup.find("pedantic"); + assert(I != DiagsInGroup.end() && "pedantic group not defined"); + OS << ", " << I->second.IDNo; } else { OS << ", 0"; } @@ -262,12 +448,12 @@ static std::string getDiagCategoryEnum(llvm::StringRef name) { enumName += isalnum(*I) ? *I : '_'; return enumName.str(); } - + namespace clang { void EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) { // Compute a mapping from a DiagGroup to all of its parents. DiagGroupParentMap DGParentMap(Records); - + std::vector<Record*> Diags = Records.getAllDerivedDefinitions("Diagnostic"); @@ -276,7 +462,15 @@ void EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) { std::map<std::string, GroupInfo> DiagsInGroup; groupDiagnostics(Diags, DiagGroups, DiagsInGroup); - + + // All extensions are implicitly in the "pedantic" group. Record the + // implicit set of groups in the "pedantic" group, and use this information + // later when emitting the group information for Pedantic. + RecordVec DiagsInPedantic; + RecordVec GroupsInPedantic; + InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup); + inferPedantic.compute(&DiagsInPedantic, &GroupsInPedantic); + // Walk through the groups emitting an array for each diagnostic of the diags // that are mapped to. OS << "\n#ifdef GET_DIAG_ARRAYS\n"; @@ -284,17 +478,23 @@ void EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) { for (std::map<std::string, GroupInfo>::iterator I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) { MaxLen = std::max(MaxLen, (unsigned)I->first.size()); - + const bool IsPedantic = I->first == "pedantic"; + std::vector<const Record*> &V = I->second.DiagsInGroup; - if (!V.empty()) { + if (!V.empty() || (IsPedantic && !DiagsInPedantic.empty())) { OS << "static const short DiagArray" << I->second.IDNo << "[] = { "; for (unsigned i = 0, e = V.size(); i != e; ++i) OS << "diag::" << V[i]->getName() << ", "; + // Emit the diagnostics implicitly in "pedantic". + if (IsPedantic) { + for (unsigned i = 0, e = DiagsInPedantic.size(); i != e; ++i) + OS << "diag::" << DiagsInPedantic[i]->getName() << ", "; + } OS << "-1 };\n"; } const std::vector<std::string> &SubGroups = I->second.SubGroups; - if (!SubGroups.empty()) { + if (!SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty())) { OS << "static const short DiagSubGroup" << I->second.IDNo << "[] = { "; for (unsigned i = 0, e = SubGroups.size(); i != e; ++i) { std::map<std::string, GroupInfo>::iterator RI = @@ -302,6 +502,18 @@ void EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) { assert(RI != DiagsInGroup.end() && "Referenced without existing?"); OS << RI->second.IDNo << ", "; } + // Emit the groups implicitly in "pedantic". + if (IsPedantic) { + for (unsigned i = 0, e = GroupsInPedantic.size(); i != e; ++i) { + const std::string &GroupName = + GroupsInPedantic[i]->getValueAsString("GroupName"); + std::map<std::string, GroupInfo>::iterator RI = + DiagsInGroup.find(GroupName); + assert(RI != DiagsInGroup.end() && "Referenced without existing?"); + OS << RI->second.IDNo << ", "; + } + } + OS << "-1 };\n"; } } @@ -321,15 +533,22 @@ void EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) { throw "Invalid character in diagnostic group '" + I->first + "'"; OS.write_escaped(I->first) << "\"," << std::string(MaxLen-I->first.size()+1, ' '); - + + // Special handling for 'pedantic'. + const bool IsPedantic = I->first == "pedantic"; + // Diagnostics in the group. - if (I->second.DiagsInGroup.empty()) + const bool hasDiags = !I->second.DiagsInGroup.empty() || + (IsPedantic && !DiagsInPedantic.empty()); + if (!hasDiags) OS << "0, "; else OS << "DiagArray" << I->second.IDNo << ", "; // Subgroups. - if (I->second.SubGroups.empty()) + const bool hasSubGroups = !I->second.SubGroups.empty() || + (IsPedantic && !GroupsInPedantic.empty()); + if (!hasSubGroups) OS << 0; else OS << "DiagSubGroup" << I->second.IDNo; |