Index: include/clang/Basic/Diagnostic.td =================================================================== --- include/clang/Basic/Diagnostic.td +++ include/clang/Basic/Diagnostic.td @@ -39,6 +39,15 @@ def SFINAE_Report : SFINAEResponse; def SFINAE_AccessControl : SFINAEResponse; +// Textual substitutions which may be performed on the text of diagnostics +class TextSubstitution { + string Substitution = Text; + // FIXME: These are only here to allow substitutions to be declared with + // diagnostics + string Component = ""; + string CategoryName = ""; +} + // Diagnostic Categories. These can be applied to groups or individual // diagnostics to specify a category. class DiagCategory { Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -3613,8 +3613,7 @@ def note_ovl_candidate_non_deduced_mismatch_qualified : Note< "candidate template ignored: could not match %q0 against %q1">; -// Note that we don't treat templates differently for this diagnostic. -def note_ovl_candidate_arity : Note<"candidate " +def select_ovl_candidate_kind : TextSubstitution< "%select{function|function|constructor|function|function|constructor|" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" @@ -3622,32 +3621,31 @@ "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" "inherited constructor|" - "inherited constructor}0 %select{|template }1" - "not viable: requires%select{ at least| at most|}2 %3 argument%s3, but %4 " - "%plural{1:was|:were}4 provided">; - -def note_ovl_candidate_arity_one : Note<"candidate " - "%select{function|function|constructor|function|function|constructor|" + "inherited constructor}">; +def select_ovl_template_kind : TextSubstitution< + "%select{function|function|constructor|" + "function |function |constructor |" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" "inherited constructor|" - "inherited constructor}0 %select{|template }1not viable: " + "inherited constructor }">; + +// Note that we don't treat templates differently for this diagnostic. +def note_ovl_candidate_arity : Note<"candidate " + "%sub{select_ovl_candidate_kind}0 %select{|template }1" + "not viable: requires%select{ at least| at most|}2 %3 argument%s3, but %4 " + "%plural{1:was|:were}4 provided">; + +def note_ovl_candidate_arity_one : Note<"candidate " + "%sub{select_ovl_candidate_kind}0 %select{|template }1not viable: " "%select{requires at least|allows at most single|requires single}2 " "argument %3, but %plural{0:no|:%4}4 arguments were provided">; def note_ovl_candidate_deleted : Note< - "candidate %select{function|function|constructor|" - "function |function |constructor |" - "constructor (the implicit default constructor)|" - "constructor (the implicit copy constructor)|" - "constructor (the implicit move constructor)|" - "function (the implicit copy assignment operator)|" - "function (the implicit move assignment operator)|" - "inherited constructor|" - "inherited constructor }0%1 has been " + "candidate %sub{select_ovl_template_kind}0%1 has been " "%select{explicitly made unavailable|explicitly deleted|" "implicitly deleted}2">; @@ -3657,15 +3655,7 @@ // to complete the type, which doesn't involve changes to the call line // anyway. If people complain, we can change it. def note_ovl_candidate_bad_conv_incomplete : Note<"candidate " - "%select{function|function|constructor|" - "function |function |constructor |" - "constructor (the implicit default constructor)|" - "constructor (the implicit copy constructor)|" - "constructor (the implicit move constructor)|" - "function (the implicit copy assignment operator)|" - "function (the implicit move assignment operator)|" - "inherited constructor|" - "inherited constructor }0%1 " + "%sub{select_ovl_template_kind}0%1 " "not viable: cannot convert argument of incomplete type " "%diff{$ to $|to parameter type}2,3 for " "%select{%ordinal5 argument|object argument}4" @@ -3674,37 +3664,13 @@ "; remove *|" "; remove &}6">; def note_ovl_candidate_bad_list_argument : Note<"candidate " - "%select{function|function|constructor|" - "function |function |constructor |" - "constructor (the implicit default constructor)|" - "constructor (the implicit copy constructor)|" - "constructor (the implicit move constructor)|" - "function (the implicit copy assignment operator)|" - "function (the implicit move assignment operator)|" - "inherited constructor|" - "inherited constructor }0%1 " + "%sub{select_ovl_template_kind}0%1 " "not viable: cannot convert initializer list argument to %3">; def note_ovl_candidate_bad_overload : Note<"candidate " - "%select{function|function|constructor|" - "function |function |constructor |" - "constructor (the implicit default constructor)|" - "constructor (the implicit copy constructor)|" - "constructor (the implicit move constructor)|" - "function (the implicit copy assignment operator)|" - "function (the implicit move assignment operator)|" - "inherited constructor|" - "inherited constructor }0%1" + "%sub{select_ovl_template_kind}0%1" " not viable: no overload of %3 matching %2 for %ordinal4 argument">; def note_ovl_candidate_bad_conv : Note<"candidate " - "%select{function|function|constructor|" - "function |function |constructor |" - "constructor (the implicit default constructor)|" - "constructor (the implicit copy constructor)|" - "constructor (the implicit move constructor)|" - "function (the implicit copy assignment operator)|" - "function (the implicit move assignment operator)|" - "inherited constructor|" - "inherited constructor }0%1" + "%sub{select_ovl_template_kind}0%1" " not viable: no known conversion " "%diff{from $ to $|from argument type to parameter type}2,3 for " "%select{%ordinal5 argument|object argument}4" @@ -3713,64 +3679,24 @@ "; remove *|" "; remove &}6">; def note_ovl_candidate_bad_arc_conv : Note<"candidate " - "%select{function|function|constructor|" - "function |function |constructor |" - "constructor (the implicit default constructor)|" - "constructor (the implicit copy constructor)|" - "constructor (the implicit move constructor)|" - "function (the implicit copy assignment operator)|" - "function (the implicit move assignment operator)|" - "inherited constructor|" - "inherited constructor }0%1" + "%sub{select_ovl_template_kind}0%1" " not viable: cannot implicitly convert argument " "%diff{of type $ to $|type to parameter type}2,3 for " "%select{%ordinal5 argument|object argument}4 under ARC">; def note_ovl_candidate_bad_lvalue : Note<"candidate " - "%select{function|function|constructor|" - "function |function |constructor |" - "constructor (the implicit default constructor)|" - "constructor (the implicit copy constructor)|" - "constructor (the implicit move constructor)|" - "function (the implicit copy assignment operator)|" - "function (the implicit move assignment operator)|" - "inherited constructor|" - "inherited constructor }0%1" + "%sub{select_ovl_template_kind}0%1" " not viable: expects an l-value for " "%select{%ordinal3 argument|object argument}2">; def note_ovl_candidate_bad_addrspace : Note<"candidate " - "%select{function|function|constructor|" - "function |function |constructor |" - "constructor (the implicit default constructor)|" - "constructor (the implicit copy constructor)|" - "constructor (the implicit move constructor)|" - "function (the implicit copy assignment operator)|" - "function (the implicit move assignment operator)|" - "inherited constructor|" - "inherited constructor }0%1 not viable: " + "%sub{select_ovl_template_kind}0%1 not viable: " "%select{%ordinal6|'this'}5 argument (%2) is in " "address space %3, but parameter must be in address space %4">; def note_ovl_candidate_bad_gc : Note<"candidate " - "%select{function|function|constructor|" - "function |function |constructor |" - "constructor (the implicit default constructor)|" - "constructor (the implicit copy constructor)|" - "constructor (the implicit move constructor)|" - "function (the implicit copy assignment operator)|" - "function (the implicit move assignment operator)|" - "inherited constructor|" - "inherited constructor }0%1 not viable: " + "%sub{select_ovl_template_kind}0%1 not viable: " "%select{%ordinal6|'this'}5 argument (%2) has %select{no|__weak|__strong}3 " "ownership, but parameter has %select{no|__weak|__strong}4 ownership">; def note_ovl_candidate_bad_ownership : Note<"candidate " - "%select{function|function|constructor|" - "function |function |constructor |" - "constructor (the implicit default constructor)|" - "constructor (the implicit copy constructor)|" - "constructor (the implicit move constructor)|" - "function (the implicit copy assignment operator)|" - "function (the implicit move assignment operator)|" - "inherited constructor|" - "inherited constructor }0%1 not viable: " + "%sub{select_ovl_template_kind}0%1 not viable: " "%select{%ordinal6|'this'}5 argument (%2) has " "%select{no|__unsafe_unretained|__strong|__weak|__autoreleasing}3 ownership," " but parameter has %select{no|__unsafe_unretained|__strong|__weak|" @@ -3783,54 +3709,22 @@ "%select{const|restrict|const or restrict|volatile|const or volatile|" "volatile or restrict|const, volatile, or restrict}3">; def note_ovl_candidate_bad_cvr : Note<"candidate " - "%select{function|function|constructor|" - "function |function |constructor |" - "constructor (the implicit default constructor)|" - "constructor (the implicit copy constructor)|" - "constructor (the implicit move constructor)|" - "function (the implicit copy assignment operator)|" - "function (the implicit move assignment operator)|" - "inherited constructor|" - "inherited constructor }0%1 not viable: " + "%sub{select_ovl_template_kind}0%1 not viable: " "%ordinal4 argument (%2) would lose " "%select{const|restrict|const and restrict|volatile|const and volatile|" "volatile and restrict|const, volatile, and restrict}3 qualifier" "%select{||s||s|s|s}3">; def note_ovl_candidate_bad_unaligned : Note<"candidate " - "%select{function|function|constructor|" - "function |function |constructor |" - "constructor (the implicit default constructor)|" - "constructor (the implicit copy constructor)|" - "constructor (the implicit move constructor)|" - "function (the implicit copy assignment operator)|" - "function (the implicit move assignment operator)|" - "inherited constructor|" - "inherited constructor }0%1 not viable: " + "%sub{select_ovl_template_kind}0%1 not viable: " "%ordinal4 argument (%2) would lose __unaligned qualifier">; def note_ovl_candidate_bad_base_to_derived_conv : Note<"candidate " - "%select{function|function|constructor|" - "function |function |constructor |" - "constructor (the implicit default constructor)|" - "constructor (the implicit copy constructor)|" - "constructor (the implicit move constructor)|" - "function (the implicit copy assignment operator)|" - "function (the implicit move assignment operator)|" - "inherited constructor|" - "inherited constructor }0%1 not viable: " + "%sub{select_ovl_template_kind}0%1 not viable: " "cannot %select{convert from|convert from|bind}2 " "%select{base class pointer|superclass|base class object of type}2 %3 to " "%select{derived class pointer|subclass|derived class reference}2 %4 for " "%ordinal5 argument">; def note_ovl_candidate_bad_target : Note< - "candidate %select{function|function|constructor|" - "function|function|constructor|" - "constructor (the implicit default constructor)|" - "constructor (the implicit copy constructor)|" - "constructor (the implicit move constructor)|" - "function (the implicit copy assignment operator)|" - "function (the implicit move assignment operator)|" - "inherited constructor|" - "inherited constructor}0 not viable: " + "candidate %sub{select_ovl_candidate_kind}0 not viable: " "call to " "%select{__device__|__global__|__host__|__host__ __device__|invalid}1 function from" " %select{__device__|__global__|__host__|__host__ __device__|invalid}2 function">; @@ -7749,6 +7643,10 @@ "explicit conversion functions are incompatible with C++98">, InGroup, DefaultIgnore; +def select_special_member : TextSubstitution< + "%select{default constructor|copy constructor|move constructor|" + "copy assignment operator|move assignment operator|destructor}">; + // C++11 defaulted functions def err_defaulted_special_member_params : Error< "an explicitly-defaulted %select{|copy |move }0constructor cannot " @@ -7763,9 +7661,8 @@ "an explicitly-defaulted %select{copy|move}0 assignment operator may not " "have 'const'%select{, 'constexpr'|}1 or 'volatile' qualifiers">; def err_defaulted_special_member_volatile_param : Error< - "the parameter for an explicitly-defaulted %select{<>|" - "copy constructor|move constructor|copy assignment operator|" - "move assignment operator|<>}0 may not be volatile">; + "the parameter for an explicitly-defaulted %sub{select_special_member}0 " + "may not be volatile">; def err_defaulted_special_member_move_const_param : Error< "the parameter for an explicitly-defaulted move " "%select{constructor|assignment operator}0 may not be const">; @@ -7777,17 +7674,13 @@ "the parameter for an explicitly-defaulted copy assignment operator must be an " "lvalue reference type">; def err_incorrect_defaulted_exception_spec : Error< - "exception specification of explicitly defaulted %select{default constructor|" - "copy constructor|move constructor|copy assignment operator|move assignment " - "operator|destructor}0 does not match the " - "calculated one">; + "exception specification of explicitly defaulted %sub{select_special_member}0 " + "does not match the calculated one">; def err_incorrect_defaulted_constexpr : Error< - "defaulted definition of %select{default constructor|copy constructor|" - "move constructor|copy assignment operator|move assignment operator}0 " + "defaulted definition of %sub{select_special_member}0 " "is not constexpr">; def err_out_of_line_default_deletes : Error< - "defaulting this %select{default constructor|copy constructor|move " - "constructor|copy assignment operator|move assignment operator|destructor}0 " + "defaulting this %sub{select_special_member}0 " "would delete it after its first declaration">; def warn_vbase_moved_multiple_times : Warning< "defaulted move assignment operator of %0 will move assign virtual base " Index: utils/TableGen/ClangDiagnosticsEmitter.cpp =================================================================== --- utils/TableGen/ClangDiagnosticsEmitter.cpp +++ utils/TableGen/ClangDiagnosticsEmitter.cpp @@ -14,12 +14,13 @@ #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Twine.h" +#include "llvm/Support/Regex.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/StringToOffsetTable.h" @@ -455,6 +456,39 @@ return ClsName == "CLASS_REMARK"; } +static void substituteDiagText(Record *Diag, StringMap SubsMap) { + llvm::Regex RE("%sub{[^}]*}"); + std::string Error; + ((void)Error); + assert(RE.isValid(Error) && RE.getNumMatches() == 0); + + RecordVal *RV = Diag->getValue("Text"); + std::string Text = RV->getValue()->getAsString(); + + unsigned Count = 0; + SmallVector Matches; + while (RE.match(Text, &Matches)) { + ++Count; + assert(Matches.size() == 1); + StringRef M = Matches[0]; + std::pair Range(M.data() - Text.data(), M.size()); + + assert(Text.size() > Range.first + Range.second); + StringRef Found(Text); + + Found = Found.substr(Range.first, Range.second); + StringRef FoundName = Found.substr(5, Found.size() - 6); + Record *S = SubsMap.lookup(FoundName); + if (!S) { + PrintFatalError(Diag->getLoc(), "Diag " + Diag->getName() + + " has no substitution for: " + Found); + } + Text.replace(Range.first, Range.second, + S->getValueAsString("Substitution")); + } + RV->setValue(StringInit::get(Text)); +} + /// ClangDiagsDefsEmitter - The top-level class emits .def files containing /// declarations of Clang diagnostics. namespace clang { @@ -470,8 +504,14 @@ OS << "#endif\n\n"; } - const std::vector &Diags = - Records.getAllDerivedDefinitions("Diagnostic"); + std::vector Substitutions = + Records.getAllDerivedDefinitions("TextSubstitution"); + StringMap SubsMap; + for (auto *R : Substitutions) + SubsMap.try_emplace(R->getName(), R); + + std::vector Diags = Records.getAllDerivedDefinitions("Diagnostic"); + llvm::for_each(Diags, [&](Record *R) { substituteDiagText(R, SubsMap); }); std::vector DiagGroups = Records.getAllDerivedDefinitions("DiagGroup"); @@ -953,6 +993,9 @@ StringRef Modifier = Text.slice(0, ModLength); Text = Text.slice(ModLength, StringRef::npos); + assert(Modifier != "sub" && + "substitutions should have already taken place!"); + // FIXME: Handle %ordinal here. if (Modifier == "select" || Modifier == "plural") { DiagText::SelectPiece Select; @@ -1208,9 +1251,16 @@ } OS << Documentation->getValueAsString("Intro") << "\n"; + std::vector Substitutions = + Records.getAllDerivedDefinitions("TextSubstitution"); + StringMap SubsMap; + for (Record *R : Substitutions) + SubsMap.try_emplace(R->getName(), R); std::vector Diags = Records.getAllDerivedDefinitions("Diagnostic"); + llvm::for_each(Diags, [&](Record *R) { substituteDiagText(R, SubsMap); }); + std::vector DiagGroups = Records.getAllDerivedDefinitions("DiagGroup"); llvm::sort(DiagGroups.begin(), DiagGroups.end(), diagGroupBeforeByName); @@ -1300,6 +1350,7 @@ Severity[0] = tolower(Severity[0]); if (Severity == "ignored") Severity = IsRemarkGroup ? "remark" : "warning"; + writeDiagnosticText(Severity, D->getValueAsString("Text"), OS); } }