diff options
author | Nicolai Haehnle <nhaehnle@gmail.com> | 2018-03-19 14:14:20 +0000 |
---|---|---|
committer | Nicolai Haehnle <nhaehnle@gmail.com> | 2018-03-19 14:14:20 +0000 |
commit | 076f8dc78864a16d2823e21176833012a55081ce (patch) | |
tree | 90a9fb0dc9cabf5f4225f23c09b6ece8a7119734 /llvm/lib/TableGen | |
parent | 0d9fee1c146d47dbf280ab2f2fe87db44bc92dd5 (diff) |
TableGen: Check the dynamic type of !cast<Rec>(string)
Summary:
The docs already claim that this happens, but so far it hasn't. As a
consequence, existing TableGen files get this wrong a lot, but luckily
the fixes are all reasonably straightforward.
To make this work with all the existing forms of self-references (since
the true type of a record is only built up over time), the lookup of
self-references in !cast is delayed until the final resolving step.
Change-Id: If5923a72a252ba2fbc81a889d59775df0ef31164
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, javed.absar, llvm-commits
Differential Revision: https://reviews.llvm.org/D44475
Diffstat (limited to 'llvm/lib/TableGen')
-rw-r--r-- | llvm/lib/TableGen/Record.cpp | 43 |
1 files changed, 33 insertions, 10 deletions
diff --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp index 8b78f229ab3..333f45b7be9 100644 --- a/llvm/lib/TableGen/Record.cpp +++ b/llvm/lib/TableGen/Record.cpp @@ -194,7 +194,7 @@ void RecordRecTy::Profile(FoldingSetNodeID &ID) const { std::string RecordRecTy::getAsString() const { if (NumClasses == 1) - return getClasses()[0]->getName(); + return getClasses()[0]->getNameInitAsString(); std::string Str = "{"; bool First = true; @@ -202,7 +202,7 @@ std::string RecordRecTy::getAsString() const { if (!First) Str += ", "; First = false; - Str += R->getName(); + Str += R->getNameInitAsString(); } Str += "}"; return Str; @@ -700,7 +700,7 @@ void UnOpInit::Profile(FoldingSetNodeID &ID) const { ProfileUnOpInit(ID, getOpcode(), getOperand(), getType()); } -Init *UnOpInit::Fold(Record *CurRec) const { +Init *UnOpInit::Fold(Record *CurRec, bool IsFinal) const { switch (getOpcode()) { case CAST: if (isa<StringRecTy>(getType())) { @@ -715,12 +715,34 @@ Init *UnOpInit::Fold(Record *CurRec) const { } else if (isa<RecordRecTy>(getType())) { if (StringInit *Name = dyn_cast<StringInit>(LHS)) { assert(CurRec && "NULL pointer"); - if (Record *D = (CurRec->getRecords()).getDef(Name->getValue())) - return DefInit::get(D); + Record *D; + + // Self-references are allowed, but their resolution is delayed until + // the final resolve to ensure that we get the correct type for them. + if (Name == CurRec->getNameInit()) { + if (!IsFinal) + break; + D = CurRec; + } else { + D = CurRec->getRecords().getDef(Name->getValue()); + if (!D) { + if (IsFinal) + PrintFatalError(CurRec->getLoc(), + Twine("Undefined reference to record: '") + + Name->getValue() + "'\n"); + break; + } + } - PrintFatalError(CurRec->getLoc(), - Twine("Undefined reference to record: '") + - Name->getValue() + "'\n"); + DefInit *DI = DefInit::get(D); + if (!DI->getType()->typeIsA(getType())) { + PrintFatalError(CurRec->getLoc(), + Twine("Expected type '") + + getType()->getAsString() + "', got '" + + DI->getType()->getAsString() + "' in: " + + getAsString() + "\n"); + } + return DI; } } @@ -762,9 +784,9 @@ Init *UnOpInit::Fold(Record *CurRec) const { Init *UnOpInit::resolveReferences(Resolver &R) const { Init *lhs = LHS->resolveReferences(R); - if (LHS != lhs) + if (LHS != lhs || (R.isFinal() && getOpcode() == CAST)) return (UnOpInit::get(getOpcode(), lhs, getType())) - ->Fold(R.getCurrentRecord()); + ->Fold(R.getCurrentRecord(), R.isFinal()); return const_cast<UnOpInit *>(this); } @@ -1904,6 +1926,7 @@ void Record::resolveReferences(Resolver &R, const RecordVal *SkipVal) { void Record::resolveReferences() { RecordResolver R(*this); + R.setFinal(true); resolveReferences(R); } |