[cfe-commits] r172087 - in /cfe/trunk: test/TableGen/ test/TableGen/DiagnosticBase.inc test/TableGen/anonymous-groups.td test/TableGen/lit.local.cfg test/TableGen/tg-fixits.td utils/TableGen/ClangDiagnosticsEmitter.cpp
Jordan Rose
jordan_rose at apple.com
Thu Jan 10 10:50:46 PST 2013
Author: jrose
Date: Thu Jan 10 12:50:46 2013
New Revision: 172087
URL: http://llvm.org/viewvc/llvm-project?rev=172087&view=rev
Log:
Error if an anonymous DiagGroup is referenced multiple times.
Not only is this inefficient for TableGen, it's annoying for maintenance
when renaming warning flags (unusual) or adding those flags to a group
(more likely).
This uses the new fix-it infrastructure for LLVM's SourceMgr/SMDiagnostic,
as well as a few changes to TableGen to track more source information.
Added:
cfe/trunk/test/TableGen/
cfe/trunk/test/TableGen/DiagnosticBase.inc
cfe/trunk/test/TableGen/anonymous-groups.td
cfe/trunk/test/TableGen/lit.local.cfg
cfe/trunk/test/TableGen/tg-fixits.td
Modified:
cfe/trunk/utils/TableGen/ClangDiagnosticsEmitter.cpp
Added: cfe/trunk/test/TableGen/DiagnosticBase.inc
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/TableGen/DiagnosticBase.inc?rev=172087&view=auto
==============================================================================
--- cfe/trunk/test/TableGen/DiagnosticBase.inc (added)
+++ cfe/trunk/test/TableGen/DiagnosticBase.inc Thu Jan 10 12:50:46 2013
@@ -0,0 +1,35 @@
+// Define the diagnostic mappings.
+class DiagMapping;
+def MAP_IGNORE : DiagMapping;
+def MAP_WARNING : DiagMapping;
+def MAP_ERROR : DiagMapping;
+def MAP_FATAL : DiagMapping;
+
+// Define the diagnostic classes.
+class DiagClass;
+def CLASS_NOTE : DiagClass;
+def CLASS_WARNING : DiagClass;
+def CLASS_EXTENSION : DiagClass;
+def CLASS_ERROR : DiagClass;
+
+class DiagGroup<string Name, list<DiagGroup> subgroups = []> {
+ string GroupName = Name;
+ list<DiagGroup> SubGroups = subgroups;
+ string CategoryName = "";
+}
+class InGroup<DiagGroup G> { DiagGroup Group = G; }
+
+// All diagnostics emitted by the compiler are an indirect subclass of this.
+class Diagnostic<string text, DiagClass DC, DiagMapping defaultmapping> {
+ string Text = text;
+ DiagClass Class = DC;
+ DiagMapping DefaultMapping = defaultmapping;
+ DiagGroup Group;
+ string CategoryName = "";
+}
+
+class Error<string str> : Diagnostic<str, CLASS_ERROR, MAP_ERROR>;
+class Warning<string str> : Diagnostic<str, CLASS_WARNING, MAP_WARNING>;
+class Extension<string str> : Diagnostic<str, CLASS_EXTENSION, MAP_IGNORE>;
+class ExtWarn<string str> : Diagnostic<str, CLASS_EXTENSION, MAP_WARNING>;
+class Note<string str> : Diagnostic<str, CLASS_NOTE, MAP_FATAL/*ignored*/>;
Added: cfe/trunk/test/TableGen/anonymous-groups.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/TableGen/anonymous-groups.td?rev=172087&view=auto
==============================================================================
--- cfe/trunk/test/TableGen/anonymous-groups.td (added)
+++ cfe/trunk/test/TableGen/anonymous-groups.td Thu Jan 10 12:50:46 2013
@@ -0,0 +1,42 @@
+// RUN: clang-tblgen -gen-clang-diag-groups -I%S %s -o /dev/null 2>&1 | FileCheck --strict-whitespace %s
+include "DiagnosticBase.inc"
+
+// Do not move this line; it is referred to by absolute line number in the
+// FileCheck lines below.
+def NamedGroup : DiagGroup<"name">;
+
+
+def InNamedGroup : Warning<"">, InGroup<DiagGroup<"name">>;
+// CHECK: anonymous-groups.td:[[@LINE-1]]:41: error: group 'name' is referred to anonymously
+// CHECK-NEXT: {{^def InNamedGroup : Warning<"">, InGroup<DiagGroup<"name">>;}}
+// CHECK-NEXT: {{^ ~~~~~~~~\^~~~~~~~~~~~~~~~~~}}
+// CHECK-NEXT: {{^ InGroup<NamedGroup>}}
+// CHECK-NEXT: anonymous-groups.td:6:1: note: group defined here
+// CHECK-NEXT: def NamedGroup : DiagGroup<"name">;
+// CHECK-NEXT: ^
+
+
+def AlsoInNamedGroup : Warning<"">, InGroup < DiagGroup<"name"> >;
+// CHECK: anonymous-groups.td:[[@LINE-1]]:48: error: group 'name' is referred to anonymously
+// CHECK-NEXT: {{^def AlsoInNamedGroup : Warning<"">, InGroup < DiagGroup<"name"> >;}}
+// CHECK-NEXT: {{^ ~~~~~~~~~~~\^~~~~~~~~~~~~~~~~~~}}
+// CHECK-NEXT: {{^ InGroup<NamedGroup>}}
+// CHECK-NEXT: anonymous-groups.td:6:1: note: group defined here
+// CHECK-NEXT: def NamedGroup : DiagGroup<"name">;
+// CHECK-NEXT: ^
+
+
+def AnonymousGroup : Warning<"">, InGroup<DiagGroup<"anonymous">>;
+def AlsoAnonymousGroup : Warning<"">, InGroup<DiagGroup<"anonymous">>;
+def AnonymousGroupAgain : Warning<"">,
+ InGroup<DiagGroup<"anonymous">>;
+
+// CHECK: anonymous-groups.td:[[@LINE-5]]:43: error: group 'anonymous' is referred to anonymously
+// CHECK-NEXT: {{^def AnonymousGroup : Warning<"">, InGroup<DiagGroup<"anonymous">>;}}
+// CHECK-NEXT: {{^ ~~~~~~~~\^~~~~~~~~~~~~~~~~~~~~~~}}
+// CHECK-NEXT: anonymous-groups.td:[[@LINE-7]]:47: note: also referenced here
+// CHECK-NEXT: {{^def AlsoAnonymousGroup : Warning<"">, InGroup<DiagGroup<"anonymous">>;}}
+// CHECK-NEXT: {{^ ~~~~~~~~\^~~~~~~~~~~~~~~~~~~~~~~}}
+// CHECK-NEXT: anonymous-groups.td:[[@LINE-8]]:11: note: also referenced here
+// CHECK-NEXT: {{^ InGroup<DiagGroup<"anonymous">>;}}
+// CHECK-NEXT: {{^ ~~~~~~~~\^~~~~~~~~~~~~~~~~~~~~~~}}
Added: cfe/trunk/test/TableGen/lit.local.cfg
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/TableGen/lit.local.cfg?rev=172087&view=auto
==============================================================================
--- cfe/trunk/test/TableGen/lit.local.cfg (added)
+++ cfe/trunk/test/TableGen/lit.local.cfg Thu Jan 10 12:50:46 2013
@@ -0,0 +1 @@
+config.suffixes = ['.td']
Added: cfe/trunk/test/TableGen/tg-fixits.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/TableGen/tg-fixits.td?rev=172087&view=auto
==============================================================================
--- cfe/trunk/test/TableGen/tg-fixits.td (added)
+++ cfe/trunk/test/TableGen/tg-fixits.td Thu Jan 10 12:50:46 2013
@@ -0,0 +1,41 @@
+// RUN: clang-tblgen -gen-clang-diag-groups -I%S %s -o /dev/null 2>&1 | FileCheck --strict-whitespace %s
+include "DiagnosticBase.inc"
+
+def NamedGroup : DiagGroup<"name">;
+
+def InNamedGroup : Warning<"">, InGroup<DiagGroup<"name">>;
+// CHECK: tg-fixits.td:[[@LINE-1]]:41: error: group 'name' is referred to anonymously
+// CHECK-NEXT: {{^def InNamedGroup : Warning<"">, InGroup<DiagGroup<"name">>;}}
+// CHECK-NEXT: {{^ ~~~~~~~~\^~~~~~~~~~~~~~~~~~}}
+// CHECK-NEXT: {{^ InGroup<NamedGroup>}}
+
+def Wrapped : Warning<"">, InGroup<DiagGroup<
+ "name">>;
+// CHECK: tg-fixits.td:[[@LINE-2]]:36: error: group 'name' is referred to anonymously
+// CHECK-NEXT: {{^def Wrapped : Warning<"">, InGroup<DiagGroup<}}
+// CHECK-NEXT: {{^ ~~~~~~~~\^~~~~~~~~~}}
+// CHECK-NEXT: {{^ InGroup<NamedGroup>}}
+
+def AlsoWrapped : Warning<"">, InGroup<
+ DiagGroup<"name">>;
+// CHECK: tg-fixits.td:[[@LINE-1]]:3: error: group 'name' is referred to anonymously
+// CHECK-NEXT: {{^ DiagGroup<"name">>;}}
+// CHECK-NEXT: {{^~~\^~~~~~~~~~~~~~~~~~}}
+// CHECK-NEXT: {{^InGroup<NamedGroup>}}
+
+// The following lines contain hard tabs (\t); do not change this!
+def HardTabs : Warning<"">,
+ InGroup< DiagGroup<"name"> >;
+// CHECK: tg-fixits.td:[[@LINE-1]]:11: error: group 'name' is referred to anonymously
+// CHECK-NEXT: {{^ InGroup< DiagGroup<"name"> >;}}
+// CHECK-NEXT: {{^ ~~~~~~~~~~~~~~~~\^~~~~~~~~~~~~~~~~~~~~~~~~}}
+// CHECK-NEXT: {{^ InGroup<NamedGrop>}}
+
+// The following line has Unicode characters in it; do not change them!
+// FIXME: For now, we just give up on printing carets/ranges/fixits for
+// lines with Unicode in them, because SMDiagnostic don't keep a byte<->column
+// map around to line things up like Clang does.
+def Unicode : Warning<"ã¦ãã³ã¼ã">, InGroup<DiagGroup<"name">>;
+// CHECK: tg-fixits.td:[[@LINE-1]]:51: error: group 'name' is referred to anonymously
+// CHECK-NEXT: def Unicode : Warning<"{{[^"]+}}">, InGroup<DiagGroup<"name">>;
+// CHECK-NEXT: note:
Modified: cfe/trunk/utils/TableGen/ClangDiagnosticsEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/ClangDiagnosticsEmitter.cpp?rev=172087&r1=172086&r2=172087&view=diff
==============================================================================
--- cfe/trunk/utils/TableGen/ClangDiagnosticsEmitter.cpp (original)
+++ cfe/trunk/utils/TableGen/ClangDiagnosticsEmitter.cpp Thu Jan 10 12:50:46 2013
@@ -14,8 +14,12 @@
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/Twine.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/TableGen/Error.h"
@@ -127,14 +131,41 @@
std::vector<const Record*> DiagsInGroup;
std::vector<std::string> SubGroups;
unsigned IDNo;
+
+ const Record *ExplicitDef;
+
+ GroupInfo() : ExplicitDef(0) {}
};
} // end anonymous namespace.
+static bool beforeThanCompare(const Record *LHS, const Record *RHS) {
+ assert(!LHS->getLoc().empty() && !RHS->getLoc().empty());
+ return
+ LHS->getLoc().front().getPointer() < RHS->getLoc().front().getPointer();
+}
+
+static bool beforeThanCompareGroups(const GroupInfo *LHS, const GroupInfo *RHS){
+ assert(!LHS->DiagsInGroup.empty() && !RHS->DiagsInGroup.empty());
+ return beforeThanCompare(LHS->DiagsInGroup.front(),
+ RHS->DiagsInGroup.front());
+}
+
+static SMRange findSuperClassRange(const Record *R, StringRef SuperName) {
+ ArrayRef<Record *> Supers = R->getSuperClasses();
+
+ for (size_t i = 0, e = Supers.size(); i < e; ++i)
+ if (Supers[i]->getName() == SuperName)
+ return R->getSuperClassRanges()[i];
+
+ return SMRange();
+}
+
/// \brief 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,
const std::vector<Record*> &DiagGroups,
std::map<std::string, GroupInfo> &DiagsInGroup) {
+
for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
const Record *R = Diags[i];
DefInit *DI = dyn_cast<DefInit>(R->getValueInit("Group"));
@@ -144,13 +175,25 @@
std::string GroupName = DI->getDef()->getValueAsString("GroupName");
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[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;
+ }
+
std::vector<Record*> SubGroups = Group->getValueAsListOfDefs("SubGroups");
for (unsigned j = 0, e = SubGroups.size(); j != e; ++j)
GI.SubGroups.push_back(SubGroups[j]->getValueAsString("GroupName"));
@@ -161,6 +204,80 @@
for (std::map<std::string, GroupInfo>::iterator
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;
+ std::sort(GroupDiags.begin(), GroupDiags.end(), beforeThanCompare);
+ }
+ std::sort(SortedGroups.begin(), SortedGroups.end(), beforeThanCompareGroups);
+
+ // 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 = (*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;
+
+ SMRange InGroupRange = findSuperClassRange(*DI, "InGroup");
+ SmallString<64> Replacement;
+ if (InGroupRange.isValid()) {
+ Replacement += "InGroup<";
+ Replacement += (*I)->ExplicitDef->getName();
+ Replacement += ">";
+ }
+ SMFixIt FixIt(InGroupRange, Replacement.str());
+
+ SrcMgr.PrintMessage(NextDiagGroup->getLoc().front(),
+ SourceMgr::DK_Error,
+ Twine("group '") + Name +
+ "' is referred to anonymously",
+ ArrayRef<SMRange>(),
+ InGroupRange.isValid() ? FixIt
+ : ArrayRef<SMFixIt>());
+ SrcMgr.PrintMessage((*I)->ExplicitDef->getLoc().front(),
+ SourceMgr::DK_Note, "group defined here");
+ }
+ } 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 = NextDiagGroup->getValueAsString("GroupName");
+
+ SMRange InGroupRange = findSuperClassRange(*DI, "InGroup");
+ SrcMgr.PrintMessage(NextDiagGroup->getLoc().front(),
+ SourceMgr::DK_Error,
+ Twine("group '") + Name +
+ "' is referred to anonymously",
+ InGroupRange);
+
+ for (++DI; DI != DE; ++DI) {
+ GroupInit = cast<DefInit>((*DI)->getValueInit("Group"));
+ InGroupRange = findSuperClassRange(*DI, "InGroup");
+ SrcMgr.PrintMessage(GroupInit->getDef()->getLoc().front(),
+ SourceMgr::DK_Note, "also referenced here",
+ InGroupRange);
+ }
+ }
+ }
}
//===----------------------------------------------------------------------===//
More information about the cfe-commits
mailing list