diff --git a/Changelog.md b/Changelog.md index 9736a352c..c3045b3ae 100644 --- a/Changelog.md +++ b/Changelog.md @@ -23,6 +23,7 @@ Bugfixes: * Wasm backend: Fix code generation for for-loops with pre statements. * Wasm backend: Properly support both ``i32.drop`` and ``i64.drop``, and remove ``drop``. * Yul: Fix source location of variable multi-assignment. + * Yul: Disallow the same variable to occur multiple times on the left-hand side of an assignment. ### 0.6.10 (2020-06-11) diff --git a/docs/yul.rst b/docs/yul.rst index 58a8b745a..2054f35c7 100644 --- a/docs/yul.rst +++ b/docs/yul.rst @@ -288,6 +288,8 @@ variables at the same time. For this, the number and types of the values have to match. If you want to assign the values returned from a function that has multiple return parameters, you have to provide multiple variables. +The same variable may not occur multiple times on the left-hand side of +an assignment, e.g. ``x, x := f()`` is invalid. .. code-block:: yul @@ -506,6 +508,8 @@ In variable declarations and assignments, the right-hand-side expression variables on the left-hand-side. This is the only situation where an expression evaluating to more than one value is allowed. +The same variable name cannot occur more than once in the left-hand-side of +an assignment or variable declaration. Expressions that are also statements (i.e. at the block level) have to evaluate to zero values. diff --git a/libyul/AsmAnalysis.cpp b/libyul/AsmAnalysis.cpp index ad697fb40..f0ac3c242 100644 --- a/libyul/AsmAnalysis.cpp +++ b/libyul/AsmAnalysis.cpp @@ -167,6 +167,17 @@ void AsmAnalyzer::operator()(Assignment const& _assignment) size_t const numVariables = _assignment.variableNames.size(); yulAssert(numVariables >= 1, ""); + set variables; + for (auto const& _variableName: _assignment.variableNames) + if (!variables.insert(_variableName.name).second) + m_errorReporter.declarationError( + 9005_error, + _assignment.location, + "Variable " + + _variableName.name.str() + + " occurs multiple times on the left-hand side of the assignment." + ); + vector types = std::visit(*this, *_assignment.value); if (types.size() != numVariables) diff --git a/test/libyul/yulSyntaxTests/assignment_duplicate_vars.yul b/test/libyul/yulSyntaxTests/assignment_duplicate_vars.yul new file mode 100644 index 000000000..9bb725fd6 --- /dev/null +++ b/test/libyul/yulSyntaxTests/assignment_duplicate_vars.yul @@ -0,0 +1,10 @@ +{ + function f() -> a, b {} + function g() -> a, b, c {} + let x, y + x, x := f() + y, x, y := g() +} +// ---- +// DeclarationError 9005: (70-81): Variable x occurs multiple times on the left-hand side of the assignment. +// DeclarationError 9005: (84-98): Variable y occurs multiple times on the left-hand side of the assignment. diff --git a/test/libyul/yulSyntaxTests/declaration_duplicate_vars.yul b/test/libyul/yulSyntaxTests/declaration_duplicate_vars.yul new file mode 100644 index 000000000..7f786ac9a --- /dev/null +++ b/test/libyul/yulSyntaxTests/declaration_duplicate_vars.yul @@ -0,0 +1,6 @@ +{ + function f() -> a, b {} + let x, x := f() +} +// ---- +// DeclarationError 1395: (30-45): Variable name x already taken in this scope.