[TableGen] Track reference locations of Records/RecordVals
authorRiver Riddle <riddleriver@gmail.com>
Fri, 16 Sep 2022 22:06:51 +0000 (15:06 -0700)
committerRiver Riddle <riddleriver@gmail.com>
Wed, 28 Sep 2022 06:48:16 +0000 (23:48 -0700)
This is extremely useful for language tooling as it allows
for providing go-to-def/find-references/etc. for many
more situations than what is currently possible.

Differential Revision: https://reviews.llvm.org/D134087

18 files changed:
clang/test/TableGen/redefined-group.td
llvm/include/llvm/TableGen/Record.h
llvm/lib/TableGen/TGLexer.cpp
llvm/lib/TableGen/TGLexer.h
llvm/lib/TableGen/TGParser.cpp
llvm/lib/TableGen/TGParser.h
llvm/test/TableGen/ConstraintChecking1.td
llvm/test/TableGen/ConstraintChecking2.td
llvm/test/TableGen/ConstraintChecking3.td
llvm/test/TableGen/ConstraintChecking4.td
llvm/test/TableGen/ConstraintChecking5.td
llvm/test/TableGen/ConstraintChecking6.td
llvm/test/TableGen/ConstraintChecking7.td
llvm/test/TableGen/GlobalISelEmitter-setcc.td
llvm/test/TableGen/RegisterClass.td
llvm/test/TableGen/SchedModelError.td
llvm/test/TableGen/generic-tables.td
mlir/lib/Tools/tblgen-lsp-server/TableGenServer.cpp

index 5ffeb30..558c677 100644 (file)
@@ -4,31 +4,31 @@ include "DiagnosticBase.inc"
 def NamedGroup : DiagGroup<"a">;
 def InNamedGroup1 : Warning<"">, InGroup<DiagGroup<"a">>;
 def InNamedGroup2 : Warning<"">, InGroup  < DiagGroup<"a"> >;
-// CHECK: redefined-group.td:[[@LINE-3]]:1: error: group 'a' is defined more than once
-// CHECK: redefined-group.td:[[@LINE-3]]:1: note: also implicitly defined here
-// CHECK: redefined-group.td:[[@LINE-3]]:1: note: also implicitly defined here
+// CHECK: redefined-group.td:[[@LINE-3]]:5: error: group 'a' is defined more than once
+// CHECK: redefined-group.td:[[@LINE-3]]:5: note: also implicitly defined here
+// CHECK: redefined-group.td:[[@LINE-3]]:5: note: also implicitly defined here
 
 def : DiagGroup<"b">;
 def InUnnamedGroup : Warning<"">, InGroup<DiagGroup<"b">>;
 // CHECK: redefined-group.td:[[@LINE-2]]:1: error: group 'b' is defined more than once
-// CHECK: redefined-group.td:[[@LINE-2]]:1: note: also implicitly defined here
+// CHECK: redefined-group.td:[[@LINE-2]]:5: note: also implicitly defined here
 
 def ImplicitGroup1 : Warning<"">, InGroup<DiagGroup<"c">>;
 def ImplicitGroup2 : Warning<"">, InGroup<DiagGroup<"c">>;
 def ImplicitGroup3 : Warning<"">,
   InGroup<DiagGroup<"c">>;
-// CHECK: redefined-group.td:[[@LINE-4]]:1: error: group 'c' is implicitly defined more than once
-// CHECK: redefined-group.td:[[@LINE-4]]:1: note: also implicitly defined here
-// CHECK: redefined-group.td:[[@LINE-4]]:1: note: also implicitly defined here
+// CHECK: redefined-group.td:[[@LINE-4]]:5: error: group 'c' is implicitly defined more than once
+// CHECK: redefined-group.td:[[@LINE-4]]:5: note: also implicitly defined here
+// CHECK: redefined-group.td:[[@LINE-4]]:5: note: also implicitly defined here
 
 def NamedAndUnnamed : DiagGroup<"d">;
 def : DiagGroup<"d">;
-// CHECK: redefined-group.td:[[@LINE-2]]:1: error: group 'd' is defined more than once
+// CHECK: redefined-group.td:[[@LINE-2]]:5: error: group 'd' is defined more than once
 // CHECK: redefined-group.td:[[@LINE-2]]:1: note: also defined here
 
 def : DiagGroup<"e">;
 def NamedAndUnnamed2 : DiagGroup<"e">;
-// CHECK: redefined-group.td:[[@LINE-1]]:1: error: group 'e' is defined more than once
+// CHECK: redefined-group.td:[[@LINE-1]]:5: error: group 'e' is defined more than once
 // CHECK: redefined-group.td:[[@LINE-3]]:1: note: also defined here
 
 def InGroupF1 : Warning<"">, InGroup<DiagGroup<"f">>;
@@ -38,6 +38,6 @@ def GroupF : DiagGroup<"f">;
 def InGroupF3 : Warning<"">, InGroup<GroupF>;
 def InGroupF4 : Warning<"">, InGroup<DiagGroup<"f">>;
 // CHECK: redefined-group.td:[[@LINE-5]]:1: error: group 'f' is defined more than once
-// CHECK: redefined-group.td:[[@LINE-7]]:1: note: also implicitly defined here
-// CHECK: redefined-group.td:[[@LINE-6]]:1: note: also implicitly defined here
-// CHECK: redefined-group.td:[[@LINE-4]]:1: note: also implicitly defined here
+// CHECK: redefined-group.td:[[@LINE-7]]:5: note: also implicitly defined here
+// CHECK: redefined-group.td:[[@LINE-6]]:5: note: also implicitly defined here
+// CHECK: redefined-group.td:[[@LINE-4]]:5: note: also implicitly defined here
index 50df38e..2d44f39 100644 (file)
@@ -1478,6 +1478,9 @@ private:
   Init *Value;
   bool IsUsed = false;
 
+  /// Reference locations to this record value.
+  SmallVector<SMRange> ReferenceLocs;
+
 public:
   RecordVal(Init *N, RecTy *T, FieldKind K);
   RecordVal(Init *N, SMLoc Loc, RecTy *T, FieldKind K);
@@ -1524,6 +1527,12 @@ public:
   /// Set the value and source location of the field.
   bool setValue(Init *V, SMLoc NewLoc);
 
+  /// Add a reference to this record value.
+  void addReferenceLoc(SMRange Loc) { ReferenceLocs.push_back(Loc); }
+
+  /// Return the references of this record value.
+  ArrayRef<SMRange> getReferenceLocs() const { return ReferenceLocs; }
+
   /// Whether this value is used. Useful for reporting warnings, for example
   /// when a template argument is unused.
   void setUsed(bool Used) { IsUsed = Used; }
@@ -1556,9 +1565,11 @@ public:
 private:
   Init *Name;
   // Location where record was instantiated, followed by the location of
-  // multiclass prototypes used.
+  // multiclass prototypes used, and finally by the locations of references to
+  // this record.
   SmallVector<SMLoc, 4> Locs;
   SmallVector<SMLoc, 0> ForwardDeclarationLocs;
+  SmallVector<SMRange, 0> ReferenceLocs;
   SmallVector<Init *, 0> TemplateArgs;
   SmallVector<RecordVal, 0> Values;
   SmallVector<AssertionInfo, 0> Assertions;
@@ -1628,6 +1639,12 @@ public:
     return ForwardDeclarationLocs;
   }
 
+  /// Add a reference to this record value.
+  void appendReferenceLoc(SMRange Loc) { ReferenceLocs.push_back(Loc); }
+
+  /// Return the references of this record value.
+  ArrayRef<SMRange> getReferenceLocs() const { return ReferenceLocs; }
+
   // Update a class location when encountering a (re-)definition.
   void updateClassLoc(SMLoc Loc);
 
index a33ed81..65959b2 100644 (file)
@@ -63,6 +63,10 @@ SMLoc TGLexer::getLoc() const {
   return SMLoc::getFromPointer(TokStart);
 }
 
+SMRange TGLexer::getLocRange() const {
+  return {getLoc(), SMLoc::getFromPointer(CurPtr)};
+}
+
 /// ReturnError - Set the error to the specified string at the specified
 /// location.  This is defined to always return tgtok::Error.
 tgtok::TokKind TGLexer::ReturnError(SMLoc Loc, const Twine &Msg) {
index 459ba0f..9ba66b7 100644 (file)
@@ -131,6 +131,7 @@ public:
   }
 
   SMLoc getLoc() const;
+  SMRange getLocRange() const;
 
 private:
   /// LexToken - Read the next token and return its code.
index 325d437..82a589a 100644 (file)
@@ -161,7 +161,7 @@ bool TGParser::AddValue(Record *CurRec, SMLoc Loc, const RecordVal &RV) {
 /// Return true on error, false on success.
 bool TGParser::SetValue(Record *CurRec, SMLoc Loc, Init *ValName,
                         ArrayRef<unsigned> BitList, Init *V,
-                        bool AllowSelfAssignment) {
+                        bool AllowSelfAssignment, bool OverrideDefLoc) {
   if (!V) return false;
 
   if (!CurRec) CurRec = &CurMultiClass->Rec;
@@ -211,7 +211,7 @@ bool TGParser::SetValue(Record *CurRec, SMLoc Loc, Init *ValName,
     V = BitsInit::get(Records, NewBits);
   }
 
-  if (RV->setValue(V, Loc)) {
+  if (OverrideDefLoc ? RV->setValue(V, Loc) : RV->setValue(V)) {
     std::string InitType;
     if (BitsInit *BI = dyn_cast<BitsInit>(V))
       InitType = (Twine("' of type bit initializer with length ") +
@@ -586,6 +586,8 @@ Record *TGParser::ParseClassID() {
                Lex.getCurStrVal() + "'");
     else
       TokError(Msg);
+  } else {
+    Result->appendReferenceLoc(Lex.getLocRange());
   }
 
   Lex.Lex();
@@ -867,11 +869,13 @@ RecTy *TGParser::ParseType() {
 }
 
 /// ParseIDValue
-Init *TGParser::ParseIDValue(Record *CurRec, StringInit *Name, SMLoc NameLoc,
+Init *TGParser::ParseIDValue(Record *CurRec, StringInit *Name, SMRange NameLoc,
                              IDParseMode Mode) {
   if (CurRec) {
-    if (const RecordVal *RV = CurRec->getValue(Name))
+    if (RecordVal *RV = CurRec->getValue(Name)) {
+      RV->addReferenceLoc(NameLoc);
       return VarInit::get(Name, RV->getType());
+    }
   }
 
   if ((CurRec && CurRec->isClass()) || CurMultiClass) {
@@ -887,6 +891,7 @@ Init *TGParser::ParseIDValue(Record *CurRec, StringInit *Name, SMLoc NameLoc,
       RecordVal *RV = TemplateRec->getValue(TemplateArgName);
       assert(RV && "Template arg doesn't exist??");
       RV->setUsed(true);
+      RV->addReferenceLoc(NameLoc);
       return VarInit::get(TemplateArgName, RV->getType());
     } else if (Name->getValue() == "NAME") {
       return VarInit::get(TemplateArgName, StringRecTy::get(Records));
@@ -909,8 +914,12 @@ Init *TGParser::ParseIDValue(Record *CurRec, StringInit *Name, SMLoc NameLoc,
   if (Mode == ParseNameMode)
     return Name;
 
-  if (Init *I = Records.getGlobal(Name->getValue()))
+  if (Init *I = Records.getGlobal(Name->getValue())) {
+    // Add a reference to the global if it's a record.
+    if (auto *Def = dyn_cast<DefInit>(I))
+      Def->getDef()->appendReferenceLoc(NameLoc);
     return I;
+  }
 
   // Allow self-references of concrete defs, but delay the lookup so that we
   // get the correct type.
@@ -918,7 +927,7 @@ Init *TGParser::ParseIDValue(Record *CurRec, StringInit *Name, SMLoc NameLoc,
       CurRec->getNameInit() == Name)
     return UnOpInit::get(UnOpInit::CAST, Name, CurRec->getType());
 
-  Error(NameLoc, "Variable not defined: '" + Name->getValue() + "'");
+  Error(NameLoc.Start, "Variable not defined: '" + Name->getValue() + "'");
   return nullptr;
 }
 
@@ -2184,7 +2193,7 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType,
     Lex.Lex();
     break;
   case tgtok::Id: {
-    SMLoc NameLoc = Lex.getLoc();
+    SMRange NameLoc = Lex.getLocRange();
     StringInit *Name = StringInit::get(Records, Lex.getCurStrVal());
     if (Lex.Lex() != tgtok::less)  // consume the Id.
       return ParseIDValue(CurRec, Name, NameLoc, Mode);    // Value ::= IDValue
@@ -2194,7 +2203,8 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType,
     // from the class with the template arguments, but no body.
     Record *Class = Records.getClass(Name->getValue());
     if (!Class) {
-      Error(NameLoc, "Expected a class name, got '" + Name->getValue() + "'");
+      Error(NameLoc.Start,
+            "Expected a class name, got '" + Name->getValue() + "'");
       return nullptr;
     }
 
@@ -2203,7 +2213,7 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType,
     if (ParseTemplateArgValueList(Args, CurRec, Class))
       return nullptr; // Error parsing value list.
 
-    if (CheckTemplateArgValues(Args, NameLoc, Class))
+    if (CheckTemplateArgValues(Args, NameLoc.Start, Class))
       return nullptr; // Error checking template argument values.
 
     // Loop through the arguments that were not specified and make sure
@@ -2211,14 +2221,15 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType,
     ArrayRef<Init *> TArgs = Class->getTemplateArgs();
     for (unsigned I = Args.size(), E = TArgs.size(); I < E; ++I) {
       RecordVal *Arg = Class->getValue(TArgs[I]);
-      if (!Arg->getValue()->isComplete()) 
-        Error(NameLoc, "Value not specified for template argument '" +
-                           TArgs[I]->getAsUnquotedString() + "' (#" + Twine(I) +
-                           ") of parent class '" +
-                           Class->getNameInitAsString() + "'");
-              
+      if (!Arg->getValue()->isComplete()) {
+        Error(NameLoc.Start, "Value not specified for template argument '" +
+                                 TArgs[I]->getAsUnquotedString() + "' (#" +
+                                 Twine(I) + ") of parent class '" +
+                                 Class->getNameInitAsString() + "'");
+      }
     }
 
+    Class->appendReferenceLoc(NameLoc);
     return VarDefInit::get(Class, Args)->Fold();
   }
   case tgtok::l_brace: {           // Value ::= '{' ValueList '}'
@@ -2510,12 +2521,25 @@ Init *TGParser::ParseValue(Record *CurRec, RecTy *ItemType, IDParseMode Mode) {
         TokError("expected field identifier after '.'");
         return nullptr;
       }
+      SMRange FieldNameLoc = Lex.getLocRange();
       StringInit *FieldName = StringInit::get(Records, Lex.getCurStrVal());
       if (!Result->getFieldType(FieldName)) {
         TokError("Cannot access field '" + Lex.getCurStrVal() + "' of value '" +
                  Result->getAsString() + "'");
         return nullptr;
       }
+
+      // Add a reference to this field if we know the record class.
+      if (auto *DI = dyn_cast<DefInit>(Result)) {
+        DI->getDef()->getValue(FieldName)->addReferenceLoc(FieldNameLoc);
+      } else if (auto *TI = dyn_cast<TypedInit>(Result)) {
+        if (auto *RecTy = dyn_cast<RecordRecTy>(TI->getType())) {
+          for (Record *R : RecTy->getClasses())
+            if (auto *RV = R->getValue(FieldName))
+              RV->addReferenceLoc(FieldNameLoc);
+        }
+      }
+
       Result = FieldInit::get(Result, FieldName)->Fold(CurRec);
       Lex.Lex();  // eat field name
       break;
@@ -2780,11 +2804,13 @@ Init *TGParser::ParseDeclaration(Record *CurRec,
     SMLoc ValLoc = Lex.getLoc();
     Init *Val = ParseValue(CurRec, Type);
     if (!Val ||
-        SetValue(CurRec, ValLoc, DeclName, None, Val))
+        SetValue(CurRec, ValLoc, DeclName, None, Val,
+                 /*AllowSelfAssignment=*/false, /*OverrideDefLoc=*/false)) {
       // Return the name, even if an error is thrown.  This is so that we can
       // continue to make some progress, even without the value having been
       // initialized.
       return DeclName;
+    }
   }
 
   return DeclName;
@@ -3078,17 +3104,24 @@ bool TGParser::ParseDef(MultiClass *CurMultiClass) {
   assert(Lex.getCode() == tgtok::Def && "Unknown tok");
   Lex.Lex();  // Eat the 'def' token.
 
+  // If the name of the def is an Id token, use that for the location.
+  // Otherwise, the name is more complex and we use the location of the 'def'
+  // token.
+  SMLoc NameLoc = Lex.getCode() == tgtok::Id ? Lex.getLoc() : DefLoc;
+
   // Parse ObjectName and make a record for it.
   std::unique_ptr<Record> CurRec;
   Init *Name = ParseObjectName(CurMultiClass);
   if (!Name)
     return true;
 
-  if (isa<UnsetInit>(Name))
-    CurRec = std::make_unique<Record>(Records.getNewAnonymousName(), DefLoc, Records,
+  if (isa<UnsetInit>(Name)) {
+    CurRec =
+        std::make_unique<Record>(Records.getNewAnonymousName(), DefLoc, Records,
                                  /*Anonymous=*/true);
-  else
-    CurRec = std::make_unique<Record>(Name, DefLoc, Records);
+  } else {
+    CurRec = std::make_unique<Record>(Name, NameLoc, Records);
+  }
 
   if (ParseObjectBody(CurRec.get()))
     return true;
index d4b928c..0e630dc 100644 (file)
@@ -198,9 +198,12 @@ public:
 
 private: // Semantic analysis methods.
   bool AddValue(Record *TheRec, SMLoc Loc, const RecordVal &RV);
+  /// Set the value of a RecordVal within the given record. If `OverrideDefLoc`
+  /// is set, the provided location overrides any existing location of the
+  /// RecordVal.
   bool SetValue(Record *TheRec, SMLoc Loc, Init *ValName,
                 ArrayRef<unsigned> BitList, Init *V,
-                bool AllowSelfAssignment = false);
+                bool AllowSelfAssignment = false, bool OverrideDefLoc = true);
   bool AddSubClass(Record *Rec, SubClassReference &SubClass);
   bool AddSubClass(RecordsEntry &Entry, SubClassReference &SubClass);
   bool AddSubMultiClass(MultiClass *CurMC,
@@ -244,7 +247,7 @@ private:  // Parser methods.
   SubClassReference ParseSubClassReference(Record *CurRec, bool isDefm);
   SubMultiClassReference ParseSubMultiClassReference(MultiClass *CurMC);
 
-  Init *ParseIDValue(Record *CurRec, StringInit *Name, SMLoc NameLoc,
+  Init *ParseIDValue(Record *CurRec, StringInit *Name, SMRange NameLoc,
                      IDParseMode Mode = ParseValueMode);
   Init *ParseSimpleValue(Record *CurRec, RecTy *ItemType = nullptr,
                          IDParseMode Mode = ParseValueMode);
index 2c0c3d9..f885974 100644 (file)
@@ -2,5 +2,5 @@
 
 include "ConstraintChecking.inc"
 
-// CHECK: [[FILE]]:[[@LINE+1]]:1: error: Unrecognized constraint '$dest1 ~ $src2' in 'Foo'
+// CHECK: [[FILE]]:[[@LINE+1]]:5: error: Unrecognized constraint '$dest1 ~ $src2' in 'Foo'
 def Foo : TestInstructionWithConstraints<"$dest1 ~ $src2">;
index 65ec882..ae9fbe3 100644 (file)
@@ -2,5 +2,5 @@
 
 include "ConstraintChecking.inc"
 
-// CHECK: [[FILE]]:[[@LINE+1]]:1: error: Illegal format for @earlyclobber constraint in 'Foo'
+// CHECK: [[FILE]]:[[@LINE+1]]:5: error: Illegal format for @earlyclobber constraint in 'Foo'
 def Foo : TestInstructionWithConstraints<"@earlyclobber ">;
index 835ec2e..2d5fe6b 100644 (file)
@@ -4,5 +4,5 @@ include "ConstraintChecking.inc"
 
 // (This is illegal because the '=' has to be surrounded by whitespace)
 
-// CHECK: [[FILE]]:[[@LINE+1]]:1: error: Illegal format for tied-to constraint in 'Foo'
+// CHECK: [[FILE]]:[[@LINE+1]]:5: error: Illegal format for tied-to constraint in 'Foo'
 def Foo : TestInstructionWithConstraints<"$dest1=$dest2">;
index bd511eb..ae11c47 100644 (file)
@@ -2,5 +2,5 @@
 
 include "ConstraintChecking.inc"
 
-// CHECK: [[FILE]]:[[@LINE+1]]:1: error: Output operands '$dest1' and '$dest2' of 'Foo' cannot be tied!
+// CHECK: [[FILE]]:[[@LINE+1]]:5: error: Output operands '$dest1' and '$dest2' of 'Foo' cannot be tied!
 def Foo : TestInstructionWithConstraints<"$dest1 = $dest2">;
index 7db3546..0773e65 100644 (file)
@@ -2,5 +2,5 @@
 
 include "ConstraintChecking.inc"
 
-// CHECK: [[FILE]]:[[@LINE+1]]:1: error: Input operands '$src1' and '$src2' of 'Foo' cannot be tied!
+// CHECK: [[FILE]]:[[@LINE+1]]:5: error: Input operands '$src1' and '$src2' of 'Foo' cannot be tied!
 def Foo : TestInstructionWithConstraints<"$src1 = $src2">;
index 2d3bdd2..676eb7a 100644 (file)
@@ -2,5 +2,5 @@
 
 include "ConstraintChecking.inc"
 
-// CHECK: [[FILE]]:[[@LINE+1]]:1: error: Operand '$dest1' of 'Foo' cannot have multiple operands tied to it!
+// CHECK: [[FILE]]:[[@LINE+1]]:5: error: Operand '$dest1' of 'Foo' cannot have multiple operands tied to it!
 def Foo : TestInstructionWithConstraints<"$dest1 = $src1, $dest1 = $src2">;
index 5a44ee4..d884ac6 100644 (file)
@@ -2,5 +2,5 @@
 
 include "ConstraintChecking.inc"
 
-// CHECK: [[FILE]]:[[@LINE+1]]:1: error: Operand '$src1' of 'Foo' cannot have multiple constraints!
+// CHECK: [[FILE]]:[[@LINE+1]]:5: error: Operand '$src1' of 'Foo' cannot have multiple constraints!
 def Foo : TestInstructionWithConstraints<"$dest1 = $src1, $dest2 = $src1">;
index 1bad175..933489b 100644 (file)
@@ -19,6 +19,6 @@ def ICMPEQ : I<(outs GPR32:$dst), (ins GPR32Op:$src0, GPR32:$src1),
                [(set GPR32:$dst, (i32 (setcc i32:$src0, i32:$src1, SETEQ)))]>;
 
 // Check there is an error if not a CondCode operand.
-// ERR: [[FILE]]:[[@LINE+1]]:1: warning: Skipped pattern: Unable to handle CondCode
+// ERR: [[FILE]]:[[@LINE+1]]:5: warning: Skipped pattern: Unable to handle CondCode
 def FCMP_NOTCC : I<(outs GPR32:$dst), (ins FPR32Op:$src0, FPR32:$src1),
                    [(set GPR32:$dst, (i32 (setcc f32:$src0, f32:$src1, i32)))]>;
index d81c2df..b7520bc 100644 (file)
@@ -4,4 +4,4 @@ include "llvm/Target/Target.td"
 
 def MyTarget : Target;
 def R0 : Register<"r0">;
-def ClassA : RegisterClass<"MyTarget", [], 32, (add R0)>; // CHECK: [[@LINE]]:1: error: RegTypes list must not be empty!
+def ClassA : RegisterClass<"MyTarget", [], 32, (add R0)>; // CHECK: [[@LINE]]:5: error: RegTypes list must not be empty!
index 237bc45..d846d27 100644 (file)
@@ -4,7 +4,7 @@ include "llvm/Target/Target.td"
 
 def TestTarget : Target;
 
-// CHECK: [[FILE]]:[[@LINE+1]]:1: error: No schedule information for instruction 'TestInst' in SchedMachineModel 'TestSchedModel'
+// CHECK: [[FILE]]:[[@LINE+1]]:5: error: No schedule information for instruction 'TestInst' in SchedMachineModel 'TestSchedModel'
 def TestInst : Instruction {
   let OutOperandList = (outs);
   let InOperandList = (ins);
index e410159..4bf3918 100644 (file)
@@ -154,7 +154,7 @@ class DEntry<string str, int val1> {
 }
 
 def DFoo : DEntry<"foo", 1>;
-// ERROR1: [[@LINE+1]]:1: error: Record 'DBar' for table 'DTable' is missing field 'Val1'
+// ERROR1: [[@LINE+1]]:5: error: Record 'DBar' for table 'DTable' is missing field 'Val1'
 def DBar : DEntry<"bar", ?>;
 
 def DTable : GenericTable {
index 7d44047..faa9a55 100644 (file)
@@ -202,16 +202,15 @@ void TableGenIndex::initialize(const llvm::RecordKeeper &records) {
     // Add references to the definition.
     for (SMLoc loc : def.getLoc().drop_front())
       insertRef(sym, lsp::convertTokenLocToRange(loc));
-
-    // Add references to any super classes.
-    for (auto &it : def.getSuperClasses())
-      insertRef(getOrInsertDef(it.first),
-                lsp::convertTokenLocToRange(it.second.Start));
+    for (SMRange loc : def.getReferenceLocs())
+      insertRef(sym, loc);
 
     // Add definitions for any values.
     for (const llvm::RecordVal &value : def.getValues()) {
       auto *sym = getOrInsertDef(&value);
       insertRef(sym, sym->defLoc, /*isDef=*/true);
+      for (SMRange refLoc : value.getReferenceLocs())
+        insertRef(sym, refLoc);
     }
   }
 }