diff --git a/llvm/lib/TableGen/TGLexer.cpp b/llvm/lib/TableGen/TGLexer.cpp index 8fe7f69ecf8e5..b45b037862ef6 100644 --- a/llvm/lib/TableGen/TGLexer.cpp +++ b/llvm/lib/TableGen/TGLexer.cpp @@ -383,6 +383,7 @@ tgtok::TokKind TGLexer::LexIdentifier() { StringRef Str(IdentStart, CurPtr-IdentStart); tgtok::TokKind Kind = StringSwitch(Str) + .Case("auto", tgtok::Auto) .Case("int", tgtok::Int) .Case("bit", tgtok::Bit) .Case("bits", tgtok::Bits) diff --git a/llvm/lib/TableGen/TGLexer.h b/llvm/lib/TableGen/TGLexer.h index 4fa4d84d0535d..a87a2f36b9b69 100644 --- a/llvm/lib/TableGen/TGLexer.h +++ b/llvm/lib/TableGen/TGLexer.h @@ -75,6 +75,7 @@ enum TokKind { // Reserved keywords. ('ElseKW' is named to distinguish it from the // existing 'Else' that means the preprocessor #else.) + Auto, Bit, Bits, Code, diff --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp index 54c9a902ec27a..08d4462140f19 100644 --- a/llvm/lib/TableGen/TGParser.cpp +++ b/llvm/lib/TableGen/TGParser.cpp @@ -3262,13 +3262,19 @@ bool TGParser::ParseTemplateArgValueList( /// /// Declaration ::= FIELD? Type ID ('=' Value)? /// -Init *TGParser::ParseDeclaration(Record *CurRec, - bool ParsingTemplateArgs) { +Init *TGParser::ParseDeclaration(Record *CurRec, bool ParsingTemplateArgs, + bool AllowAuto = false) { // Read the field prefix if present. bool HasField = consume(tgtok::Field); - RecTy *Type = ParseType(); - if (!Type) return nullptr; + RecTy *Type; + if (AllowAuto && consume(tgtok::Auto)) { + Type = nullptr; + } else { + Type = ParseType(); + if (!Type) + return nullptr; + } if (Lex.getCode() != tgtok::Id) { TokError("Expected identifier in declaration"); @@ -3290,6 +3296,32 @@ Init *TGParser::ParseDeclaration(Record *CurRec, Init *DeclName = StringInit::get(Records, Str); Lex.Lex(); + bool HasValue = consume(tgtok::equal); + + // When 'auto' is used, parse the value and infer the type based on the + // value's type. + SMLoc ValLoc; + Init *Val = nullptr; + if (!Type) { + if (!HasValue) { + // auto used without a value. + TokError("auto requires assigning a value"); + return nullptr; + } + ValLoc = Lex.getLoc(); + // When no item type is supplied to ParseValue, it will either infer the + // type from the value, or fail to parse + Val = ParseValue(CurRec); + + // Infer type from the value. + if (TypedInit *TI = dyn_cast_or_null(Val)) { + Type = TI->getType(); + } else { + Error(ValLoc, "unable to infer type"); + return nullptr; + } + } + bool BadField; if (!ParsingTemplateArgs) { // def, possibly in a multiclass BadField = AddValue(CurRec, IdLoc, @@ -3311,10 +3343,14 @@ Init *TGParser::ParseDeclaration(Record *CurRec, if (BadField) return nullptr; - // If a value is present, parse it and set new field's value. - if (consume(tgtok::equal)) { - SMLoc ValLoc = Lex.getLoc(); - Init *Val = ParseValue(CurRec, Type); + // For the non-auto case, if a value is present, parse it. + if (!Val && HasValue) { + ValLoc = Lex.getLoc(); + Val = ParseValue(CurRec, Type); + } + + // Set the new field's value. + if (HasValue) { if (!Val || SetValue(CurRec, ValLoc, DeclName, {}, Val, /*AllowSelfAssignment=*/false, /*OverrideDefLoc=*/false)) { @@ -3423,7 +3459,7 @@ bool TGParser::ParseTemplateArgList(Record *CurRec) { Record *TheRecToAddTo = CurRec ? CurRec : &CurMultiClass->Rec; // Read the first declaration. - Init *TemplArg = ParseDeclaration(CurRec, true/*templateargs*/); + Init *TemplArg = ParseDeclaration(CurRec, /*ParsingTemplateArgs=*/true); if (!TemplArg) return true; @@ -3432,7 +3468,7 @@ bool TGParser::ParseTemplateArgList(Record *CurRec) { while (consume(tgtok::comma)) { // Read the following declarations. SMLoc Loc = Lex.getLoc(); - TemplArg = ParseDeclaration(CurRec, true/*templateargs*/); + TemplArg = ParseDeclaration(CurRec, /*ParsingTemplateArgs=*/true); if (!TemplArg) return true; @@ -3467,7 +3503,9 @@ bool TGParser::ParseBodyItem(Record *CurRec) { return ParseDump(nullptr, CurRec); if (Lex.getCode() != tgtok::Let) { - if (!ParseDeclaration(CurRec, false)) + // Allow 'auto' when parsing declarations in the body of a def or class. + if (!ParseDeclaration(CurRec, /*ParsingTemplateArgs=*/false, + /*AllowAuto=*/true)) return true; if (!consume(tgtok::semi)) diff --git a/llvm/lib/TableGen/TGParser.h b/llvm/lib/TableGen/TGParser.h index b08e250870901..7101cd43b53d5 100644 --- a/llvm/lib/TableGen/TGParser.h +++ b/llvm/lib/TableGen/TGParser.h @@ -280,7 +280,8 @@ class TGParser { bool ParseBodyItem(Record *CurRec); bool ParseTemplateArgList(Record *CurRec); - Init *ParseDeclaration(Record *CurRec, bool ParsingTemplateArgs); + Init *ParseDeclaration(Record *CurRec, bool ParsingTemplateArgs, + bool AllowAuto); VarInit *ParseForeachDeclaration(Init *&ForeachListValue); SubClassReference ParseSubClassReference(Record *CurRec, bool isDefm); diff --git a/llvm/test/TableGen/auto.td b/llvm/test/TableGen/auto.td new file mode 100644 index 0000000000000..b05af8d5c16a7 --- /dev/null +++ b/llvm/test/TableGen/auto.td @@ -0,0 +1,44 @@ +// RUN: llvm-tblgen %s | FileCheck %s --check-prefix=CHECK-PASS +// RUN: not llvm-tblgen -DBAD0 %s 2>&1 | FileCheck %s --check-prefix=CHECK-BAD0 -DFILE=%s +// RUN: not llvm-tblgen -DBAD1 %s 2>&1 | FileCheck %s --check-prefix=CHECK-BAD1 -DFILE=%s + +// CHECK-PASS: int Arg = A:P; +class A { + auto Arg = P; +} + +def MyOp; + +// CHECK-PASS-LABEL: class B +// CHECK-PASS: int A = 10; +// CHECK-PASS: string B = "x"; +// CHECK-PASS: list C = [10, 10]; +// CHECK-PASS{LITERAL}: list> D = [[10, 10], [11, 11]]; +// CHECK-PASS: list F = [anonymous_0, anonymous_1]; +// CHECK-PASS: bits<4> G = { 0, 1, 0, 1 }; +// CHECK-PASS: code H = [{ printf(); }]; +// CHECK-PASS: bits<1> I = { 0 }; +// CHECK-PASS: dag K = (MyOp 10, 100); +// CHECK-PASS: int L = 10; +class B { + auto A = 10; + auto B = "x"; + auto C = [10,10]; + auto D = [[10,10],[11,11]]; +#ifdef BAD0 + // CHECK-BAD0: [[FILE]]:[[@LINE+1]]:12: error: unable to infer type + auto E = []; +#endif + auto F = [A<10>, A<11>]; + auto G = {0,1,0,1}; + auto H = [{ printf(); }]; + // FIXME: This becomes `bits` and not `bit`. + auto I = 0b0; +#ifdef BAD1 + // CHECK-BAD1: [[FILE]]:[[@LINE+1]]:12: error: unable to infer type + auto J = ?; +#endif + auto K = (MyOp 10, 100); + auto L = A<10>.Arg; +} +