diff options
Diffstat (limited to 'contrib/llvm-project/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp')
-rw-r--r-- | contrib/llvm-project/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp | 300 |
1 files changed, 169 insertions, 131 deletions
diff --git a/contrib/llvm-project/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp b/contrib/llvm-project/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp index 430895d8425f..480c7c83f5f8 100644 --- a/contrib/llvm-project/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp +++ b/contrib/llvm-project/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp @@ -12,7 +12,6 @@ #include "TableGenBackends.h" #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" @@ -30,6 +29,7 @@ #include <cctype> #include <functional> #include <map> +#include <optional> #include <set> using namespace llvm; @@ -129,13 +129,14 @@ namespace { }; struct GroupInfo { + llvm::StringRef GroupName; std::vector<const Record*> DiagsInGroup; std::vector<std::string> SubGroups; - unsigned IDNo; + unsigned IDNo = 0; - const Record *ExplicitDef; + llvm::SmallVector<const Record *, 1> Defs; - GroupInfo() : IDNo(0), ExplicitDef(nullptr) {} + GroupInfo() = default; }; } // end anonymous namespace. @@ -150,12 +151,6 @@ static bool diagGroupBeforeByName(const Record *LHS, const Record *RHS) { RHS->getValueAsString("GroupName"); } -static bool beforeThanCompareGroups(const GroupInfo *LHS, const GroupInfo *RHS){ - assert(!LHS->DiagsInGroup.empty() && !RHS->DiagsInGroup.empty()); - return beforeThanCompare(LHS->DiagsInGroup.front(), - RHS->DiagsInGroup.front()); -} - /// Invert the 1-[0/1] mapping of diags to group into a one to many /// mapping of groups to diags in the group. static void groupDiagnostics(const std::vector<Record*> &Diags, @@ -174,24 +169,14 @@ static void groupDiagnostics(const std::vector<Record*> &Diags, DiagsInGroup[GroupName].DiagsInGroup.push_back(R); } - typedef SmallPtrSet<GroupInfo *, 16> GroupSetTy; - GroupSetTy ImplicitGroups; - // Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty // groups (these are warnings that GCC supports that clang never produces). for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) { Record *Group = DiagGroups[i]; GroupInfo &GI = DiagsInGroup[std::string(Group->getValueAsString("GroupName"))]; - if (Group->isAnonymous()) { - if (GI.DiagsInGroup.size() > 1) - ImplicitGroups.insert(&GI); - } else { - if (GI.ExplicitDef) - assert(GI.ExplicitDef == Group); - else - GI.ExplicitDef = Group; - } + GI.GroupName = Group->getName(); + GI.Defs.push_back(Group); std::vector<Record*> SubGroups = Group->getValueAsListOfDefs("SubGroups"); for (unsigned j = 0, e = SubGroups.size(); j != e; ++j) @@ -205,61 +190,51 @@ static void groupDiagnostics(const std::vector<Record*> &Diags, I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I, ++IDNo) I->second.IDNo = IDNo; - // Sort the implicit groups, so we can warn about them deterministically. - SmallVector<GroupInfo *, 16> SortedGroups(ImplicitGroups.begin(), - ImplicitGroups.end()); - for (SmallVectorImpl<GroupInfo *>::iterator I = SortedGroups.begin(), - E = SortedGroups.end(); - I != E; ++I) { - MutableArrayRef<const Record *> GroupDiags = (*I)->DiagsInGroup; - llvm::sort(GroupDiags, beforeThanCompare); - } - llvm::sort(SortedGroups, beforeThanCompareGroups); + // Warn if the same group is defined more than once (including implicitly). + for (auto &Group : DiagsInGroup) { + if (Group.second.Defs.size() == 1 && + (!Group.second.Defs.front()->isAnonymous() || + Group.second.DiagsInGroup.size() <= 1)) + continue; - // Warn about the same group being used anonymously in multiple places. - for (SmallVectorImpl<GroupInfo *>::const_iterator I = SortedGroups.begin(), - E = SortedGroups.end(); - I != E; ++I) { - ArrayRef<const Record *> GroupDiags = (*I)->DiagsInGroup; - - if ((*I)->ExplicitDef) { - std::string Name = - std::string((*I)->ExplicitDef->getValueAsString("GroupName")); - for (ArrayRef<const Record *>::const_iterator DI = GroupDiags.begin(), - DE = GroupDiags.end(); - DI != DE; ++DI) { - const DefInit *GroupInit = cast<DefInit>((*DI)->getValueInit("Group")); - const Record *NextDiagGroup = GroupInit->getDef(); - if (NextDiagGroup == (*I)->ExplicitDef) - continue; - - SrcMgr.PrintMessage((*DI)->getLoc().front(), - SourceMgr::DK_Error, - Twine("group '") + Name + - "' is referred to anonymously"); - SrcMgr.PrintMessage((*I)->ExplicitDef->getLoc().front(), - SourceMgr::DK_Note, "group defined here"); + bool First = true; + for (const Record *Def : Group.second.Defs) { + // Skip implicit definitions from diagnostics; we'll report those + // separately below. + bool IsImplicit = false; + for (const Record *Diag : Group.second.DiagsInGroup) { + if (cast<DefInit>(Diag->getValueInit("Group"))->getDef() == Def) { + IsImplicit = true; + break; + } } - } else { - // If there's no existing named group, we should just warn once and use - // notes to list all the other cases. - ArrayRef<const Record *>::const_iterator DI = GroupDiags.begin(), - DE = GroupDiags.end(); - assert(DI != DE && "We only care about groups with multiple uses!"); - - const DefInit *GroupInit = cast<DefInit>((*DI)->getValueInit("Group")); - const Record *NextDiagGroup = GroupInit->getDef(); - std::string Name = - std::string(NextDiagGroup->getValueAsString("GroupName")); - - SrcMgr.PrintMessage((*DI)->getLoc().front(), - SourceMgr::DK_Error, - Twine("group '") + Name + - "' is referred to anonymously"); - - for (++DI; DI != DE; ++DI) { - SrcMgr.PrintMessage((*DI)->getLoc().front(), - SourceMgr::DK_Note, "also referenced here"); + if (IsImplicit) + continue; + + llvm::SMLoc Loc = Def->getLoc().front(); + if (First) { + SrcMgr.PrintMessage(Loc, SourceMgr::DK_Error, + Twine("group '") + Group.first + + "' is defined more than once"); + First = false; + } else { + SrcMgr.PrintMessage(Loc, SourceMgr::DK_Note, "also defined here"); + } + } + + for (const Record *Diag : Group.second.DiagsInGroup) { + if (!cast<DefInit>(Diag->getValueInit("Group"))->getDef()->isAnonymous()) + continue; + + llvm::SMLoc Loc = Diag->getLoc().front(); + if (First) { + SrcMgr.PrintMessage(Loc, SourceMgr::DK_Error, + Twine("group '") + Group.first + + "' is implicitly defined more than once"); + First = false; + } else { + SrcMgr.PrintMessage(Loc, SourceMgr::DK_Note, + "also implicitly defined here"); } } } @@ -275,8 +250,9 @@ typedef llvm::PointerUnion<RecordVec*, RecordSet*> VecOrSet; namespace { class InferPedantic { - typedef llvm::DenseMap<const Record*, - std::pair<unsigned, Optional<unsigned> > > GMap; + typedef llvm::DenseMap<const Record *, + std::pair<unsigned, std::optional<unsigned>>> + GMap; DiagGroupParentMap &DiagGroupParents; const std::vector<Record*> &Diags; @@ -350,7 +326,7 @@ bool InferPedantic::isOffByDefault(const Record *Diag) { 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()) { + if (!V.second) { const GroupInfo &GI = DiagsInGroup[std::string(Group->getValueAsString("GroupName"))]; V.second = GI.SubGroups.size() + GI.DiagsInGroup.size(); @@ -362,7 +338,7 @@ bool InferPedantic::groupInPedantic(const Record *Group, bool increment) { // 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(); + return V.first != 0 && V.first == *V.second; } void InferPedantic::markGroup(const Record *Group) { @@ -429,17 +405,14 @@ void InferPedantic::compute(VecOrSet DiagsInPedantic, 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; - } + bool AllParentsInPedantic = + llvm::all_of(Parents, [&](Record *R) { return groupInPedantic(R); }); // 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()) + if (Parents.size() > 0 && AllParentsInPedantic) continue; if (RecordVec *V = GroupsInPedantic.dyn_cast<RecordVec*>()) @@ -584,7 +557,7 @@ struct PluralPiece : SelectPiece { struct DiffPiece : Piece { DiffPiece() : Piece(DiffPieceClass) {} - Piece *Options[2] = {}; + Piece *Parts[4] = {}; int Indexes[2] = {}; static bool classof(const Piece *P) { @@ -641,7 +614,7 @@ struct DiagnosticTextBuilder { return It->second.Root; } - LLVM_ATTRIBUTE_NORETURN void PrintFatalError(llvm::Twine const &Msg) const { + [[noreturn]] void PrintFatalError(llvm::Twine const &Msg) const { assert(EvaluatingRecord && "not evaluating a record?"); llvm::PrintFatalError(EvaluatingRecord->getLoc(), Msg); } @@ -660,9 +633,18 @@ private: } DiagText(DiagnosticTextBuilder &Builder, StringRef Text) - : Builder(Builder), Root(parseDiagText(Text)) {} - - Piece *parseDiagText(StringRef &Text, bool Nested = false); + : Builder(Builder), Root(parseDiagText(Text, StopAt::End)) {} + + enum class StopAt { + // Parse until the end of the string. + End, + // Additionally stop if we hit a non-nested '|' or '}'. + PipeOrCloseBrace, + // Additionally stop if we hit a non-nested '$'. + Dollar, + }; + + Piece *parseDiagText(StringRef &Text, StopAt Stop); int parseModifier(StringRef &) const; public: @@ -671,6 +653,14 @@ private: Root(O.Root) { O.Root = nullptr; } + // The move assignment operator is defined as deleted pending further + // motivation. + DiagText &operator=(DiagText &&) = delete; + + // The copy constrcutor and copy assignment operator is defined as deleted + // pending further motivation. + DiagText(const DiagText &) = delete; + DiagText &operator=(const DiagText &) = delete; ~DiagText() { for (Piece *P : AllocatedPieces) @@ -694,7 +684,7 @@ private: }; template <class Derived> struct DiagTextVisitor { - using ModifierMappingsType = Optional<std::vector<int>>; + using ModifierMappingsType = std::optional<std::vector<int>>; private: Derived &getDerived() { return static_cast<Derived &>(*this); } @@ -725,7 +715,7 @@ public: private: DiagTextVisitor &Visitor; - Optional<std::vector<int>> OldMappings; + std::optional<std::vector<int>> OldMappings; public: Piece *Substitution; @@ -928,7 +918,24 @@ struct DiagTextDocPrinter : DiagTextVisitor<DiagTextDocPrinter> { void VisitPlural(PluralPiece *P) { VisitSelect(P); } - void VisitDiff(DiffPiece *P) { Visit(P->Options[1]); } + void VisitDiff(DiffPiece *P) { + // Render %diff{a $ b $ c|d}e,f as %select{a %e b %f c|d}. + PlaceholderPiece E(MT_Placeholder, P->Indexes[0]); + PlaceholderPiece F(MT_Placeholder, P->Indexes[1]); + + MultiPiece FirstOption; + FirstOption.Pieces.push_back(P->Parts[0]); + FirstOption.Pieces.push_back(&E); + FirstOption.Pieces.push_back(P->Parts[1]); + FirstOption.Pieces.push_back(&F); + FirstOption.Pieces.push_back(P->Parts[2]); + + SelectPiece Select(MT_Diff); + Select.Options.push_back(&FirstOption); + Select.Options.push_back(P->Parts[3]); + + VisitSelect(&Select); + } std::vector<std::string> &RST; }; @@ -982,9 +989,13 @@ public: void VisitDiff(DiffPiece *P) { Result += "%diff{"; - Visit(P->Options[0]); + Visit(P->Parts[0]); + Result += "$"; + Visit(P->Parts[1]); + Result += "$"; + Visit(P->Parts[2]); Result += "|"; - Visit(P->Options[1]); + Visit(P->Parts[3]); Result += "}"; addInt(mapIndex(P->Indexes[0])); Result += ","; @@ -1009,16 +1020,19 @@ int DiagnosticTextBuilder::DiagText::parseModifier(StringRef &Text) const { } Piece *DiagnosticTextBuilder::DiagText::parseDiagText(StringRef &Text, - bool Nested) { + StopAt Stop) { std::vector<Piece *> Parsed; + constexpr llvm::StringLiteral StopSets[] = {"%", "%|}", "%|}$"}; + llvm::StringRef StopSet = StopSets[static_cast<int>(Stop)]; + while (!Text.empty()) { size_t End = (size_t)-2; do - End = Nested ? Text.find_first_of("%|}", End + 2) - : Text.find_first_of('%', End + 2); - while (End < Text.size() - 1 && Text[End] == '%' && - (Text[End + 1] == '%' || Text[End + 1] == '|')); + End = Text.find_first_of(StopSet, End + 2); + while ( + End < Text.size() - 1 && Text[End] == '%' && + (Text[End + 1] == '%' || Text[End + 1] == '|' || Text[End + 1] == '$')); if (End) { Parsed.push_back(New<TextPiece>(Text.slice(0, End), "diagtext")); @@ -1027,7 +1041,7 @@ Piece *DiagnosticTextBuilder::DiagText::parseDiagText(StringRef &Text, break; } - if (Text[0] == '|' || Text[0] == '}') + if (Text[0] == '|' || Text[0] == '}' || Text[0] == '$') break; // Drop the '%'. @@ -1050,6 +1064,12 @@ Piece *DiagnosticTextBuilder::DiagText::parseDiagText(StringRef &Text, .Case("", MT_Placeholder) .Default(MT_Unknown); + auto ExpectAndConsume = [&](StringRef Prefix) { + if (!Text.consume_front(Prefix)) + Builder.PrintFatalError("expected '" + Prefix + "' while parsing %" + + Modifier); + }; + switch (ModType) { case MT_Unknown: Builder.PrintFatalError("Unknown modifier type: " + Modifier); @@ -1057,11 +1077,11 @@ Piece *DiagnosticTextBuilder::DiagText::parseDiagText(StringRef &Text, SelectPiece *Select = New<SelectPiece>(MT_Select); do { Text = Text.drop_front(); // '{' or '|' - Select->Options.push_back(parseDiagText(Text, true)); + Select->Options.push_back( + parseDiagText(Text, StopAt::PipeOrCloseBrace)); assert(!Text.empty() && "malformed %select"); } while (Text.front() == '|'); - // Drop the trailing '}'. - Text = Text.drop_front(1); + ExpectAndConsume("}"); Select->Index = parseModifier(Text); Parsed.push_back(Select); continue; @@ -1078,24 +1098,24 @@ Piece *DiagnosticTextBuilder::DiagText::parseDiagText(StringRef &Text, Plural->OptionPrefixes.push_back( New<TextPiece>(Text.slice(0, End), "diagtext")); Text = Text.slice(End, StringRef::npos); - Plural->Options.push_back(parseDiagText(Text, true)); - assert(!Text.empty() && "malformed %select"); + Plural->Options.push_back( + parseDiagText(Text, StopAt::PipeOrCloseBrace)); + assert(!Text.empty() && "malformed %plural"); } while (Text.front() == '|'); - // Drop the trailing '}'. - Text = Text.drop_front(1); + ExpectAndConsume("}"); Plural->Index = parseModifier(Text); Parsed.push_back(Plural); continue; } case MT_Sub: { SubstitutionPiece *Sub = New<SubstitutionPiece>(); - Text = Text.drop_front(); // '{' + ExpectAndConsume("{"); size_t NameSize = Text.find_first_of('}'); assert(NameSize != size_t(-1) && "failed to find the end of the name"); assert(NameSize != 0 && "empty name?"); Sub->Name = Text.substr(0, NameSize).str(); Text = Text.drop_front(NameSize); - Text = Text.drop_front(); // '}' + ExpectAndConsume("}"); if (!Text.empty()) { while (true) { if (!isdigit(Text[0])) @@ -1113,14 +1133,17 @@ Piece *DiagnosticTextBuilder::DiagText::parseDiagText(StringRef &Text, } case MT_Diff: { DiffPiece *Diff = New<DiffPiece>(); - Text = Text.drop_front(); // '{' - Diff->Options[0] = parseDiagText(Text, true); - Text = Text.drop_front(); // '|' - Diff->Options[1] = parseDiagText(Text, true); - - Text = Text.drop_front(); // '}' + ExpectAndConsume("{"); + Diff->Parts[0] = parseDiagText(Text, StopAt::Dollar); + ExpectAndConsume("$"); + Diff->Parts[1] = parseDiagText(Text, StopAt::Dollar); + ExpectAndConsume("$"); + Diff->Parts[2] = parseDiagText(Text, StopAt::PipeOrCloseBrace); + ExpectAndConsume("|"); + Diff->Parts[3] = parseDiagText(Text, StopAt::PipeOrCloseBrace); + ExpectAndConsume("}"); Diff->Indexes[0] = parseModifier(Text); - Text = Text.drop_front(); // ',' + ExpectAndConsume(","); Diff->Indexes[1] = parseModifier(Text); Parsed.push_back(Diff); continue; @@ -1151,7 +1174,7 @@ std::vector<std::string> DiagnosticTextBuilder::buildForDocumentation(StringRef Severity, const Record *R) { EvaluatingRecordGuard Guard(&EvaluatingRecord, R); - StringRef Text = R->getValueAsString("Text"); + StringRef Text = R->getValueAsString("Summary"); DiagText D(*this, Text); TextPiece *Prefix = D.New<TextPiece>(Severity, Severity); @@ -1170,7 +1193,7 @@ DiagnosticTextBuilder::buildForDocumentation(StringRef Severity, std::string DiagnosticTextBuilder::buildForDefinition(const Record *R) { EvaluatingRecordGuard Guard(&EvaluatingRecord, R); - StringRef Text = R->getValueAsString("Text"); + StringRef Text = R->getValueAsString("Summary"); DiagText D(*this, Text); std::string Result; DiagTextPrinter{*this, Result}.Visit(D.Root); @@ -1264,8 +1287,8 @@ void clang::EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS, OS << ", \""; OS.write_escaped(DiagTextBuilder.buildForDefinition(&R)) << '"'; - // Warning associated with the diagnostic. This is stored as an index into - // the alphabetically sorted warning table. + // Warning group associated with the diagnostic. This is stored as an index + // into the alphabetically sorted warning group table. if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) { std::map<std::string, GroupInfo>::iterator I = DiagsInGroup.find( std::string(DI->getDef()->getValueAsString("GroupName"))); @@ -1294,6 +1317,11 @@ void clang::EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS, else OS << ", false"; + if (R.getValueAsBit("ShowInSystemMacro")) + OS << ", true"; + else + OS << ", false"; + if (R.getValueAsBit("Deferrable")) OS << ", true"; else @@ -1315,7 +1343,7 @@ static std::string getDiagCategoryEnum(llvm::StringRef name) { SmallString<256> enumName = llvm::StringRef("DiagCat_"); for (llvm::StringRef::iterator I = name.begin(), E = name.end(); I != E; ++I) enumName += isalnum(*I) ? *I : '_'; - return std::string(enumName.str()); + return std::string(enumName); } /// Emit the array of diagnostic subgroups. @@ -1472,18 +1500,20 @@ static void emitDiagTable(std::map<std::string, GroupInfo> &DiagsInGroup, for (auto const &I: DiagsInGroup) MaxLen = std::max(MaxLen, (unsigned)I.first.size()); - OS << "\n#ifdef GET_DIAG_TABLE\n"; + OS << "\n#ifdef DIAG_ENTRY\n"; unsigned SubGroupIndex = 1, DiagArrayIndex = 1; for (auto const &I: DiagsInGroup) { // Group option string. - OS << " { /* "; + OS << "DIAG_ENTRY("; + OS << I.second.GroupName << " /* "; + if (I.first.find_first_not_of("abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789!@#$%^*-+=:?") != std::string::npos) PrintFatalError("Invalid character in diagnostic group '" + I.first + "'"); - OS << I.first << " */ " << std::string(MaxLen - I.first.size(), ' '); + OS << I.first << " */, "; // Store a pascal-style length byte at the beginning of the string. std::string Name = char(I.first.size()) + I.first; OS << GroupNames.GetOrAddStringOffset(Name, false) << ", "; @@ -1502,7 +1532,7 @@ static void emitDiagTable(std::map<std::string, GroupInfo> &DiagsInGroup, DiagArrayIndex += DiagsInPedantic.size(); DiagArrayIndex += V.size() + 1; } else { - OS << "/* Empty */ 0, "; + OS << "0, "; } // Subgroups. @@ -1510,17 +1540,25 @@ static void emitDiagTable(std::map<std::string, GroupInfo> &DiagsInGroup, const bool hasSubGroups = !SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty()); if (hasSubGroups) { - OS << "/* DiagSubGroup" << I.second.IDNo << " */ " << SubGroupIndex; + OS << "/* DiagSubGroup" << I.second.IDNo << " */ " << SubGroupIndex + << ", "; if (IsPedantic) SubGroupIndex += GroupsInPedantic.size(); SubGroupIndex += SubGroups.size() + 1; } else { - OS << "/* Empty */ 0"; + OS << "0, "; } - OS << " },\n"; + std::string Documentation = I.second.Defs.back() + ->getValue("Documentation") + ->getValue() + ->getAsUnquotedString(); + + OS << "R\"(" << StringRef(Documentation).trim() << ")\""; + + OS << ")\n"; } - OS << "#endif // GET_DIAG_TABLE\n\n"; + OS << "#endif // DIAG_ENTRY\n\n"; } /// Emit the table of diagnostic categories. @@ -1673,7 +1711,7 @@ void writeHeader(StringRef Str, raw_ostream &OS, char Kind = '-') { void writeDiagnosticText(DiagnosticTextBuilder &Builder, const Record *R, StringRef Role, raw_ostream &OS) { - StringRef Text = R->getValueAsString("Text"); + StringRef Text = R->getValueAsString("Summary"); if (Text == "%0") OS << "The text of this diagnostic is not controlled by Clang.\n\n"; else { |