diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index e5895b6de..dc05ce18f 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include @@ -707,7 +706,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) *_inlineAssembly.annotation().analysisInfo, m_errorReporter, Error::Type::SyntaxError, - yul::EVMDialect::looseAssemblyForEVM(m_evmVersion), + _inlineAssembly.dialect(), identifierAccess ); if (!analyzer.analyze(_inlineAssembly.operations())) diff --git a/libsolidity/analysis/ViewPureChecker.cpp b/libsolidity/analysis/ViewPureChecker.cpp index bee0298bc..9a208a28e 100644 --- a/libsolidity/analysis/ViewPureChecker.cpp +++ b/libsolidity/analysis/ViewPureChecker.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -33,7 +34,11 @@ namespace class AssemblyViewPureChecker: public boost::static_visitor { public: - explicit AssemblyViewPureChecker(std::function _reportMutability): + explicit AssemblyViewPureChecker( + yul::Dialect const& _dialect, + std::function _reportMutability + ): + m_dialect(_dialect), m_reportMutability(_reportMutability) {} void operator()(yul::Label const&) { } @@ -69,6 +74,11 @@ public: } void operator()(yul::FunctionCall const& _funCall) { + if (yul::EVMDialect const* dialect = dynamic_cast(&m_dialect)) + if (yul::BuiltinFunctionForEVM const* fun = dialect->builtin(_funCall.functionName.name)) + if (fun->instruction) + checkInstruction(_funCall.location, *fun->instruction); + for (auto const& arg: _funCall.arguments) boost::apply_visitor(*this, arg); } @@ -107,7 +117,6 @@ public: } private: - std::function m_reportMutability; void checkInstruction(SourceLocation _location, dev::eth::Instruction _instruction) { if (eth::SemanticInformation::invalidInViewFunctions(_instruction)) @@ -115,6 +124,9 @@ private: else if (eth::SemanticInformation::invalidInPureFunctions(_instruction)) m_reportMutability(StateMutability::View, _location); } + + yul::Dialect const& m_dialect; + std::function m_reportMutability; }; } @@ -221,6 +233,7 @@ void ViewPureChecker::endVisit(Identifier const& _identifier) void ViewPureChecker::endVisit(InlineAssembly const& _inlineAssembly) { AssemblyViewPureChecker{ + _inlineAssembly.dialect(), [=](StateMutability _mutability, SourceLocation const& _location) { reportMutability(_mutability, _location); } }(_inlineAssembly.operations()); } diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index d8229593e..ffdb2a574 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -43,6 +43,7 @@ namespace yul { // Forward-declaration to struct Block; +struct Dialect; } namespace dev @@ -1049,17 +1050,20 @@ public: InlineAssembly( SourceLocation const& _location, ASTPointer const& _docString, + yul::Dialect const& _dialect, std::shared_ptr const& _operations ): - Statement(_location, _docString), m_operations(_operations) {} + Statement(_location, _docString), m_dialect(_dialect), m_operations(_operations) {} void accept(ASTVisitor& _visitor) override; void accept(ASTConstVisitor& _visitor) const override; + yul::Dialect const& dialect() const { return m_dialect; } yul::Block const& operations() const { return *m_operations; } InlineAssemblyAnnotation& annotation() const override; private: + yul::Dialect const& m_dialect; std::shared_ptr m_operations; }; diff --git a/libsolidity/ast/ASTAnnotations.h b/libsolidity/ast/ASTAnnotations.h index 64c8c779c..539ba85bf 100644 --- a/libsolidity/ast/ASTAnnotations.h +++ b/libsolidity/ast/ASTAnnotations.h @@ -35,8 +35,9 @@ namespace yul { - struct AsmAnalysisInfo; - struct Identifier; +struct AsmAnalysisInfo; +struct Identifier; +struct Dialect; } namespace dev diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 6bab80d1e..c4e83bc9e 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -32,6 +32,7 @@ #include #include +#include #include #include @@ -50,14 +51,21 @@ struct CopyTranslate: public yul::ASTCopier { using ExternalRefsMap = std::map; - CopyTranslate(IRGenerationContext& _context, ExternalRefsMap const& _references): - m_context(_context), m_references(_references) {} + CopyTranslate(yul::Dialect const& _dialect, IRGenerationContext& _context, ExternalRefsMap const& _references): + m_dialect(_dialect), m_context(_context), m_references(_references) {} using ASTCopier::operator(); yul::YulString translateIdentifier(yul::YulString _name) override { - return yul::YulString{"usr$" + _name.str()}; + // Strictly, the dialect used by inline assembly (m_dialect) could be different + // from the Yul dialect we are compiling to. So we are assuming here that the builtin + // functions are identical. This should not be a problem for now since everything + // is EVM anyway. + if (m_dialect.builtin(_name)) + return _name; + else + return yul::YulString{"usr$" + _name.str()}; } yul::Identifier translate(yul::Identifier const& _identifier) override @@ -80,6 +88,7 @@ struct CopyTranslate: public yul::ASTCopier } private: + yul::Dialect const& m_dialect; IRGenerationContext& m_context; ExternalRefsMap const& m_references; }; @@ -723,7 +732,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) bool IRGeneratorForStatements::visit(InlineAssembly const& _inlineAsm) { - CopyTranslate bodyCopier{m_context, _inlineAsm.annotation().externalReferences}; + CopyTranslate bodyCopier{_inlineAsm.dialect(), m_context, _inlineAsm.annotation().externalReferences}; yul::Statement modified = bodyCopier(_inlineAsm.operations()); diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 3e49173c8..d6e998644 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -217,7 +217,7 @@ bool CompilerStack::parse() string const& path = sourcesToParse[i]; Source& source = m_sources[path]; source.scanner->reset(); - source.ast = Parser(m_errorReporter).parse(source.scanner); + source.ast = Parser(m_errorReporter, m_evmVersion).parse(source.scanner); if (!source.ast) solAssert(!Error::containsOnlyWarnings(m_errorReporter.errors()), "Parser returned null but did not report error."); else diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index cb4525b92..5b5c56523 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -1039,21 +1040,22 @@ ASTPointer Parser::parseInlineAssembly(ASTPointer con SourceLocation location{position(), -1, source()}; expectToken(Token::Assembly); + yul::Dialect const& dialect = yul::EVMDialect::looseAssemblyForEVM(m_evmVersion); if (m_scanner->currentToken() == Token::StringLiteral) { if (m_scanner->currentLiteral() != "evmasm") fatalParserError("Only \"evmasm\" supported."); + // This can be used in the future to set the dialect. m_scanner->next(); } - // Using latest EVM Version for now, it will be run again later. - yul::Parser asmParser(m_errorReporter, yul::EVMDialect::looseAssemblyForEVM(EVMVersion{})); + yul::Parser asmParser(m_errorReporter, dialect); shared_ptr block = asmParser.parse(m_scanner, true); if (block == nullptr) BOOST_THROW_EXCEPTION(FatalError()); location.end = block->location.end; - return make_shared(location, _docString, block); + return make_shared(location, _docString, dialect, block); } ASTPointer Parser::parseIfStatement(ASTPointer const& _docString) diff --git a/libsolidity/parsing/Parser.h b/libsolidity/parsing/Parser.h index 2468c86ea..51b3b5be4 100644 --- a/libsolidity/parsing/Parser.h +++ b/libsolidity/parsing/Parser.h @@ -24,6 +24,7 @@ #include #include +#include namespace langutil { @@ -38,7 +39,13 @@ namespace solidity class Parser: public langutil::ParserBase { public: - explicit Parser(langutil::ErrorReporter& _errorReporter): ParserBase(_errorReporter) {} + explicit Parser( + langutil::ErrorReporter& _errorReporter, + langutil::EVMVersion _evmVersion + ): + ParserBase(_errorReporter), + m_evmVersion(_evmVersion) + {} ASTPointer parse(std::shared_ptr const& _scanner); @@ -181,6 +188,7 @@ private: /// Flag that signifies whether '_' is parsed as a PlaceholderStatement or a regular identifier. bool m_insideModifier = false; + langutil::EVMVersion m_evmVersion; }; } diff --git a/libyul/AsmAnalysis.cpp b/libyul/AsmAnalysis.cpp index 12f440d1d..ef6c8706c 100644 --- a/libyul/AsmAnalysis.cpp +++ b/libyul/AsmAnalysis.cpp @@ -399,9 +399,11 @@ bool AsmAnalyzer::operator()(If const& _if) { bool success = true; + int const initialHeight = m_stackHeight; if (!expectExpression(*_if.condition)) success = false; - m_stackHeight--; + + m_stackHeight = initialHeight; if (!(*this)(_if.body)) success = false; @@ -417,6 +419,7 @@ bool AsmAnalyzer::operator()(Switch const& _switch) bool success = true; + int const initialHeight = m_stackHeight; if (!expectExpression(*_switch.expression)) success = false; @@ -476,7 +479,7 @@ bool AsmAnalyzer::operator()(Switch const& _switch) success = false; } - m_stackHeight--; + m_stackHeight = initialHeight; m_info.stackHeightInfo[&_switch] = m_stackHeight; return success; @@ -488,6 +491,8 @@ bool AsmAnalyzer::operator()(ForLoop const& _for) Scope* outerScope = m_currentScope; + int const initialHeight = m_stackHeight; + bool success = true; if (!(*this)(_for.pre)) success = false; @@ -498,6 +503,7 @@ bool AsmAnalyzer::operator()(ForLoop const& _for) if (!expectExpression(*_for.condition)) success = false; + m_stackHeight--; // backup outer for-loop & create new state @@ -510,7 +516,7 @@ bool AsmAnalyzer::operator()(ForLoop const& _for) if (!(*this)(_for.post)) success = false; - m_stackHeight -= scope(&_for.pre).numberOfVariables(); + m_stackHeight = initialHeight; m_info.stackHeightInfo[&_for] = m_stackHeight; m_currentScope = outerScope; m_currentForLoop = outerForLoop; diff --git a/libyul/AsmParser.cpp b/libyul/AsmParser.cpp index a81c3dbc6..3f29f6fa5 100644 --- a/libyul/AsmParser.cpp +++ b/libyul/AsmParser.cpp @@ -248,14 +248,7 @@ Statement Parser::parseStatement() if (elementary.type() == typeid(Identifier)) { Identifier& identifier = boost::get(elementary); - // Fallback from builtin function to Instruction for loose assembly. - if ( - m_dialect.flavour == AsmFlavour::Loose && - instructions().count(identifier.name.str()) - ) - return Instruction{identifier.location, instructions().at(identifier.name.str())}; - else - return ExpressionStatement{identifier.location, { move(identifier) }}; + return ExpressionStatement{identifier.location, { move(identifier) }}; } else if (elementary.type() == typeid(Literal)) { @@ -405,11 +398,18 @@ Parser::ElementaryOperation Parser::parseElementaryOperation() // first search the set of builtins, then the instructions. if (m_dialect.builtin(literal)) { - // For builtins we already check here that they are followed by `(`. - ret = FunctionCall{location(), Identifier{location(), literal}, {}}; + Identifier identifier{location(), literal}; advance(); - expectToken(Token::LParen, false); - return ret; + // If the builtin is not followed by `(` and we are in loose mode, + // fall back to instruction. + if ( + m_dialect.flavour == AsmFlavour::Loose && + instructions().count(identifier.name.str()) && + m_scanner->currentToken() != Token::LParen + ) + return Instruction{identifier.location, instructions().at(identifier.name.str())}; + else + return FunctionCall{identifier.location, identifier, {}}; } else if (m_dialect.flavour == AsmFlavour::Loose && instructions().count(literal.str())) { diff --git a/libyul/backends/evm/EVMDialect.cpp b/libyul/backends/evm/EVMDialect.cpp index 375d0c897..36244d576 100644 --- a/libyul/backends/evm/EVMDialect.cpp +++ b/libyul/backends/evm/EVMDialect.cpp @@ -90,19 +90,18 @@ pair createFunction( return {name, f}; } -map createBuiltins(langutil::EVMVersion _evmVersion, bool _objectAccess, bool _evmOpcodes) +map createBuiltins(langutil::EVMVersion _evmVersion, bool _objectAccess) { map builtins; - if (_evmOpcodes) - for (auto const& instr: Parser::instructions()) - if ( - !dev::eth::isDupInstruction(instr.second) && - !dev::eth::isSwapInstruction(instr.second) && - instr.second != eth::Instruction::JUMP && - instr.second != eth::Instruction::JUMPI && - _evmVersion.hasOpcode(instr.second) - ) - builtins.emplace(createEVMFunction(instr.first, instr.second)); + for (auto const& instr: Parser::instructions()) + if ( + !dev::eth::isDupInstruction(instr.second) && + !dev::eth::isSwapInstruction(instr.second) && + instr.second != eth::Instruction::JUMP && + instr.second != eth::Instruction::JUMPI && + _evmVersion.hasOpcode(instr.second) + ) + builtins.emplace(createEVMFunction(instr.first, instr.second)); if (_objectAccess) { @@ -167,7 +166,7 @@ EVMDialect::EVMDialect(AsmFlavour _flavour, bool _objectAccess, langutil::EVMVer Dialect{_flavour}, m_objectAccess(_objectAccess), m_evmVersion(_evmVersion), - m_functions(createBuiltins(_evmVersion, _objectAccess, _flavour != AsmFlavour::Loose)) + m_functions(createBuiltins(_evmVersion, _objectAccess)) { } diff --git a/test/libsolidity/Assembly.cpp b/test/libsolidity/Assembly.cpp index 7281fd2eb..db3b395a5 100644 --- a/test/libsolidity/Assembly.cpp +++ b/test/libsolidity/Assembly.cpp @@ -57,7 +57,7 @@ eth::AssemblyItems compileContract(std::shared_ptr _sourceCode) { ErrorList errors; ErrorReporter errorReporter(errors); - Parser parser(errorReporter); + Parser parser(errorReporter, dev::test::Options::get().evmVersion()); ASTPointer sourceUnit; BOOST_REQUIRE_NO_THROW(sourceUnit = parser.parse(make_shared(_sourceCode))); BOOST_CHECK(!!sourceUnit); diff --git a/test/libsolidity/InlineAssembly.cpp b/test/libsolidity/InlineAssembly.cpp index 364e46ee0..39cc6fbf2 100644 --- a/test/libsolidity/InlineAssembly.cpp +++ b/test/libsolidity/InlineAssembly.cpp @@ -30,6 +30,7 @@ #include #include +#include #include @@ -80,7 +81,12 @@ boost::optional parseAndReturnFirstError( if (_allowWarnings && e->type() == Error::Type::Warning) continue; if (error) - BOOST_FAIL("Found more than one error."); + { + string errors; + for (auto const& err: stack.errors()) + errors += SourceReferenceFormatter::formatErrorInformation(*err); + BOOST_FAIL("Found more than one error:\n" + errors); + } error = e; } if (!success) @@ -299,7 +305,7 @@ BOOST_AUTO_TEST_CASE(if_statement_invalid) { CHECK_PARSE_ERROR("{ if mload {} }", ParserError, "Expected '(' (instruction \"mload\" expects 1 arguments)"); BOOST_CHECK("{ if calldatasize() {}"); - CHECK_PARSE_ERROR("{ if mstore(1, 1) {} }", ParserError, "Instruction \"mstore\" not allowed in this context"); + CHECK_PARSE_ERROR("{ if mstore(1, 1) {} }", TypeError, "Expected expression to return one item to the stack, but did return 0 items"); CHECK_PARSE_ERROR("{ if 32 let x := 3 }", ParserError, "Expected '{' but got reserved keyword 'let'"); } @@ -328,7 +334,7 @@ BOOST_AUTO_TEST_CASE(switch_invalid_expression) { CHECK_PARSE_ERROR("{ switch {} default {} }", ParserError, "Literal, identifier or instruction expected."); CHECK_PARSE_ERROR("{ switch mload default {} }", ParserError, "Expected '(' (instruction \"mload\" expects 1 arguments)"); - CHECK_PARSE_ERROR("{ switch mstore(1, 1) default {} }", ParserError, "Instruction \"mstore\" not allowed in this context"); + CHECK_PARSE_ERROR("{ switch mstore(1, 1) default {} }", TypeError, "Expected expression to return one item to the stack, but did return 0 items"); } BOOST_AUTO_TEST_CASE(switch_default_before_case) @@ -364,7 +370,7 @@ BOOST_AUTO_TEST_CASE(for_invalid_expression) CHECK_PARSE_ERROR("{ for {} 1 1 {} }", ParserError, "Expected '{' but got 'Number'"); CHECK_PARSE_ERROR("{ for {} 1 {} 1 }", ParserError, "Expected '{' but got 'Number'"); CHECK_PARSE_ERROR("{ for {} mload {} {} }", ParserError, "Expected '(' (instruction \"mload\" expects 1 arguments)"); - CHECK_PARSE_ERROR("{ for {} mstore(1, 1) {} {} }", ParserError, "Instruction \"mstore\" not allowed in this context"); + CHECK_PARSE_ERROR("{ for {} mstore(1, 1) {} {} }", TypeError, "Expected expression to return one item to the stack, but did return 0 items"); } BOOST_AUTO_TEST_CASE(for_visibility) @@ -417,13 +423,13 @@ BOOST_AUTO_TEST_CASE(function_calls) BOOST_AUTO_TEST_CASE(opcode_for_functions) { - CHECK_PARSE_ERROR("{ function gas() { } }", ParserError, "Cannot use instruction names for identifier names."); + CHECK_PARSE_ERROR("{ function gas() { } }", ParserError, "Cannot use builtin"); } BOOST_AUTO_TEST_CASE(opcode_for_function_args) { - CHECK_PARSE_ERROR("{ function f(gas) { } }", ParserError, "Cannot use instruction names for identifier names."); - CHECK_PARSE_ERROR("{ function f() -> gas { } }", ParserError, "Cannot use instruction names for identifier names."); + CHECK_PARSE_ERROR("{ function f(gas) { } }", ParserError, "Cannot use builtin"); + CHECK_PARSE_ERROR("{ function f() -> gas { } }", ParserError, "Cannot use builtin"); } BOOST_AUTO_TEST_CASE(name_clashes) @@ -467,13 +473,13 @@ BOOST_AUTO_TEST_CASE(invalid_tuple_assignment) BOOST_AUTO_TEST_CASE(instruction_too_few_arguments) { - CHECK_PARSE_ERROR("{ mul() }", ParserError, "Expected expression (instruction \"mul\" expects 2 arguments)"); - CHECK_PARSE_ERROR("{ mul(1) }", ParserError, "Expected ',' (instruction \"mul\" expects 2 arguments)"); + CHECK_PARSE_ERROR("{ pop(mul()) }", TypeError, "Function expects 2 arguments but got 0."); + CHECK_PARSE_ERROR("{ pop(mul(1)) }", TypeError, "Function expects 2 arguments but got 1."); } BOOST_AUTO_TEST_CASE(instruction_too_many_arguments) { - CHECK_PARSE_ERROR("{ mul(1, 2, 3) }", ParserError, "Expected ')' (instruction \"mul\" expects 2 arguments)"); + CHECK_PARSE_ERROR("{ pop(mul(1, 2, 3)) }", TypeError, "Function expects 2 arguments but got 3"); } BOOST_AUTO_TEST_CASE(recursion_depth) @@ -517,7 +523,7 @@ BOOST_AUTO_TEST_CASE(no_opcodes_in_strict) BOOST_CHECK(successParse("{ pop(callvalue) }")); BOOST_CHECK(successParse("{ callvalue pop }")); CHECK_STRICT_ERROR("{ pop(callvalue) }", ParserError, "Expected '(' but got ')'"); - CHECK_STRICT_ERROR("{ callvalue pop }", ParserError, "Expected '(' but got identifier"); + CHECK_STRICT_ERROR("{ callvalue pop }", ParserError, "Call or assignment expected"); SUCCESS_STRICT("{ pop(callvalue()) }"); BOOST_CHECK(successParse("{ switch callvalue case 0 {} }")); CHECK_STRICT_ERROR("{ switch callvalue case 0 {} }", ParserError, "Expected '(' but got reserved keyword 'case'"); @@ -692,12 +698,12 @@ BOOST_AUTO_TEST_CASE(designated_invalid_instruction) BOOST_AUTO_TEST_CASE(inline_assembly_shadowed_instruction_declaration) { - CHECK_ASSEMBLE_ERROR("{ let gas := 1 }", ParserError, "Cannot use instruction names for identifier names."); + CHECK_ASSEMBLE_ERROR("{ let gas := 1 }", ParserError, "Cannot use builtin"); } BOOST_AUTO_TEST_CASE(inline_assembly_shadowed_instruction_assignment) { - CHECK_ASSEMBLE_ERROR("{ 2 =: gas }", ParserError, "Identifier expected, got instruction name."); + CHECK_ASSEMBLE_ERROR("{ 2 =: gas }", ParserError, "Identifier expected, got builtin symbol"); } BOOST_AUTO_TEST_CASE(inline_assembly_shadowed_instruction_functional_assignment) diff --git a/test/libsolidity/SolidityExpressionCompiler.cpp b/test/libsolidity/SolidityExpressionCompiler.cpp index 3cdd70f67..607706162 100644 --- a/test/libsolidity/SolidityExpressionCompiler.cpp +++ b/test/libsolidity/SolidityExpressionCompiler.cpp @@ -102,7 +102,9 @@ bytes compileFirstExpression( { ErrorList errors; ErrorReporter errorReporter(errors); - sourceUnit = Parser(errorReporter).parse(make_shared(CharStream(_sourceCode, ""))); + sourceUnit = Parser(errorReporter, dev::test::Options::get().evmVersion()).parse( + make_shared(CharStream(_sourceCode, "")) + ); if (!sourceUnit) return bytes(); } diff --git a/test/libsolidity/SolidityParser.cpp b/test/libsolidity/SolidityParser.cpp index 763fda9ca..fe1ce5eda 100644 --- a/test/libsolidity/SolidityParser.cpp +++ b/test/libsolidity/SolidityParser.cpp @@ -44,7 +44,10 @@ namespace ASTPointer parseText(std::string const& _source, ErrorList& _errors) { ErrorReporter errorReporter(_errors); - ASTPointer sourceUnit = Parser(errorReporter).parse(std::make_shared(CharStream(_source, ""))); + ASTPointer sourceUnit = Parser( + errorReporter, + dev::test::Options::get().evmVersion() + ).parse(std::make_shared(CharStream(_source, ""))); if (!sourceUnit) return ASTPointer(); for (ASTPointer const& node: sourceUnit->nodes()) diff --git a/test/libsolidity/syntaxTests/inlineAssembly/invalid/assign_to_instruction.sol b/test/libsolidity/syntaxTests/inlineAssembly/invalid/assign_to_instruction.sol index 07bf01bef..f8734da31 100644 --- a/test/libsolidity/syntaxTests/inlineAssembly/invalid/assign_to_instruction.sol +++ b/test/libsolidity/syntaxTests/inlineAssembly/invalid/assign_to_instruction.sol @@ -6,4 +6,4 @@ contract C { } } // ---- -// ParserError: (67-70): Cannot use instruction names for identifier names. +// ParserError: (67-70): Cannot use builtin function name "mod" as identifier name. diff --git a/test/libsolidity/syntaxTests/inlineAssembly/invalid/multiple_assign_to_instruction.sol b/test/libsolidity/syntaxTests/inlineAssembly/invalid/multiple_assign_to_instruction.sol index 4e280bc63..30f7ff823 100644 --- a/test/libsolidity/syntaxTests/inlineAssembly/invalid/multiple_assign_to_instruction.sol +++ b/test/libsolidity/syntaxTests/inlineAssembly/invalid/multiple_assign_to_instruction.sol @@ -7,4 +7,4 @@ contract C { } } // ---- -// ParserError: (102-105): Cannot use instruction names for identifier names. +// ParserError: (102-105): Cannot use builtin function name "sub" as identifier name. diff --git a/test/libyul/Parser.cpp b/test/libyul/Parser.cpp index 396ae5c30..fe278c1aa 100644 --- a/test/libyul/Parser.cpp +++ b/test/libyul/Parser.cpp @@ -549,11 +549,11 @@ BOOST_AUTO_TEST_CASE(builtins_parser) SimpleDialect dialect; CHECK_ERROR_DIALECT("{ let builtin := 6 }", ParserError, "Cannot use builtin function name \"builtin\" as identifier name.", dialect); CHECK_ERROR_DIALECT("{ function builtin() {} }", ParserError, "Cannot use builtin function name \"builtin\" as identifier name.", dialect); - CHECK_ERROR_DIALECT("{ builtin := 6 }", ParserError, "Expected '(' but got ':='", dialect); + CHECK_ERROR_DIALECT("{ builtin := 6 }", ParserError, "Variable name must precede \":=\" in assignment.", dialect); CHECK_ERROR_DIALECT("{ function f(x) { f(builtin) } }", ParserError, "Expected '(' but got ')'", dialect); CHECK_ERROR_DIALECT("{ function f(builtin) {}", ParserError, "Cannot use builtin function name \"builtin\" as identifier name.", dialect); CHECK_ERROR_DIALECT("{ function f() -> builtin {}", ParserError, "Cannot use builtin function name \"builtin\" as identifier name.", dialect); - CHECK_ERROR_DIALECT("{ function g() -> a,b {} builtin, builtin2 := g() }", ParserError, "Expected '(' but got ','", dialect); + CHECK_ERROR_DIALECT("{ function g() -> a,b {} builtin, builtin2 := g() }", ParserError, "Variable name must precede \",\" in multiple assignment.", dialect); } BOOST_AUTO_TEST_CASE(builtins_analysis)