From 49d663d5468c144eb7566e81a1a5f598f02a022b Mon Sep 17 00:00:00 2001 From: "Paul C. Anagnostopoulos" Date: Thu, 18 Feb 2021 09:25:30 -0500 Subject: [PATCH] Revert "[TableGen] Improve algorithms for processing template arguments" This reverts commit e589207d5aaee6cbf1d7c7de8867a17727d14aca. --- llvm/docs/TableGen/ProgRef.rst | 21 +- llvm/include/llvm/TableGen/Record.h | 6 - llvm/lib/TableGen/Record.cpp | 14 +- llvm/lib/TableGen/TGParser.cpp | 346 +++++++++++++------------ llvm/lib/TableGen/TGParser.h | 8 +- llvm/test/TableGen/self-reference-typeerror.td | 9 +- llvm/test/TableGen/template-args.td | 142 ---------- 7 files changed, 196 insertions(+), 350 deletions(-) delete mode 100644 llvm/test/TableGen/template-args.td diff --git a/llvm/docs/TableGen/ProgRef.rst b/llvm/docs/TableGen/ProgRef.rst index b6bd88c..f5a7760 100644 --- a/llvm/docs/TableGen/ProgRef.rst +++ b/llvm/docs/TableGen/ProgRef.rst @@ -299,7 +299,7 @@ wide range of records conveniently and compactly. :token:`ClassID` Specifying a class name in a type context indicates that the type of the defined value must - be a subclass of the specified class. This is useful in conjunction with + be a subclass of the specified class. This is useful in conjunction with the ``list`` type; for example, to constrain the elements of the list to a common base class (e.g., a ``list`` can only contain definitions derived from the ``Register`` class). @@ -554,22 +554,19 @@ classes and records can inherit. TemplateArgDecl: `Type` `TokIdentifier` ["=" `Value`] A class can be parameterized by a list of "template arguments," whose values -can be used in the class's record body. These template arguments are +can be used in the class's record body. These template arguments are specified each time the class is inherited by another class or record. If a template argument is not assigned a default value with ``=``, it is uninitialized (has the "value" ``?``) and must be specified in the template -argument list when the class is inherited (required argument). If an -argument is assigned a default value, then it need not be specified in the -argument list (optional argument). In the declaration, all required template -arguments must precede any optional arguments. The template argument default -values are evaluated from left to right. +argument list when the class is inherited. If an argument is assigned a +default value, then it need not be specified in the argument list. The +template argument default values are evaluated from left to right. The :token:`RecordBody` is defined below. It can include a list of -superclasses from which the current class inherits, along with field -definitions and other statements. When a class ``C`` inherits from another -class ``D``, the fields of ``D`` are effectively merged into the fields of -``C``. +superclasses from which the current class inherits, along with field definitions +and other statements. When a class ``C`` inherits from another class ``D``, +the fields of ``D`` are effectively merged into the fields of ``C``. A given class can only be defined once. A ``class`` statement is considered to define the class if *any* of the following are true (the @@ -608,7 +605,7 @@ of the fields of the class or record. RecordBody: `ParentClassList` `Body` ParentClassList: [":" `ParentClassListNE`] ParentClassListNE: `ClassRef` ("," `ClassRef`)* - ClassRef: (`ClassID` | `MultiClassID`) ["<" [`ValueList`] ">"] + ClassRef: (`ClassID` | `MultiClassID`) ["<" `ValueList` ">"] A :token:`ParentClassList` containing a :token:`MultiClassID` is valid only in the class list of a ``defm`` statement. In that case, the ID must be the diff --git a/llvm/include/llvm/TableGen/Record.h b/llvm/include/llvm/TableGen/Record.h index ea47d67..e75b7f0 100644 --- a/llvm/include/llvm/TableGen/Record.h +++ b/llvm/include/llvm/TableGen/Record.h @@ -2024,12 +2024,6 @@ public: void set(Init *Key, Init *Value) { Map[Key] = {Value, false}; } - bool isComplete(Init *VarName) const { - auto It = Map.find(VarName); - assert(It != Map.end() && "key must be present in map"); - return It->second.V->isComplete(); - } - Init *resolve(Init *VarName) override; }; diff --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp index 3172d71..1321209 100644 --- a/llvm/lib/TableGen/Record.cpp +++ b/llvm/lib/TableGen/Record.cpp @@ -2344,13 +2344,13 @@ void Record::resolveReferences(Resolver &R, const RecordVal *SkipVal) { if (TypedInit *VRT = dyn_cast(VR)) Type = (Twine("of type '") + VRT->getType()->getAsString() + "' ").str(); - PrintFatalError( - getLoc(), - Twine("Invalid value ") + Type + "found when setting field '" + - Value.getNameInitAsString() + "' of type '" + - Value.getType()->getAsString() + - "' after resolving references: " + VR->getAsUnquotedString() + - "\n"); + PrintFatalError(getLoc(), Twine("Invalid value ") + Type + + "is found when setting '" + + Value.getNameInitAsString() + + "' of type '" + + Value.getType()->getAsString() + + "' after resolving references: " + + VR->getAsUnquotedString() + "\n"); } } } diff --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp index 974df42..87faf77 100644 --- a/llvm/lib/TableGen/TGParser.cpp +++ b/llvm/lib/TableGen/TGParser.cpp @@ -229,33 +229,38 @@ bool TGParser::SetValue(Record *CurRec, SMLoc Loc, Init *ValName, /// args as SubClass's template arguments. bool TGParser::AddSubClass(Record *CurRec, SubClassReference &SubClass) { Record *SC = SubClass.Rec; + // Add all of the values in the subclass into the current class. + for (const RecordVal &Val : SC->getValues()) + if (AddValue(CurRec, SubClass.RefRange.Start, Val)) + return true; + + ArrayRef TArgs = SC->getTemplateArgs(); + + // Ensure that an appropriate number of template arguments are specified. + if (TArgs.size() < SubClass.TemplateArgs.size()) + return Error(SubClass.RefRange.Start, + "More template args specified than expected"); + + // Loop over all of the template arguments, setting them to the specified + // value or leaving them as the default if necessary. MapResolver R(CurRec); - // Loop over all the subclass record's fields. Add template arguments - // to the resolver map. Add regular fields to the new record. - for (const RecordVal &Field : SC->getValues()) { - if (Field.isTemplateArg()) { - R.set(Field.getNameInit(), Field.getValue()); - } else { - if (AddValue(CurRec, SubClass.RefRange.Start, Field)) + for (unsigned i = 0, e = TArgs.size(); i != e; ++i) { + if (i < SubClass.TemplateArgs.size()) { + // If a value is specified for this template arg, set it now. + if (SetValue(CurRec, SubClass.RefRange.Start, TArgs[i], + None, SubClass.TemplateArgs[i])) return true; + } else if (!CurRec->getValue(TArgs[i])->getValue()->isComplete()) { + return Error(SubClass.RefRange.Start, + "Value not specified for template argument #" + + Twine(i) + " (" + TArgs[i]->getAsUnquotedString() + + ") of subclass '" + SC->getNameInitAsString() + "'!"); } - } - ArrayRef TArgs = SC->getTemplateArgs(); - assert(SubClass.TemplateArgs.size() <= TArgs.size() && - "Too many template arguments allowed"); - - // Loop over the template argument names. If a value was specified, - // reset the map value. If not and there was no default, complain. - for (unsigned I = 0, E = TArgs.size(); I != E; ++I) { - if (I < SubClass.TemplateArgs.size()) - R.set(TArgs[I], SubClass.TemplateArgs[I]); - else if (!R.isComplete(TArgs[I])) - return Error(SubClass.RefRange.Start, - "Value not specified for template argument '" + - TArgs[I]->getAsUnquotedString() + "' (#" + Twine(I) + - ") of parent class '" + SC->getNameInitAsString() + "'"); + R.set(TArgs[i], CurRec->getValue(TArgs[i])->getValue()); + + CurRec->removeValue(TArgs[i]); } Init *Name; @@ -579,8 +584,8 @@ MultiClass *TGParser::ParseMultiClassID() { return Result; } -/// ParseSubClassReference - Parse a reference to a subclass or a -/// multiclass. This returns a SubClassRefTy with a null Record* on error. +/// ParseSubClassReference - Parse a reference to a subclass or to a templated +/// subclass. This returns a SubClassRefTy with a null Record* on error. /// /// SubClassRef ::= ClassID /// SubClassRef ::= ClassID '<' ValueList '>' @@ -604,18 +609,25 @@ ParseSubClassReference(Record *CurRec, bool isDefm) { return Result; } - if (ParseTemplateArgValueList(Result.TemplateArgs, CurRec, Result.Rec)) { - Result.Rec = nullptr; // Error parsing value list. + if (Lex.getCode() == tgtok::greater) { + TokError("subclass reference requires a non-empty list of template values"); + Result.Rec = nullptr; return Result; } - if (CheckTemplateArgValues(Result.TemplateArgs, Result.RefRange.Start, - Result.Rec)) { - Result.Rec = nullptr; // Error checking value list. + ParseValueList(Result.TemplateArgs, CurRec, Result.Rec); + if (Result.TemplateArgs.empty()) { + Result.Rec = nullptr; // Error parsing value list. return Result; } + if (!consume(tgtok::greater)) { + TokError("expected '>' in template value list"); + Result.Rec = nullptr; + return Result; + } Result.RefRange.End = Lex.getLoc(); + return Result; } @@ -640,12 +652,23 @@ ParseSubMultiClassReference(MultiClass *CurMC) { return Result; } - if (ParseTemplateArgValueList(Result.TemplateArgs, &CurMC->Rec, - &Result.MC->Rec)) { - Result.MC = nullptr; // Error parsing value list. + if (Lex.getCode() == tgtok::greater) { + TokError("subclass reference requires a non-empty list of template values"); + Result.MC = nullptr; return Result; } + ParseValueList(Result.TemplateArgs, &CurMC->Rec, &Result.MC->Rec); + if (Result.TemplateArgs.empty()) { + Result.MC = nullptr; // Error parsing value list. + return Result; + } + + if (!consume(tgtok::greater)) { + TokError("expected '>' in template value list"); + Result.MC = nullptr; + return Result; + } Result.RefRange.End = Lex.getLoc(); return Result; @@ -2009,9 +2032,15 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType, if (Lex.Lex() != tgtok::less) // consume the Id. return ParseIDValue(CurRec, Name, NameLoc, Mode); // Value ::= IDValue - // Value ::= CLASSID '<' ValueListNE '>' (CLASSID has been consumed) - // This is supposed to synthesize a new anonymous definition, deriving - // from the class with the template arguments, but no body. + // Value ::= ID '<' ValueListNE '>' + if (Lex.Lex() == tgtok::greater) { + TokError("expected non-empty value list"); + return nullptr; + } + + // This is a CLASS expression. This is supposed to synthesize + // a new anonymous definition, deriving from CLASS with no + // body. Record *Class = Records.getClass(Name->getValue()); if (!Class) { Error(NameLoc, "Expected a class name, got '" + Name->getValue() + "'"); @@ -2019,26 +2048,44 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType, } SmallVector Args; - Lex.Lex(); // consume the < - if (ParseTemplateArgValueList(Args, CurRec, Class)) - return nullptr; // Error parsing value list. - - if (CheckTemplateArgValues(Args, NameLoc, Class)) - return nullptr; // Error checking template argument values. - - // Loop through the arguments that were not specified and make sure - // they have a complete value. - // TODO: If we just keep a required argument count, we can do away - // with this checking. - ArrayRef 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() + "'"); - + ParseValueList(Args, CurRec, Class); + if (Args.empty()) return nullptr; + + if (!consume(tgtok::greater)) { + TokError("expected '>' at end of value list"); + return nullptr; + } + + // Typecheck the template arguments list + ArrayRef ExpectedArgs = Class->getTemplateArgs(); + if (ExpectedArgs.size() < Args.size()) { + Error(NameLoc, + "More template args specified than expected"); + return nullptr; + } + + for (unsigned i = 0, e = ExpectedArgs.size(); i != e; ++i) { + RecordVal *ExpectedArg = Class->getValue(ExpectedArgs[i]); + if (i < Args.size()) { + if (TypedInit *TI = dyn_cast(Args[i])) { + RecTy *ExpectedType = ExpectedArg->getType(); + if (!TI->getType()->typeIsConvertibleTo(ExpectedType)) { + Error(NameLoc, + "Value specified for template argument #" + Twine(i) + " (" + + ExpectedArg->getNameInitAsString() + ") is of type '" + + TI->getType()->getAsString() + "', expected '" + + ExpectedType->getAsString() + "': " + TI->getAsString()); + return nullptr; + } + continue; + } + } else if (ExpectedArg->getValue()->isComplete()) + continue; + + Error(NameLoc, + "Value not specified for template argument #" + Twine(i) + " (" + + ExpectedArgs[i]->getAsUnquotedString() + ")"); + return nullptr; } return VarDefInit::get(Class, Args)->Fold(); @@ -2111,7 +2158,7 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType, } if (Lex.getCode() != tgtok::r_square) { - ParseValueList(Vals, CurRec, + ParseValueList(Vals, CurRec, nullptr, GivenListTy ? GivenListTy->getElementType() : nullptr); if (Vals.empty()) return nullptr; } @@ -2475,15 +2522,32 @@ void TGParser::ParseDagArgList( } } -/// ParseValueList - Parse a comma separated list of values, returning them -/// in a vector. Note that this always expects to be able to parse at least one -/// value. It returns an empty list if this is not possible. +/// ParseValueList - Parse a comma separated list of values, returning them as a +/// vector. Note that this always expects to be able to parse at least one +/// value. It returns an empty list if this is not possible. /// /// ValueList ::= Value (',' Value) /// -void TGParser::ParseValueList(SmallVectorImpl &Result, Record *CurRec, - RecTy *ItemType) { - +void TGParser::ParseValueList(SmallVectorImpl &Result, Record *CurRec, + Record *ArgsRec, RecTy *EltTy) { + RecTy *ItemType = EltTy; + unsigned int ArgN = 0; + if (ArgsRec && !EltTy) { + ArrayRef TArgs = ArgsRec->getTemplateArgs(); + if (TArgs.empty()) { + TokError("template argument provided to non-template class"); + Result.clear(); + return; + } + const RecordVal *RV = ArgsRec->getValue(TArgs[ArgN]); + if (!RV) { + errs() << "Cannot find template arg " << ArgN << " (" << TArgs[ArgN] + << ")\n"; + } + assert(RV && "Template argument record not found??"); + ItemType = RV->getType(); + ++ArgN; + } Result.push_back(ParseValue(CurRec, ItemType)); if (!Result.back()) { Result.clear(); @@ -2494,6 +2558,19 @@ void TGParser::ParseValueList(SmallVectorImpl &Result, Record *CurRec, // ignore trailing comma for lists if (Lex.getCode() == tgtok::r_square) return; + + if (ArgsRec && !EltTy) { + ArrayRef TArgs = ArgsRec->getTemplateArgs(); + if (ArgN >= TArgs.size()) { + TokError("too many template arguments"); + Result.clear(); + return; + } + const RecordVal *RV = ArgsRec->getValue(TArgs[ArgN]); + assert(RV && "Template argument record not found??"); + ItemType = RV->getType(); + ++ArgN; + } Result.push_back(ParseValue(CurRec, ItemType)); if (!Result.back()) { Result.clear(); @@ -2502,48 +2579,9 @@ void TGParser::ParseValueList(SmallVectorImpl &Result, Record *CurRec, } } -// ParseTemplateArgValueList - Parse a template argument list with the syntax -// shown, filling in the Result vector. The open angle has been consumed. -// An empty argument list is allowed. Return false if okay, true if an -// error was detected. -// -// TemplateArgList ::= '<' [Value {',' Value}*] '>' -bool TGParser::ParseTemplateArgValueList(SmallVectorImpl &Result, - Record *CurRec, Record *ArgsRec) { - - assert(Result.empty() && "Result vector is not empty"); - ArrayRef TArgs = ArgsRec->getTemplateArgs(); - unsigned ArgIndex = 0; - RecTy *ItemType; - - if (consume(tgtok::greater)) // empty value list - return false; - - while (true) { - if (ArgIndex >= TArgs.size()) { - TokError("Too many template arguments: " + utostr(ArgIndex + 1)); - return true; - } - const RecordVal *Arg = ArgsRec->getValue(TArgs[ArgIndex]); - assert(Arg && "Template argument record not found"); - - ItemType = Arg->getType(); - Init *Value = ParseValue(CurRec, ItemType); - if (!Value) - return true; - Result.push_back(Value); - - if (consume(tgtok::greater)) // end of argument list? - return false; - if (!consume(tgtok::comma)) // must be comma - return true; - ++ArgIndex; - } -} - /// ParseDeclaration - Read a declaration, returning the name of field ID, or an -/// empty string on error. This can happen in a number of different contexts, -/// including within a def or in the template args for a class (in which case +/// empty string on error. This can happen in a number of different context's, +/// including within a def or in the template args for a def (which which case /// CurRec will be non-null) and within the template args for a multiclass (in /// which case CurRec will be null, but CurMultiClass will be set). This can /// also happen within a def that is within a multiclass, which will set both @@ -2574,28 +2612,23 @@ Init *TGParser::ParseDeclaration(Record *CurRec, Init *DeclName = StringInit::get(Str); Lex.Lex(); - bool BadField; - if (!ParsingTemplateArgs) { // def, possibly in a multiclass - BadField = AddValue(CurRec, IdLoc, - RecordVal(DeclName, IdLoc, Type, - HasField ? RecordVal::FK_NonconcreteOK - : RecordVal::FK_Normal)); - - } else if (CurRec) { // class template argument - DeclName = QualifyName(*CurRec, CurMultiClass, DeclName, ":"); - BadField = AddValue(CurRec, IdLoc, RecordVal(DeclName, IdLoc, Type, - RecordVal::FK_TemplateArg)); - - } else { // multiclass template argument - assert(CurMultiClass && "invalid context for template argument"); - DeclName = QualifyName(CurMultiClass->Rec, CurMultiClass, DeclName, "::"); - BadField = AddValue(CurRec, IdLoc, RecordVal(DeclName, IdLoc, Type, - RecordVal::FK_TemplateArg)); - } - if (BadField) + if (ParsingTemplateArgs) { + if (CurRec) + DeclName = QualifyName(*CurRec, CurMultiClass, DeclName, ":"); + else + assert(CurMultiClass); + if (CurMultiClass) + DeclName = QualifyName(CurMultiClass->Rec, CurMultiClass, DeclName, + "::"); + } + + // Add the field to the record. + if (AddValue(CurRec, IdLoc, RecordVal(DeclName, IdLoc, Type, + HasField ? RecordVal::FK_NonconcreteOK + : RecordVal::FK_Normal))) return nullptr; - // If a value is present, parse it and set new field's value. + // If a value is present, parse it. if (consume(tgtok::equal)) { SMLoc ValLoc = Lex.getLoc(); Init *Val = ParseValue(CurRec, Type); @@ -2682,7 +2715,7 @@ VarInit *TGParser::ParseForeachDeclaration(Init *&ForeachListValue) { if (!Ranges.empty()) { assert(!IterType && "Type already initialized?"); IterType = IntRecTy::get(); - std::vector Values; + std::vector Values; for (unsigned R : Ranges) Values.push_back(IntInit::get(R)); ForeachListValue = ListInit::get(Values, IterType); @@ -2696,7 +2729,7 @@ VarInit *TGParser::ParseForeachDeclaration(Init *&ForeachListValue) { /// ParseTemplateArgList - Read a template argument list, which is a non-empty /// sequence of template-declarations in <>'s. If CurRec is non-null, these are -/// template args for a class, which may or may not be in a multiclass. If null, +/// template args for a def, which may or may not be in a multiclass. If null, /// these are the template args for a multiclass. /// /// TemplateArgList ::= '<' Declaration (',' Declaration)* '>' @@ -3460,28 +3493,32 @@ bool TGParser::ParseDefm(MultiClass *CurMultiClass) { while (true) { if (!Ref.Rec) return true; - // To instantiate a multiclass, we get the multiclass and then loop - // through its template argument names. Substs contains a substitution - // value for each argument, either the value specified or the default. - // Then we can resolve the template arguments. + // To instantiate a multiclass, we need to first get the multiclass, then + // instantiate each def contained in the multiclass with the SubClassRef + // template parameters. MultiClass *MC = MultiClasses[std::string(Ref.Rec->getName())].get(); assert(MC && "Didn't lookup multiclass correctly?"); + ArrayRef TemplateVals = Ref.TemplateArgs; - ArrayRef TemplateVals = Ref.TemplateArgs; + // Verify that the correct number of template arguments were specified. ArrayRef TArgs = MC->Rec.getTemplateArgs(); - SubstStack Substs; + if (TArgs.size() < TemplateVals.size()) + return Error(SubClassLoc, + "more template args specified than multiclass expects"); + SubstStack Substs; for (unsigned i = 0, e = TArgs.size(); i != e; ++i) { if (i < TemplateVals.size()) { Substs.emplace_back(TArgs[i], TemplateVals[i]); } else { Init *Default = MC->Rec.getValue(TArgs[i])->getValue(); - if (!Default->isComplete()) + if (!Default->isComplete()) { return Error(SubClassLoc, - "value not specified for template argument '" + - TArgs[i]->getAsUnquotedString() + "' (#" + - Twine(i) + ") of multiclass '" + - MC->Rec.getNameInitAsString() + "'"); + "value not specified for template argument #" + + Twine(i) + " (" + TArgs[i]->getAsUnquotedString() + + ") of multiclass '" + MC->Rec.getNameInitAsString() + + "'"); + } Substs.emplace_back(TArgs[i], Default); } } @@ -3500,7 +3537,7 @@ bool TGParser::ParseDefm(MultiClass *CurMultiClass) { SubClassLoc = Lex.getLoc(); - // A defm can inherit from regular classes (non-multiclasses) as + // A defm can inherit from regular classes (non-multiclass) as // long as they come in the end of the inheritance list. InheritFromClass = (Records.getClass(Lex.getCurStrVal()) != nullptr); @@ -3605,41 +3642,6 @@ bool TGParser::ParseFile() { return TokError("Unexpected token at top level"); } -// Check the types of the template argument values for a class -// inheritance, multiclass invocation, or anonymous class invocation. -// If necessary, replace an argument with a cast to the required type. -// The argument count has already been checked. -bool TGParser::CheckTemplateArgValues(SmallVectorImpl &Values, - SMLoc Loc, Record *ArgsRec) { - - ArrayRef TArgs = ArgsRec->getTemplateArgs(); - - for (unsigned I = 0, E = Values.size(); I < E; ++I) { - RecordVal *Arg = ArgsRec->getValue(TArgs[I]); - RecTy *ArgType = Arg->getType(); - auto *Value = Values[I]; - - if (TypedInit *ArgValue = dyn_cast(Value)) { - auto *CastValue = ArgValue->getCastTo(ArgType); - if (CastValue) { - assert((!isa(CastValue) || - cast(CastValue)->getType()->typeIsA(ArgType)) && - "result of template arg value cast has wrong type"); - Values[I] = CastValue; - } else { - PrintFatalError(Loc, - "Value specified for template argument '" + - Arg->getNameInitAsString() + "' (#" + Twine(I) + - ") is of type " + ArgValue->getType()->getAsString() + - "; expected type " + ArgType->getAsString() + ": " + - ArgValue->getAsString()); - } - } - } - - return false; -} - // Check an assertion: Obtain the condition value and be sure it is true. // If not, print a nonfatal error along with the message. void TGParser::CheckAssert(SMLoc Loc, Init *Condition, Init *Message) { diff --git a/llvm/lib/TableGen/TGParser.h b/llvm/lib/TableGen/TGParser.h index 5b847ab..578a56c 100644 --- a/llvm/lib/TableGen/TGParser.h +++ b/llvm/lib/TableGen/TGParser.h @@ -243,10 +243,8 @@ private: // Parser methods. IDParseMode Mode = ParseValueMode); Init *ParseValue(Record *CurRec, RecTy *ItemType = nullptr, IDParseMode Mode = ParseValueMode); - void ParseValueList(SmallVectorImpl &Result, - Record *CurRec, RecTy *ItemType = nullptr); - bool ParseTemplateArgValueList(SmallVectorImpl &Result, - Record *CurRec, Record *ArgsRec); + void ParseValueList(SmallVectorImpl &Result, Record *CurRec, + Record *ArgsRec = nullptr, RecTy *EltTy = nullptr); void ParseDagArgList( SmallVectorImpl> &Result, Record *CurRec); @@ -266,8 +264,6 @@ private: // Parser methods. MultiClass *ParseMultiClassID(); bool ApplyLetStack(Record *CurRec); bool ApplyLetStack(RecordsEntry &Entry); - bool CheckTemplateArgValues(SmallVectorImpl &Values, - SMLoc Loc, Record *ArgsRec); void CheckAssert(SMLoc Loc, Init *Condition, Init *Message); void CheckRecordAsserts(Record &Rec); }; diff --git a/llvm/test/TableGen/self-reference-typeerror.td b/llvm/test/TableGen/self-reference-typeerror.td index 6f8da4d..35c6131 100644 --- a/llvm/test/TableGen/self-reference-typeerror.td +++ b/llvm/test/TableGen/self-reference-typeerror.td @@ -1,14 +1,13 @@ // RUN: not llvm-tblgen %s 2>&1 | FileCheck %s // XFAIL: vg_leak -class Cl { - Cl Arec = rec; +class A { + A a = x; } // At the time A0 is referenced, A has not yet been established as a superclass. // This kind of self-reference is discourage, but if you *really* want it, you // can force it with !cast. // -// CHECK: alue specified for template argument 'Cl:rec' - -def Rec0 : Cl; +// CHECK: Field 'A:x' of type 'A' is incompatible with value +def A0 : A; diff --git a/llvm/test/TableGen/template-args.td b/llvm/test/TableGen/template-args.td deleted file mode 100644 index 2a931ad..0000000 --- a/llvm/test/TableGen/template-args.td +++ /dev/null @@ -1,142 +0,0 @@ -// 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 -// 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 -// RUN: not llvm-tblgen -DERROR6 %s 2>&1 | FileCheck --check-prefix=ERROR6 %s - -// This file tests that template arguments are type-checked and cast -// if necessary. - -// Class template arguments. - -class Class1 { - string Name = nm; -} - -// CHECK: def Rec1 -// CHECK: string Name = "Alice" -// CHECK: string NameName = "AliceAlice" - -def Rec1 : Class1<"Alice"> { - string NameName = Name # Name; -} - -#ifdef ERROR1 -// ERROR1: Value specified for template argument 'Class1:nm' (#0) is of type int - -def Rec2 : Class1<42> { -} -#endif - -class Class2 cd> { - int Code = cd; -} - -// CHECK: def Rec3 -// CHECK: int Code = 42 -// CHECK: list CodeList = [42] - -def Rec3 : Class2<0b00101010> { - list CodeList = [Code]; -} - -// CHECK: def Rec4 -// CHECK: int Code = 42 -// CHECK: list CodeList = [42] - -def Rec4 : Class2<42> { - list CodeList = [Code]; -} - -#ifdef ERROR2 -// ERROR2: Value specified for template argument 'Class2:cd' (#0) is of type string - -def Rec5 : Class2<"oops"> { - list CodeList = [Code]; -} -#endif - -// Anonymous class instantiation template arguments. - -// CHECK: def Rec6 -// CHECK: string Name = "Ted" - -def Rec6 { - string Name = Class1<"Ted">.Name; -} - -#ifdef ERROR3 -// ERROR3: Value specified for template argument 'Class1:nm' (#0) is of type int - -def Rec7 { - string Name = Class1<42>.Name; -} -#endif - -// CHECK: def Rec8 -// CHECK: list CodeList = [42] - -def Rec8 { - list CodeList = [Class2<42>.Code]; -} - -#ifdef ERROR4 -// ERROR4: Value specified for template argument 'Class2:cd' (#0) is of type string - -def Rec9 { - list CodeList = [Class2<"huh?">.Code]; -} -#endif - -// Multiclass template arguments. - -multiclass MC1 { - def _1 { - string Name = nm; - } - def _2 { - string NameNmae = nm # nm; - } -} - -// CHECK: def RecMC1_1 -// CHECK: string Name = "Carol" -// CHECK: def RecMC1_2 -// CHECK: string NameNmae = "CarolCarol" - -defm RecMC1 : MC1<"Carol">; - -#ifdef ERROR5 -// ERROR5: Value specified for template argument 'MC1::nm' (#0) is of type int - -defm RecMC2 : MC1<42>; -#endif - -multiclass MC2 cd> { - def _1 { - bits<8> Code = cd; - } - def _2 { - int Code = cd; - } - def _3 { - list CodeList = [cd]; - } -} - -// CHECK: def RecMC3_1 -// CHECK: bits<8> Code = { 0, 0, 1, 0, 1, 0, 1, 0 } -// CHECK: def RecMC3_2 -// CHECK: int Code = 42 -// CHECK: def RecMC3_3 -// CHECK: list CodeList = [42] - -defm RecMC3 : MC2<42>; - -#ifdef ERROR6 -// ERROR6: Value specified for template argument 'MC2::cd' (#0) is of type string - -defm RecMC4 : MC2<"Bob">; -#endif -- 2.7.4