[llvm] [TableGen] Support type aliases via new keyword deftype (PR #79570)

Wang Pengcheng via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 31 22:12:46 PST 2024


https://github.com/wangpc-pp updated https://github.com/llvm/llvm-project/pull/79570

>From 867058380e5b02f1fc7fa0d00a0122ec03d7f82b Mon Sep 17 00:00:00 2001
From: wangpc <wangpengcheng.pp at bytedance.com>
Date: Fri, 26 Jan 2024 18:22:49 +0800
Subject: [PATCH 1/7] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20in?=
 =?UTF-8?q?itial=20version?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Created using spr 1.3.4
---
 llvm/docs/TableGen/ProgRef.rst | 18 ++++++++++++---
 llvm/lib/TableGen/TGLexer.cpp  |  1 +
 llvm/lib/TableGen/TGLexer.h    |  1 +
 llvm/lib/TableGen/TGParser.cpp | 41 +++++++++++++++++++++++++++++++++-
 llvm/lib/TableGen/TGParser.h   |  2 ++
 llvm/test/TableGen/deftype.td  | 22 ++++++++++++++++++
 6 files changed, 81 insertions(+), 4 deletions(-)
 create mode 100644 llvm/test/TableGen/deftype.td

diff --git a/llvm/docs/TableGen/ProgRef.rst b/llvm/docs/TableGen/ProgRef.rst
index 59ddef975c487..f1bbe32ec2047 100644
--- a/llvm/docs/TableGen/ProgRef.rst
+++ b/llvm/docs/TableGen/ProgRef.rst
@@ -570,8 +570,8 @@ files.
 .. productionlist::
    TableGenFile: (`Statement` | `IncludeDirective`
             :| `PreprocessorDirective`)*
-   Statement: `Assert` | `Class` | `Def` | `Defm` | `Defset` | `Defvar`
-            :| `Dump`  | `Foreach` | `If` | `Let` | `MultiClass`
+   Statement: `Assert` | `Class` | `Def` | `Defm` | `Defset` | `Deftype`
+            :| `Defvar` | `Dump`  | `Foreach` | `If` | `Let` | `MultiClass`
 
 The following sections describe each of these top-level statements.
 
@@ -931,7 +931,8 @@ template that expands into multiple records.
              : `ParentClassList`
              : "{" `MultiClassStatement`+ "}"
    MultiClassID: `TokIdentifier`
-   MultiClassStatement: `Assert` | `Def` | `Defm` | `Defvar` | `Foreach` | `If` | `Let`
+   MultiClassStatement: `Assert` | `Def` | `Defm` | `Deftype` | `Defvar`
+                      :| `Foreach` | `If` | `Let`
 
 As with regular classes, the multiclass has a name and can accept template
 arguments. A multiclass can inherit from other multiclasses, which causes
@@ -1215,6 +1216,17 @@ set.
 Anonymous records created inside initialization expressions using the
 ``ClassID<...>`` syntax are not collected in the set.
 
+``deftype`` --- define a type
+--------------------------------
+
+A ``deftype`` statement defines a type. Its value can be used
+throughout the statements that follow the definition.
+
+.. productionlist::
+   Deftype: "deftype" `TokIdentifier` "=" `Value` ";"
+
+The identifier on the left of the ``=`` is defined to be a type name
+whose actual type is given by the type expression on the right of the ``=``.
 
 ``defvar`` --- define a variable
 --------------------------------
diff --git a/llvm/lib/TableGen/TGLexer.cpp b/llvm/lib/TableGen/TGLexer.cpp
index c811a67d930d4..545643234f699 100644
--- a/llvm/lib/TableGen/TGLexer.cpp
+++ b/llvm/lib/TableGen/TGLexer.cpp
@@ -360,6 +360,7 @@ tgtok::TokKind TGLexer::LexIdentifier() {
                             .Case("foreach", tgtok::Foreach)
                             .Case("defm", tgtok::Defm)
                             .Case("defset", tgtok::Defset)
+                            .Case("deftype", tgtok::Deftype)
                             .Case("multiclass", tgtok::MultiClass)
                             .Case("field", tgtok::Field)
                             .Case("let", tgtok::Let)
diff --git a/llvm/lib/TableGen/TGLexer.h b/llvm/lib/TableGen/TGLexer.h
index 2e2aa59f34408..25dcd9fbadef7 100644
--- a/llvm/lib/TableGen/TGLexer.h
+++ b/llvm/lib/TableGen/TGLexer.h
@@ -97,6 +97,7 @@ enum TokKind {
   Def,
   Defm,
   Defset,
+  Deftype,
   Defvar,
   Dump,
   Foreach,
diff --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp
index e7dcb91ba20a6..1574505ded33a 100644
--- a/llvm/lib/TableGen/TGParser.cpp
+++ b/llvm/lib/TableGen/TGParser.cpp
@@ -1103,11 +1103,17 @@ RecTy *TGParser::ParseType() {
   case tgtok::Dag:
     Lex.Lex();
     return DagRecTy::get(Records);
-  case tgtok::Id:
+  case tgtok::Id: {
+    std::string TypeName = Lex.getCurStrVal();
+    if (TypeAliases.count(TypeName)) {
+      Lex.Lex();
+      return TypeAliases[TypeName];
+    }
     if (Record *R = ParseClassID())
       return RecordRecTy::get(R);
     TokError("unknown class name");
     return nullptr;
+  }
   case tgtok::Bits: {
     if (Lex.Lex() != tgtok::less) { // Eat 'bits'
       TokError("expected '<' after bits type");
@@ -3665,6 +3671,36 @@ bool TGParser::ParseDefset() {
   return false;
 }
 
+/// ParseDeftype - Parse a defvar statement.
+///
+///   Deftype ::= DEFTYPE Id '=' Value ';'
+///
+bool TGParser::ParseDeftype() {
+  assert(Lex.getCode() == tgtok::Deftype);
+  Lex.Lex(); // Eat the 'deftype' token
+
+  if (Lex.getCode() != tgtok::Id)
+    return TokError("expected identifier");
+
+  std::string TypeName = Lex.getCurStrVal();
+  if (TypeAliases.count(TypeName))
+    return TokError("type of this name already exists");
+
+  Lex.Lex();
+  if (!consume(tgtok::equal))
+    return TokError("expected '='");
+
+  RecTy *Type = ParseType();
+  if (!Type)
+    return true;
+  TypeAliases[TypeName] = Type;
+
+  if (!consume(tgtok::semi))
+    return TokError("expected ';'");
+
+  return false;
+}
+
 /// ParseDefvar - Parse a defvar statement.
 ///
 ///   Defvar ::= DEFVAR Id '=' Value ';'
@@ -4265,6 +4301,7 @@ bool TGParser::ParseDefm(MultiClass *CurMultiClass) {
 ///   Object ::= LETCommand '{' ObjectList '}'
 ///   Object ::= LETCommand Object
 ///   Object ::= Defset
+///   Object ::= Deftype
 ///   Object ::= Defvar
 ///   Object ::= Assert
 ///   Object ::= Dump
@@ -4276,6 +4313,8 @@ bool TGParser::ParseObject(MultiClass *MC) {
   case tgtok::Assert:  return ParseAssert(MC);
   case tgtok::Def:     return ParseDef(MC);
   case tgtok::Defm:    return ParseDefm(MC);
+  case tgtok::Deftype:
+    return ParseDeftype();
   case tgtok::Defvar:  return ParseDefvar();
   case tgtok::Dump:
     return ParseDump(MC);
diff --git a/llvm/lib/TableGen/TGParser.h b/llvm/lib/TableGen/TGParser.h
index 0929154fed3d4..b08e250870901 100644
--- a/llvm/lib/TableGen/TGParser.h
+++ b/llvm/lib/TableGen/TGParser.h
@@ -143,6 +143,7 @@ class TGParser {
   TGLexer Lex;
   std::vector<SmallVector<LetRecord, 4>> LetStack;
   std::map<std::string, std::unique_ptr<MultiClass>> MultiClasses;
+  std::map<std::string, RecTy *> TypeAliases;
 
   /// Loops - Keep track of any foreach loops we are within.
   ///
@@ -264,6 +265,7 @@ class TGParser {
   bool ParseDefm(MultiClass *CurMultiClass);
   bool ParseDef(MultiClass *CurMultiClass);
   bool ParseDefset();
+  bool ParseDeftype();
   bool ParseDefvar(Record *CurRec = nullptr);
   bool ParseDump(MultiClass *CurMultiClass, Record *CurRec = nullptr);
   bool ParseForeach(MultiClass *CurMultiClass);
diff --git a/llvm/test/TableGen/deftype.td b/llvm/test/TableGen/deftype.td
new file mode 100644
index 0000000000000..ee430cbdaf7a2
--- /dev/null
+++ b/llvm/test/TableGen/deftype.td
@@ -0,0 +1,22 @@
+// RUN: llvm-tblgen %s | FileCheck %s
+
+deftype Byte = bits<8>;
+deftype IntList = list<int>;
+deftype ByteList = list<Byte>;
+class Class<Byte b> {
+  Byte byte = b;
+}
+deftype ClassList = list<Class>;
+
+// CHECK:      def test {
+// CHECK-NEXT:   bits<8> byte = { 0, 1, 1, 1, 1, 0, 1, 1 };
+// CHECK-NEXT:   list<int> ints = [1, 2, 3];
+// CHECK-NEXT:   list<bits<8>> bytes = [{ 0, 0, 0, 0, 0, 0, 0, 1 }, { 0, 0, 0, 0, 0, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 1, 1 }];
+// CHECK-NEXT:   list<Class> defs = [anonymous_0, anonymous_1, anonymous_2];
+// CHECK-NEXT: }
+def test {
+  Byte byte = 123;
+  IntList ints = [1, 2, 3];
+  ByteList bytes = [1, 2, 3];
+  ClassList defs = [Class<1>, Class<2>, Class<3>];
+}

>From 3f642857652aeecc140eaf0641e73f789945f733 Mon Sep 17 00:00:00 2001
From: wangpc <wangpengcheng.pp at bytedance.com>
Date: Fri, 26 Jan 2024 18:29:19 +0800
Subject: [PATCH 2/7] Reword doc

Created using spr 1.3.4
---
 llvm/docs/TableGen/ProgRef.rst | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/llvm/docs/TableGen/ProgRef.rst b/llvm/docs/TableGen/ProgRef.rst
index f1bbe32ec2047..41196d7cdc6ce 100644
--- a/llvm/docs/TableGen/ProgRef.rst
+++ b/llvm/docs/TableGen/ProgRef.rst
@@ -931,8 +931,7 @@ template that expands into multiple records.
              : `ParentClassList`
              : "{" `MultiClassStatement`+ "}"
    MultiClassID: `TokIdentifier`
-   MultiClassStatement: `Assert` | `Def` | `Defm` | `Deftype` | `Defvar`
-                      :| `Foreach` | `If` | `Let`
+   MultiClassStatement: `Assert` | `Def` | `Defm` | `Defvar` | `Foreach` | `If` | `Let`
 
 As with regular classes, the multiclass has a name and can accept template
 arguments. A multiclass can inherit from other multiclasses, which causes
@@ -1219,15 +1218,18 @@ Anonymous records created inside initialization expressions using the
 ``deftype`` --- define a type
 --------------------------------
 
-A ``deftype`` statement defines a type. Its value can be used
-throughout the statements that follow the definition.
+A ``deftype`` statement defines a type. The type can be used throughout the
+statements that follow the definition.
 
 .. productionlist::
-   Deftype: "deftype" `TokIdentifier` "=" `Value` ";"
+   Deftype: "deftype" `TokIdentifier` "=" `Type` ";"
 
 The identifier on the left of the ``=`` is defined to be a type name
 whose actual type is given by the type expression on the right of the ``=``.
 
+Currently, only primitive types are supported and ``deftype`` statements can
+only appear at the top level.
+
 ``defvar`` --- define a variable
 --------------------------------
 

>From 14e3e83472c4d9391709e35dc29bce0735634a10 Mon Sep 17 00:00:00 2001
From: wangpc <wangpengcheng.pp at bytedance.com>
Date: Fri, 26 Jan 2024 18:37:15 +0800
Subject: [PATCH 3/7] Type name should not be conflict with exited class

Created using spr 1.3.4
---
 llvm/lib/TableGen/TGParser.cpp |  4 ++--
 llvm/test/TableGen/deftype.td  | 12 ++++++++++++
 2 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp
index 1574505ded33a..f6d82cddc6a05 100644
--- a/llvm/lib/TableGen/TGParser.cpp
+++ b/llvm/lib/TableGen/TGParser.cpp
@@ -3683,8 +3683,8 @@ bool TGParser::ParseDeftype() {
     return TokError("expected identifier");
 
   std::string TypeName = Lex.getCurStrVal();
-  if (TypeAliases.count(TypeName))
-    return TokError("type of this name already exists");
+  if (TypeAliases.count(TypeName) || Records.getClass(TypeName))
+    return TokError("type of this name '" + TypeName + "' already exists");
 
   Lex.Lex();
   if (!consume(tgtok::equal))
diff --git a/llvm/test/TableGen/deftype.td b/llvm/test/TableGen/deftype.td
index ee430cbdaf7a2..baf403e27ab04 100644
--- a/llvm/test/TableGen/deftype.td
+++ b/llvm/test/TableGen/deftype.td
@@ -1,4 +1,6 @@
 // RUN: llvm-tblgen %s | FileCheck %s
+// RUN: not llvm-tblgen -DERROR1 %s 2>&1 | FileCheck --check-prefix=ERROR1 %s
+// RUN: not llvm-tblgen -DERROR2 %s 2>&1 | FileCheck --check-prefix=ERROR2 %s
 
 deftype Byte = bits<8>;
 deftype IntList = list<int>;
@@ -20,3 +22,13 @@ def test {
   ByteList bytes = [1, 2, 3];
   ClassList defs = [Class<1>, Class<2>, Class<3>];
 }
+
+#ifdef ERROR1
+// ERROR1: [[@LINE+1]]:9: error: type of this name 'Byte' already exists
+deftype Byte = bits<8>;
+#endif
+
+#ifdef ERROR2
+// ERROR2: [[@LINE+1]]:9: error: type of this name 'Class' already exists
+deftype Class = int;
+#endif

>From 96f1649803d6cef1aaa2222481b2b9921d5dc08d Mon Sep 17 00:00:00 2001
From: wangpc <wangpengcheng.pp at bytedance.com>
Date: Mon, 29 Jan 2024 16:15:49 +0800
Subject: [PATCH 4/7] Address comments and add more tests

Created using spr 1.3.4
---
 llvm/docs/TableGen/ProgRef.rst |  4 ++--
 llvm/lib/TableGen/TGParser.cpp |  8 ++++++-
 llvm/test/TableGen/deftype.td  | 44 ++++++++++++++++++++++++++--------
 3 files changed, 43 insertions(+), 13 deletions(-)

diff --git a/llvm/docs/TableGen/ProgRef.rst b/llvm/docs/TableGen/ProgRef.rst
index 41196d7cdc6ce..45fda317ef643 100644
--- a/llvm/docs/TableGen/ProgRef.rst
+++ b/llvm/docs/TableGen/ProgRef.rst
@@ -1227,8 +1227,8 @@ statements that follow the definition.
 The identifier on the left of the ``=`` is defined to be a type name
 whose actual type is given by the type expression on the right of the ``=``.
 
-Currently, only primitive types are supported and ``deftype`` statements can
-only appear at the top level.
+Currently, only primitive types and type aliases are supported to be the source
+type and `deftype` statements can only appear at the top level.
 
 ``defvar`` --- define a variable
 --------------------------------
diff --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp
index f6d82cddc6a05..0f054c8fdd539 100644
--- a/llvm/lib/TableGen/TGParser.cpp
+++ b/llvm/lib/TableGen/TGParser.cpp
@@ -3673,7 +3673,7 @@ bool TGParser::ParseDefset() {
 
 /// ParseDeftype - Parse a defvar statement.
 ///
-///   Deftype ::= DEFTYPE Id '=' Value ';'
+///   Deftype ::= DEFTYPE Id '=' Type ';'
 ///
 bool TGParser::ParseDeftype() {
   assert(Lex.getCode() == tgtok::Deftype);
@@ -3690,9 +3690,15 @@ bool TGParser::ParseDeftype() {
   if (!consume(tgtok::equal))
     return TokError("expected '='");
 
+  SMLoc Loc = Lex.getLoc();
   RecTy *Type = ParseType();
   if (!Type)
     return true;
+
+  if (Type->getRecTyKind() == RecTy::RecordRecTyKind)
+    return Error(Loc, "cannot define type alias for class type '" +
+                          Type->getAsString() + "'");
+
   TypeAliases[TypeName] = Type;
 
   if (!consume(tgtok::semi))
diff --git a/llvm/test/TableGen/deftype.td b/llvm/test/TableGen/deftype.td
index baf403e27ab04..666c3a2a57d96 100644
--- a/llvm/test/TableGen/deftype.td
+++ b/llvm/test/TableGen/deftype.td
@@ -1,26 +1,45 @@
 // RUN: llvm-tblgen %s | FileCheck %s
 // RUN: not llvm-tblgen -DERROR1 %s 2>&1 | FileCheck --check-prefix=ERROR1 %s
 // RUN: not llvm-tblgen -DERROR2 %s 2>&1 | FileCheck --check-prefix=ERROR2 %s
+// RUN: not llvm-tblgen -DERROR3 %s 2>&1 | FileCheck --check-prefix=ERROR3 %s
 
-deftype Byte = bits<8>;
-deftype IntList = list<int>;
-deftype ByteList = list<Byte>;
-class Class<Byte b> {
-  Byte byte = b;
+class Class<int v> {
+  int value = v;
 }
-deftype ClassList = list<Class>;
+
+deftype StringAlias    = string;
+deftype CodeAlias      = code;
+deftype DagAlias       = dag;
+deftype Boolean        = bit;
+deftype Byte           = bits<8>;
+deftype Integer        = int;
+deftype IntList        = list<int>;
+deftype ByteList       = list<Byte>;
+deftype ClassList      = list<Class>;
+// The type can be another type alias.
+deftype ClassListAlias = ClassList;
 
 // CHECK:      def test {
+// CHECK-NEXT:   string str = "string";
+// CHECK-NEXT:   string codeStr = "code";
+// CHECK-NEXT:   dag dagExpr = ("string" "code");
+// CHECK-NEXT:   bit bool = 0;
 // CHECK-NEXT:   bits<8> byte = { 0, 1, 1, 1, 1, 0, 1, 1 };
+// CHECK-NEXT:   int integer = 123;
 // CHECK-NEXT:   list<int> ints = [1, 2, 3];
 // CHECK-NEXT:   list<bits<8>> bytes = [{ 0, 0, 0, 0, 0, 0, 0, 1 }, { 0, 0, 0, 0, 0, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 1, 1 }];
 // CHECK-NEXT:   list<Class> defs = [anonymous_0, anonymous_1, anonymous_2];
 // CHECK-NEXT: }
 def test {
-  Byte byte = 123;
-  IntList ints = [1, 2, 3];
-  ByteList bytes = [1, 2, 3];
-  ClassList defs = [Class<1>, Class<2>, Class<3>];
+  StringAlias    str     = "string";
+  CodeAlias      codeStr = "code";
+  DagAlias       dagExpr = (str codeStr);
+  Boolean        bool    = false;
+  Byte           byte    = 123;
+  Integer        integer = 123;
+  IntList        ints    = [1, 2, 3];
+  ByteList       bytes   = [1, 2, 3];
+  ClassListAlias defs    = [Class<1>, Class<2>, Class<3>];
 }
 
 #ifdef ERROR1
@@ -32,3 +51,8 @@ deftype Byte = bits<8>;
 // ERROR2: [[@LINE+1]]:9: error: type of this name 'Class' already exists
 deftype Class = int;
 #endif
+
+#ifdef ERROR3
+// ERROR3: [[@LINE+1]]:22: error: cannot define type alias for class type 'Class'
+deftype ClassAlias = Class;
+#endif

>From 5031d0495e408f141e9c7457463b5af505974d61 Mon Sep 17 00:00:00 2001
From: wangpc <wangpengcheng.pp at bytedance.com>
Date: Tue, 30 Jan 2024 14:41:39 +0800
Subject: [PATCH 5/7] Add const to TypeName

Created using spr 1.3.4
---
 llvm/lib/TableGen/TGParser.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp
index 0f054c8fdd539..01e69ca589e3f 100644
--- a/llvm/lib/TableGen/TGParser.cpp
+++ b/llvm/lib/TableGen/TGParser.cpp
@@ -1104,7 +1104,7 @@ RecTy *TGParser::ParseType() {
     Lex.Lex();
     return DagRecTy::get(Records);
   case tgtok::Id: {
-    std::string TypeName = Lex.getCurStrVal();
+    const std::string TypeName = Lex.getCurStrVal();
     if (TypeAliases.count(TypeName)) {
       Lex.Lex();
       return TypeAliases[TypeName];
@@ -3682,7 +3682,7 @@ bool TGParser::ParseDeftype() {
   if (Lex.getCode() != tgtok::Id)
     return TokError("expected identifier");
 
-  std::string TypeName = Lex.getCurStrVal();
+  const std::string TypeName = Lex.getCurStrVal();
   if (TypeAliases.count(TypeName) || Records.getClass(TypeName))
     return TokError("type of this name '" + TypeName + "' already exists");
 

>From e36c58e8f01b600afcb3a006636d70e080e74227 Mon Sep 17 00:00:00 2001
From: wangpc <wangpengcheng.pp at bytedance.com>
Date: Tue, 30 Jan 2024 16:02:22 +0800
Subject: [PATCH 6/7] Use find

Created using spr 1.3.4
---
 llvm/lib/TableGen/TGParser.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp
index 01e69ca589e3f..2fe98d22870c8 100644
--- a/llvm/lib/TableGen/TGParser.cpp
+++ b/llvm/lib/TableGen/TGParser.cpp
@@ -1104,10 +1104,10 @@ RecTy *TGParser::ParseType() {
     Lex.Lex();
     return DagRecTy::get(Records);
   case tgtok::Id: {
-    const std::string TypeName = Lex.getCurStrVal();
-    if (TypeAliases.count(TypeName)) {
+    auto I = TypeAliases.find(Lex.getCurStrVal());
+    if (I != TypeAliases.end()) {
       Lex.Lex();
-      return TypeAliases[TypeName];
+      return I->second;
     }
     if (Record *R = ParseClassID())
       return RecordRecTy::get(R);

>From b1fdd69296b39f041335eee0e7298df6adbe7f7d Mon Sep 17 00:00:00 2001
From: wangpc <wangpengcheng.pp at bytedance.com>
Date: Thu, 1 Feb 2024 14:12:34 +0800
Subject: [PATCH 7/7] check class conflict with alias; add release note

Created using spr 1.3.4
---
 llvm/docs/ReleaseNotes.rst     |  2 ++
 llvm/lib/TableGen/TGParser.cpp |  7 ++++++-
 llvm/test/TableGen/deftype.td  | 12 ++++++++++++
 3 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst
index 300c9687e8c00..0e3924f4de3cb 100644
--- a/llvm/docs/ReleaseNotes.rst
+++ b/llvm/docs/ReleaseNotes.rst
@@ -59,6 +59,8 @@ Changes to building LLVM
 Changes to TableGen
 -------------------
 
+- We can define type aliases via new keyword ``deftype``.
+
 Changes to Interprocedural Optimizations
 ----------------------------------------
 
diff --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp
index 2fe98d22870c8..f899fdb68f758 100644
--- a/llvm/lib/TableGen/TGParser.cpp
+++ b/llvm/lib/TableGen/TGParser.cpp
@@ -3956,7 +3956,8 @@ bool TGParser::ParseClass() {
   if (Lex.getCode() != tgtok::Id)
     return TokError("expected class name after 'class' keyword");
 
-  Record *CurRec = Records.getClass(Lex.getCurStrVal());
+  const std::string &Name = Lex.getCurStrVal();
+  Record *CurRec = Records.getClass(Name);
   if (CurRec) {
     // If the body was previously defined, this is an error.
     if (!CurRec->getValues().empty() ||
@@ -3973,6 +3974,10 @@ bool TGParser::ParseClass() {
     CurRec = NewRec.get();
     Records.addClass(std::move(NewRec));
   }
+
+  if (TypeAliases.count(Name))
+    return TokError("there is already a defined type alias '" + Name + "'");
+
   Lex.Lex(); // eat the name.
 
   // A class definition introduces a new scope.
diff --git a/llvm/test/TableGen/deftype.td b/llvm/test/TableGen/deftype.td
index 666c3a2a57d96..7323fc77c35dc 100644
--- a/llvm/test/TableGen/deftype.td
+++ b/llvm/test/TableGen/deftype.td
@@ -2,6 +2,8 @@
 // RUN: not llvm-tblgen -DERROR1 %s 2>&1 | FileCheck --check-prefix=ERROR1 %s
 // RUN: not llvm-tblgen -DERROR2 %s 2>&1 | FileCheck --check-prefix=ERROR2 %s
 // RUN: not llvm-tblgen -DERROR3 %s 2>&1 | FileCheck --check-prefix=ERROR3 %s
+// RUN: not llvm-tblgen -DERROR4 %s 2>&1 | FileCheck --check-prefix=ERROR4 %s
+// RUN: not llvm-tblgen -DERROR5 %s 2>&1 | FileCheck --check-prefix=ERROR5 %s
 
 class Class<int v> {
   int value = v;
@@ -56,3 +58,13 @@ deftype Class = int;
 // ERROR3: [[@LINE+1]]:22: error: cannot define type alias for class type 'Class'
 deftype ClassAlias = Class;
 #endif
+
+#ifdef ERROR4
+// ERROR4: [[@LINE+1]]:7: error: there is already a defined type alias 'Byte'
+class Byte; // incomplete class definition.
+#endif
+
+#ifdef ERROR5
+// ERROR5: [[@LINE+1]]:7: error: there is already a defined type alias 'Byte'
+class Byte {}
+#endif



More information about the llvm-commits mailing list