diff options
author | Ben Smith <binji@chromium.org> | 2020-02-28 20:42:39 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-02-28 20:42:39 -0800 |
commit | 7914f5f0182b5282d9de8399ba3ff264b5b5dea5 (patch) | |
tree | 308294028978a3c438895017fa8f4770ba9b831f /src | |
parent | 2d5bdb4a3a1bf8541dda300ffc2d35ffd9d4f84b (diff) | |
download | wabt-7914f5f0182b5282d9de8399ba3ff264b5b5dea5.tar.gz wabt-7914f5f0182b5282d9de8399ba3ff264b5b5dea5.tar.bz2 wabt-7914f5f0182b5282d9de8399ba3ff264b5b5dea5.zip |
Update testsuite (w/ reference-types changes) (#1351)
The new table-sub test, checks whether the subtyping is handled
properly w/ table.init and table.copy instructions.
The BeginElemSegment callback can't pass the element type anymore, since
it's not known yet. The callback also can't be deferred, since the
BeginElemSegmentInitExpr callback has to happen after the
BeginElemSegment callback, but the reference type is not always known
until after the initializer expression is read. To work around this, I
added a new OnElemSegmentElemType callback.
Other element segment changes:
* The element type must be tracked in the SharedValidator
* A subtle fix: when writing out the segment flags, we need to take into
account whether the element type of the segment is not funcref, even
if there are no element expressions. In that case, we have to use flag
bit 0x4 (SegUseElemExprs).
In addition, the TableCopy and TableInit instructions weren't handling
table indexes fully.
* TableCopy variables are read in the parser (both optional)
* TableCopy names are now resolved + applied
* TableCopy indexes are now validated
* TableInit table variables are read in the parser; this is subtle,
since the text format has order $table $segment, but the $table is
optional.
Diffstat (limited to 'src')
-rw-r--r-- | src/apply-names.cc | 7 | ||||
-rw-r--r-- | src/binary-reader-ir.cc | 15 | ||||
-rw-r--r-- | src/binary-reader-logging.cc | 15 | ||||
-rw-r--r-- | src/binary-reader-logging.h | 4 | ||||
-rw-r--r-- | src/binary-reader-nop.h | 6 | ||||
-rw-r--r-- | src/binary-reader-objdump.cc | 12 | ||||
-rw-r--r-- | src/binary-reader.cc | 4 | ||||
-rw-r--r-- | src/binary-reader.h | 4 | ||||
-rw-r--r-- | src/interp/binary-reader-interp.cc | 19 | ||||
-rw-r--r-- | src/ir.cc | 11 | ||||
-rw-r--r-- | src/resolve-names.cc | 7 | ||||
-rw-r--r-- | src/shared-validator.cc | 31 | ||||
-rw-r--r-- | src/shared-validator.h | 14 | ||||
-rw-r--r-- | src/validator.cc | 7 | ||||
-rw-r--r-- | src/wast-parser.cc | 20 |
15 files changed, 123 insertions, 53 deletions
diff --git a/src/apply-names.cc b/src/apply-names.cc index ee638c9b..95868176 100644 --- a/src/apply-names.cc +++ b/src/apply-names.cc @@ -58,6 +58,7 @@ class NameApplier : public ExprVisitor::DelegateNop { Result OnDataDropExpr(DataDropExpr*) override; Result OnMemoryInitExpr(MemoryInitExpr*) override; Result OnElemDropExpr(ElemDropExpr*) override; + Result OnTableCopyExpr(TableCopyExpr*) override; Result OnTableInitExpr(TableInitExpr*) override; Result OnTableGetExpr(TableGetExpr*) override; Result OnTableSetExpr(TableSetExpr*) override; @@ -260,6 +261,12 @@ Result NameApplier::OnElemDropExpr(ElemDropExpr* expr) { return Result::Ok; } +Result NameApplier::OnTableCopyExpr(TableCopyExpr* expr) { + CHECK_RESULT(UseNameForTableVar(&expr->dst_table)); + CHECK_RESULT(UseNameForTableVar(&expr->src_table)); + return Result::Ok; +} + Result NameApplier::OnTableInitExpr(TableInitExpr* expr) { CHECK_RESULT(UseNameForElemSegmentVar(&expr->segment_index)); CHECK_RESULT(UseNameForTableVar(&expr->table_index)); diff --git a/src/binary-reader-ir.cc b/src/binary-reader-ir.cc index 0bc03ebe..c907cba5 100644 --- a/src/binary-reader-ir.cc +++ b/src/binary-reader-ir.cc @@ -205,10 +205,10 @@ class BinaryReaderIR : public BinaryReaderNop { Result OnElemSegmentCount(Index count) override; Result BeginElemSegment(Index index, Index table_index, - uint8_t flags, - Type elem_type) override; + uint8_t flags) override; Result BeginElemSegmentInitExpr(Index index) override; Result EndElemSegmentInitExpr(Index index) override; + Result OnElemSegmentElemType(Index index, Type elem_type) override; Result OnElemSegmentElemExprCount(Index index, Index count) override; Result OnElemSegmentElemExpr_RefNull(Index segment_index) override; Result OnElemSegmentElemExpr_RefFunc(Index segment_index, @@ -1022,8 +1022,7 @@ Result BinaryReaderIR::OnElemSegmentCount(Index count) { Result BinaryReaderIR::BeginElemSegment(Index index, Index table_index, - uint8_t flags, - Type elem_type) { + uint8_t flags) { auto field = MakeUnique<ElemSegmentModuleField>(GetLocation()); ElemSegment& elem_segment = field->elem_segment; elem_segment.table_var = Var(table_index, GetLocation()); @@ -1034,7 +1033,6 @@ Result BinaryReaderIR::BeginElemSegment(Index index, } else { elem_segment.kind = SegmentKind::Active; } - elem_segment.elem_type = elem_type; module_->AppendField(std::move(field)); return Result::Ok; } @@ -1051,6 +1049,13 @@ Result BinaryReaderIR::EndElemSegmentInitExpr(Index index) { return Result::Ok; } +Result BinaryReaderIR::OnElemSegmentElemType(Index index, Type elem_type) { + assert(index == module_->elem_segments.size() - 1); + ElemSegment* segment = module_->elem_segments[index]; + segment->elem_type = elem_type; + return Result::Ok; +} + Result BinaryReaderIR::OnElemSegmentElemExprCount(Index index, Index count) { assert(index == module_->elem_segments.size() - 1); ElemSegment* segment = module_->elem_segments[index]; diff --git a/src/binary-reader-logging.cc b/src/binary-reader-logging.cc index 5ee062ed..81ddfbe9 100644 --- a/src/binary-reader-logging.cc +++ b/src/binary-reader-logging.cc @@ -368,12 +368,17 @@ Result BinaryReaderLogging::OnSimdShuffleOpExpr(Opcode opcode, v128 value) { Result BinaryReaderLogging::BeginElemSegment(Index index, Index table_index, - uint8_t flags, - Type elem_type) { + uint8_t flags) { LOGF("BeginElemSegment(index: %" PRIindex ", table_index: %" PRIindex - ", flags: %d, elem_type: %s)\n", - index, table_index, flags, GetTypeName(elem_type)); - return reader_->BeginElemSegment(index, table_index, flags, elem_type); + ", flags: %d)\n", + index, table_index, flags); + return reader_->BeginElemSegment(index, table_index, flags); +} + +Result BinaryReaderLogging::OnElemSegmentElemType(Index index, Type elem_type) { + LOGF("OnElemSegmentElemType(index: %" PRIindex ", type: %s)\n", index, + GetTypeName(elem_type)); + return reader_->OnElemSegmentElemType(index, elem_type); } Result BinaryReaderLogging::OnDataSegmentData(Index index, diff --git a/src/binary-reader-logging.h b/src/binary-reader-logging.h index 9e12d434..facc8d5d 100644 --- a/src/binary-reader-logging.h +++ b/src/binary-reader-logging.h @@ -231,10 +231,10 @@ class BinaryReaderLogging : public BinaryReaderDelegate { Result OnElemSegmentCount(Index count) override; Result BeginElemSegment(Index index, Index table_index, - uint8_t flags, - Type elem_type) override; + uint8_t flags) override; Result BeginElemSegmentInitExpr(Index index) override; Result EndElemSegmentInitExpr(Index index) override; + Result OnElemSegmentElemType(Index index, Type elem_type) override; Result OnElemSegmentElemExprCount(Index index, Index count) override; Result OnElemSegmentElemExpr_RefNull(Index segment_index) override; Result OnElemSegmentElemExpr_RefFunc(Index segment_index, diff --git a/src/binary-reader-nop.h b/src/binary-reader-nop.h index 2426103d..0124858c 100644 --- a/src/binary-reader-nop.h +++ b/src/binary-reader-nop.h @@ -302,12 +302,14 @@ class BinaryReaderNop : public BinaryReaderDelegate { Result OnElemSegmentCount(Index count) override { return Result::Ok; } Result BeginElemSegment(Index index, Index table_index, - uint8_t flags, - Type elem_type) override { + uint8_t flags) override { return Result::Ok; } Result BeginElemSegmentInitExpr(Index index) override { return Result::Ok; } Result EndElemSegmentInitExpr(Index index) override { return Result::Ok; } + Result OnElemSegmentElemType(Index index, Type elem_type) override { + return Result::Ok; + } Result OnElemSegmentElemExprCount(Index index, Index count) override { return Result::Ok; } diff --git a/src/binary-reader-objdump.cc b/src/binary-reader-objdump.cc index 6b80849a..a1c919ec 100644 --- a/src/binary-reader-objdump.cc +++ b/src/binary-reader-objdump.cc @@ -799,8 +799,8 @@ class BinaryReaderObjdump : public BinaryReaderObjdumpBase { Result OnElemSegmentCount(Index count) override; Result BeginElemSegment(Index index, Index table_index, - uint8_t flags, - Type elem_type) override; + uint8_t flags) override; + Result OnElemSegmentElemType(Index index, Type elem_type) override; Result OnElemSegmentElemExprCount(Index index, Index count) override; Result OnElemSegmentElemExpr_RefNull(Index segment_index) override; Result OnElemSegmentElemExpr_RefFunc(Index segment_index, @@ -1273,14 +1273,18 @@ Result BinaryReaderObjdump::OnElemSegmentCount(Index count) { Result BinaryReaderObjdump::BeginElemSegment(Index index, Index table_index, - uint8_t flags, - Type elem_type) { + uint8_t flags) { table_index_ = table_index; elem_index_ = 0; elem_flags_ = flags; return Result::Ok; } +Result BinaryReaderObjdump::OnElemSegmentElemType(Index index, Type elem_type) { + // TODO: Add support for this. + return Result::Ok; +} + Result BinaryReaderObjdump::OnElemSegmentElemExprCount(Index index, Index count) { PrintDetails(" - segment[%" PRIindex "] flags=%d table=%" PRIindex diff --git a/src/binary-reader.cc b/src/binary-reader.cc index 74fd3a67..6041145b 100644 --- a/src/binary-reader.cc +++ b/src/binary-reader.cc @@ -2220,7 +2220,7 @@ Result BinaryReader::ReadElemSection(Offset section_size) { } Type elem_type = Type::Funcref; - CALLBACK(BeginElemSegment, i, table_index, flags, elem_type); + CALLBACK(BeginElemSegment, i, table_index, flags); if (!(flags & SegPassive)) { CALLBACK(BeginElemSegmentInitExpr, i); @@ -2245,6 +2245,8 @@ Result BinaryReader::ReadElemSection(Offset section_size) { } } + CALLBACK(OnElemSegmentElemType, i, elem_type); + Index num_elem_exprs; CHECK_RESULT(ReadCount(&num_elem_exprs, "elem count")); diff --git a/src/binary-reader.h b/src/binary-reader.h index b5f97a8f..67e2c80c 100644 --- a/src/binary-reader.h +++ b/src/binary-reader.h @@ -287,10 +287,10 @@ class BinaryReaderDelegate { virtual Result OnElemSegmentCount(Index count) = 0; virtual Result BeginElemSegment(Index index, Index table_index, - uint8_t flags, - Type elem_type) = 0; + uint8_t flags) = 0; virtual Result BeginElemSegmentInitExpr(Index index) = 0; virtual Result EndElemSegmentInitExpr(Index index) = 0; + virtual Result OnElemSegmentElemType(Index index, Type elem_type) = 0; virtual Result OnElemSegmentElemExprCount(Index index, Index count) = 0; virtual Result OnElemSegmentElemExpr_RefNull(Index segment_index) = 0; virtual Result OnElemSegmentElemExpr_RefFunc(Index segment_index, diff --git a/src/interp/binary-reader-interp.cc b/src/interp/binary-reader-interp.cc index 5e442b61..8149907c 100644 --- a/src/interp/binary-reader-interp.cc +++ b/src/interp/binary-reader-interp.cc @@ -221,9 +221,9 @@ class BinaryReaderInterp : public BinaryReaderNop { wabt::Result OnElemSegmentCount(Index count) override; wabt::Result BeginElemSegment(Index index, Index table_index, - uint8_t flags, - Type elem_type) override; + uint8_t flags) override; wabt::Result EndElemSegmentInitExpr(Index index) override; + wabt::Result OnElemSegmentElemType(Index index, Type elem_type) override; wabt::Result OnElemSegmentElemExprCount(Index index, Index count) override; wabt::Result OnElemSegmentElemExpr_RefNull(Index segment_index) override; wabt::Result OnElemSegmentElemExpr_RefFunc(Index segment_index, @@ -692,13 +692,12 @@ wabt::Result BinaryReaderInterp::OnElemSegmentCount(Index count) { wabt::Result BinaryReaderInterp::BeginElemSegment(Index index, Index table_index, - uint8_t flags, - Type elem_type) { + uint8_t flags) { auto mode = ToSegmentMode(flags); - CHECK_RESULT(validator_.OnElemSegment(loc, Var(table_index), mode, elem_type)); + CHECK_RESULT(validator_.OnElemSegment(loc, Var(table_index), mode)); ElemDesc desc; - desc.type = elem_type; + desc.type = ValueType::Void; // Initialized later in OnElemSegmentElemType. desc.mode = mode; desc.table_index = table_index; module_.elems.push_back(desc); @@ -727,6 +726,14 @@ wabt::Result BinaryReaderInterp::EndElemSegmentInitExpr(Index index) { return wabt::Result::Ok; } +wabt::Result BinaryReaderInterp::OnElemSegmentElemType(Index index, + Type elem_type) { + validator_.OnElemSegmentElemType(elem_type); + ElemDesc& elem = module_.elems.back(); + elem.type = elem_type; + return wabt::Result::Ok; +} + wabt::Result BinaryReaderInterp::OnElemSegmentElemExprCount(Index index, Index count) { ElemDesc& elem = module_.elems.back(); @@ -653,6 +653,8 @@ Const::Const(V128Tag, v128 value, const Location& loc_) uint8_t ElemSegment::GetFlags(const Module* module) const { uint8_t flags = 0; + bool all_ref_func = elem_type == Type::Funcref; + switch (kind) { case SegmentKind::Active: { Index table_index = module->GetTableIndex(table_var); @@ -671,10 +673,11 @@ uint8_t ElemSegment::GetFlags(const Module* module) const { break; } - bool all_ref_func = std::all_of( - elem_exprs.begin(), elem_exprs.end(), [](const ElemExpr& elem_expr) { - return elem_expr.kind == ElemExprKind::RefFunc; - }); + all_ref_func = all_ref_func && + std::all_of(elem_exprs.begin(), elem_exprs.end(), + [](const ElemExpr& elem_expr) { + return elem_expr.kind == ElemExprKind::RefFunc; + }); if (!all_ref_func) { flags |= SegUseElemExprs; } diff --git a/src/resolve-names.cc b/src/resolve-names.cc index 2dff2a62..59bb0493 100644 --- a/src/resolve-names.cc +++ b/src/resolve-names.cc @@ -58,6 +58,7 @@ class NameResolver : public ExprVisitor::DelegateNop { Result OnDataDropExpr(DataDropExpr*) override; Result OnMemoryInitExpr(MemoryInitExpr*) override; Result OnElemDropExpr(ElemDropExpr*) override; + Result OnTableCopyExpr(TableCopyExpr*) override; Result OnTableInitExpr(TableInitExpr*) override; Result OnTableGetExpr(TableGetExpr*) override; Result OnTableSetExpr(TableSetExpr*) override; @@ -354,6 +355,12 @@ Result NameResolver::OnElemDropExpr(ElemDropExpr* expr) { return Result::Ok; } +Result NameResolver::OnTableCopyExpr(TableCopyExpr* expr) { + ResolveTableVar(&expr->dst_table); + ResolveTableVar(&expr->src_table); + return Result::Ok; +} + Result NameResolver::OnTableInitExpr(TableInitExpr* expr) { ResolveElemSegmentVar(&expr->segment_index); ResolveTableVar(&expr->table_index); diff --git a/src/shared-validator.cc b/src/shared-validator.cc index 708d6189..e286dc96 100644 --- a/src/shared-validator.cc +++ b/src/shared-validator.cc @@ -287,16 +287,19 @@ Result SharedValidator::OnStart(const Location& loc, Var func_var) { Result SharedValidator::OnElemSegment(const Location& loc, Var table_var, - SegmentKind kind, - Type elem_type) { + SegmentKind kind) { Result result = Result::Ok; if (kind == SegmentKind::Active) { result |= CheckTableIndex(table_var); } - ++elem_segments_; + elems_.push_back(ElemType{Type::Void}); // Updated in OnElemSegmentElemType. return result; } +void SharedValidator::OnElemSegmentElemType(Type elem_type) { + elems_.back().element = elem_type; +} + Result SharedValidator::OnElemSegmentInitExpr_Const(const Location& loc, Type type) { return CheckType(loc, type, Type::I32, "elem segment offset"); @@ -450,8 +453,7 @@ Result SharedValidator::CheckMemoryIndex(Var memory_var, MemoryType* out) { } // TODO: Remove; this is only used to match previous error output. -Result SharedValidator::CheckMemoryIndex(Var memory_var, - Opcode opcode) { +Result SharedValidator::CheckMemoryIndex(Var memory_var, Opcode opcode) { if (memory_var.index() >= memories_.size()) { return PrintError(memory_var.loc, "%s requires an imported or defined memory.", @@ -483,8 +485,9 @@ Result SharedValidator::CheckEventIndex(Var event_var, EventType* out) { return CheckIndexWithValue(event_var, events_, out, "event"); } -Result SharedValidator::CheckElemSegmentIndex(Var elem_segment_var) { - return CheckIndex(elem_segment_var, elem_segments_, "elem_segment"); +Result SharedValidator::CheckElemSegmentIndex(Var elem_segment_var, + ElemType* out) { + return CheckIndexWithValue(elem_segment_var, elems_, out, "elem_segment"); } Result SharedValidator::CheckDataSegmentIndex(Var data_segment_var) { @@ -1052,9 +1055,12 @@ Result SharedValidator::OnTableCopy(const Location& loc, Var src_var) { Result result = Result::Ok; expr_loc_ = &loc; - result |= CheckTableIndex(dst_var, Opcode::TableCopy); - result |= CheckTableIndex(src_var, Opcode::TableCopy); + TableType dst_table; + TableType src_table; + result |= CheckTableIndex(dst_var, &dst_table); + result |= CheckTableIndex(src_var, &src_table); result |= typechecker_.OnTableCopy(); + result |= CheckType(loc, src_table.element, dst_table.element, "table.copy"); return result; } @@ -1090,9 +1096,12 @@ Result SharedValidator::OnTableInit(const Location& loc, Var table_var) { Result result = Result::Ok; expr_loc_ = &loc; - result |= CheckTableIndex(table_var, Opcode::TableInit); - result |= CheckElemSegmentIndex(segment_var); + TableType table_type; + ElemType elem_type; + result |= CheckTableIndex(table_var, &table_type); + result |= CheckElemSegmentIndex(segment_var, &elem_type); result |= typechecker_.OnTableInit(table_var.index(), segment_var.index()); + result |= CheckType(loc, elem_type.element, table_type.element, "table.init"); return result; } diff --git a/src/shared-validator.h b/src/shared-validator.h index 2143c1fa..3e2035e9 100644 --- a/src/shared-validator.h +++ b/src/shared-validator.h @@ -84,7 +84,8 @@ class SharedValidator { Result OnStart(const Location&, Var func_var); - Result OnElemSegment(const Location&, Var table_var, SegmentKind, Type elem_type); + Result OnElemSegment(const Location&, Var table_var, SegmentKind); + void OnElemSegmentElemType(Type elem_type); Result OnElemSegmentInitExpr_Const(const Location&, Type); Result OnElemSegmentInitExpr_GlobalGet(const Location&, Var global_var); Result OnElemSegmentInitExpr_Other(const Location&); @@ -200,6 +201,13 @@ class SharedValidator { TypeVector params; }; + struct ElemType { + ElemType() = default; + ElemType(Type element) : element(element) {} + + Type element; + }; + struct LocalDecl { Type type; Index end; @@ -232,7 +240,7 @@ class SharedValidator { Result CheckMemoryIndex(Var memory_var, Opcode); Result CheckGlobalIndex(Var global_var, GlobalType* out = nullptr); Result CheckEventIndex(Var event_var, EventType* out = nullptr); - Result CheckElemSegmentIndex(Var elem_segment_var); + Result CheckElemSegmentIndex(Var elem_segment_var, ElemType* out = nullptr); Result CheckDataSegmentIndex(Var data_segment_var); Result CheckAlign(const Location&, Address align, Address natural_align); @@ -258,9 +266,9 @@ class SharedValidator { std::vector<MemoryType> memories_; // Includes imported and defined. std::vector<GlobalType> globals_; // Includes imported and defined. std::vector<EventType> events_; // Includes imported and defined. + std::vector<ElemType> elems_; Index starts_ = 0; Index num_imported_globals_ = 0; - Index elem_segments_ = 0; Index data_segments_ = 0; // Includes parameters, since this is only used for validating diff --git a/src/validator.cc b/src/validator.cc index ce25df9e..7498ca40 100644 --- a/src/validator.cc +++ b/src/validator.cc @@ -731,9 +731,10 @@ Result Validator::CheckModule() { // Elem segment section. for (const ModuleField& field : module->fields) { if (auto* f = dyn_cast<ElemSegmentModuleField>(&field)) { - result_ |= validator_.OnElemSegment( - field.loc, f->elem_segment.table_var, f->elem_segment.kind, - f->elem_segment.elem_type); + result_ |= validator_.OnElemSegment(field.loc, f->elem_segment.table_var, + f->elem_segment.kind); + + validator_.OnElemSegmentElemType(f->elem_segment.elem_type); // Init expr. if (f->elem_segment.offset.size() == 1) { diff --git a/src/wast-parser.cc b/src/wast-parser.cc index 3468e008..3075ee91 100644 --- a/src/wast-parser.cc +++ b/src/wast-parser.cc @@ -1820,11 +1820,8 @@ Result WastParser::ParsePlainInstr(std::unique_ptr<Expr>* out_expr) { Var dst(0, loc); Var src(0, loc); if (options_->features.reference_types_enabled()) { - // TODO: disabled for now, since the spec tests don't currently use. -#if 0 - CHECK_RESULT(ParseVar(&dst)); - CHECK_RESULT(ParseVar(&src)); -#endif + ParseVarOpt(&dst, dst); + ParseVarOpt(&src, src); } out_expr->reset(new TableCopyExpr(dst, src, loc)); break; @@ -1840,6 +1837,15 @@ Result WastParser::ParsePlainInstr(std::unique_ptr<Expr>* out_expr) { Var segment_index(0, loc); CHECK_RESULT(ParseVar(&segment_index)); Var table_index(0, loc); + if (ParseVarOpt(&table_index, table_index)) { + // Here are the two forms: + // + // table.init $elemidx ... + // table.init $tableidx $elemidx ... + // + // So if both indexes are provided, we need to swap them. + std::swap(segment_index, table_index); + } out_expr->reset(new TableInitExpr(segment_index, table_index, loc)); break; } @@ -1851,21 +1857,25 @@ Result WastParser::ParsePlainInstr(std::unique_ptr<Expr>* out_expr) { case TokenType::TableSet: ErrorUnlessOpcodeEnabled(Consume()); + // TODO: Table index. CHECK_RESULT(ParsePlainInstrVar<TableSetExpr>(loc, out_expr)); break; case TokenType::TableGrow: ErrorUnlessOpcodeEnabled(Consume()); + // TODO: Table index. CHECK_RESULT(ParsePlainInstrVar<TableGrowExpr>(loc, out_expr)); break; case TokenType::TableSize: ErrorUnlessOpcodeEnabled(Consume()); + // TODO: Table index. CHECK_RESULT(ParsePlainInstrVar<TableSizeExpr>(loc, out_expr)); break; case TokenType::TableFill: ErrorUnlessOpcodeEnabled(Consume()); + // TODO: Table index. CHECK_RESULT(ParsePlainInstrVar<TableFillExpr>(loc, out_expr)); break; |