diff --git a/docs/yul.rst b/docs/yul.rst index b928bf85e..473496e16 100644 --- a/docs/yul.rst +++ b/docs/yul.rst @@ -180,7 +180,11 @@ appropriate ``PUSHi`` instruction. In the following example, ``3`` and ``2`` are added resulting in 5 and then the bitwise ``and`` with the string "abc" is computed. The final value is assigned to a local variable called ``x``. + Strings are stored left-aligned and cannot be longer than 32 bytes. +The limit does not apply to string literals passed to builtin functions that require +literal arguments (e.g. ``setimmutable`` or ``loadimmutable``). Those strings never end up in the +generated bytecode. .. code-block:: yul diff --git a/libyul/AsmAnalysis.cpp b/libyul/AsmAnalysis.cpp index eeb80263e..3c639f3d1 100644 --- a/libyul/AsmAnalysis.cpp +++ b/libyul/AsmAnalysis.cpp @@ -301,10 +301,15 @@ vector AsmAnalyzer::operator()(FunctionCall const& _funCall) for (size_t i = _funCall.arguments.size(); i > 0; i--) { Expression const& arg = _funCall.arguments[i - 1]; + bool isLiteralArgument = needsLiteralArguments && (*needsLiteralArguments)[i - 1]; + bool isStringLiteral = holds_alternative(arg) && get(arg).kind == LiteralKind::String; - argTypes.emplace_back(expectExpression(arg)); + if (isLiteralArgument && isStringLiteral) + argTypes.emplace_back(expectUnlimitedStringLiteral(get(arg))); + else + argTypes.emplace_back(expectExpression(arg)); - if (needsLiteralArguments && (*needsLiteralArguments)[i - 1]) + if (isLiteralArgument) { if (!holds_alternative(arg)) m_errorReporter.typeError( @@ -433,6 +438,14 @@ YulString AsmAnalyzer::expectExpression(Expression const& _expr) return types.empty() ? m_dialect.defaultType : types.front(); } +YulString AsmAnalyzer::expectUnlimitedStringLiteral(Literal const& _literal) +{ + yulAssert(_literal.kind == LiteralKind::String, ""); + yulAssert(m_dialect.validTypeForLiteral(LiteralKind::String, _literal.value, _literal.type), ""); + + return {_literal.type}; +} + void AsmAnalyzer::expectBoolExpression(Expression const& _expr) { YulString type = expectExpression(_expr); diff --git a/libyul/AsmAnalysis.h b/libyul/AsmAnalysis.h index 3804476ae..29bfca2fd 100644 --- a/libyul/AsmAnalysis.h +++ b/libyul/AsmAnalysis.h @@ -97,6 +97,7 @@ private: /// Visits the expression, expects that it evaluates to exactly one value and /// returns the type. Reports errors on errors and returns the default type. YulString expectExpression(Expression const& _expr); + YulString expectUnlimitedStringLiteral(Literal const& _literal); /// Vists the expression and expects it to return a single boolean value. /// Reports an error otherwise. void expectBoolExpression(Expression const& _expr); diff --git a/test/libsolidity/syntaxTests/immutable/long_name.sol b/test/libsolidity/syntaxTests/immutable/long_name.sol new file mode 100644 index 000000000..914cc2ead --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/long_name.sol @@ -0,0 +1,4 @@ +contract C { + uint immutable long___name___that___definitely___exceeds___the___thirty___two___byte___limit = 0; +} +// ---- diff --git a/test/libyul/objectCompiler/immutable_long_name_does_not_end_up_in_bytecode.yul b/test/libyul/objectCompiler/immutable_long_name_does_not_end_up_in_bytecode.yul new file mode 100644 index 000000000..b7058289b --- /dev/null +++ b/test/libyul/objectCompiler/immutable_long_name_does_not_end_up_in_bytecode.yul @@ -0,0 +1,17 @@ +object "a" { + code { + setimmutable( + "long___name___that___definitely___exceeds___the___thirty___two___byte___limit", + 0x1234567890123456789012345678901234567890 + ) + } +} +// ---- +// Assembly: +// /* "source":152:194 */ +// 0x1234567890123456789012345678901234567890 +// /* "source":32:204 */ +// assignImmutable("0x85a5b1db611c82c46f5fa18e39ae218397536256c451e5de155a86de843a9ad6") +// Bytecode: 73123456789012345678901234567890123456789050 +// Opcodes: PUSH20 0x1234567890123456789012345678901234567890 POP +// SourceMappings: 152:42:0:-:0;32:172 diff --git a/test/libyul/yulSyntaxTests/byte_of_string_literal.yul b/test/libyul/yulSyntaxTests/byte_of_string_literal.yul new file mode 100644 index 000000000..9ed41172a --- /dev/null +++ b/test/libyul/yulSyntaxTests/byte_of_string_literal.yul @@ -0,0 +1,6 @@ +{ + let x := byte(31, "11112222333344445555666677778888") +} +// ==== +// dialect: evm +// ---- diff --git a/test/libyul/yulSyntaxTests/loadimmutable.yul b/test/libyul/yulSyntaxTests/loadimmutable.yul new file mode 100644 index 000000000..6aea058b5 --- /dev/null +++ b/test/libyul/yulSyntaxTests/loadimmutable.yul @@ -0,0 +1,6 @@ +{ + let addr := loadimmutable("address") +} +// ==== +// dialect: evm +// ---- diff --git a/test/libyul/yulSyntaxTests/passing_builtin_with_literal_argument_into_literal_argument.yul b/test/libyul/yulSyntaxTests/passing_builtin_with_literal_argument_into_literal_argument.yul new file mode 100644 index 000000000..4884fc265 --- /dev/null +++ b/test/libyul/yulSyntaxTests/passing_builtin_with_literal_argument_into_literal_argument.yul @@ -0,0 +1,7 @@ +{ + setimmutable(loadimmutable("abc"), "abc") +} +// ==== +// dialect: evm +// ---- +// TypeError 9114: (6-18): Function expects direct literals as arguments. diff --git a/test/libyul/yulSyntaxTests/setimmutable.yul b/test/libyul/yulSyntaxTests/setimmutable.yul new file mode 100644 index 000000000..3c37c90ff --- /dev/null +++ b/test/libyul/yulSyntaxTests/setimmutable.yul @@ -0,0 +1,6 @@ +{ + setimmutable("address", 0x1234567890123456789012345678901234567890) +} +// ==== +// dialect: evm +// ---- diff --git a/test/libyul/yulSyntaxTests/string_literal_too_long.yul b/test/libyul/yulSyntaxTests/string_literal_too_long.yul new file mode 100644 index 000000000..2ae5be44a --- /dev/null +++ b/test/libyul/yulSyntaxTests/string_literal_too_long.yul @@ -0,0 +1,7 @@ +{ + let name := "long___name___that___definitely___exceeds___the___thirty___two___byte___limit" +} +// ==== +// dialect: evm +// ---- +// TypeError 3069: (18-97): String literal too long (77 > 32) diff --git a/test/libyul/yulSyntaxTests/string_literal_too_long_byte.yul b/test/libyul/yulSyntaxTests/string_literal_too_long_byte.yul new file mode 100644 index 000000000..0ae6d3beb --- /dev/null +++ b/test/libyul/yulSyntaxTests/string_literal_too_long_byte.yul @@ -0,0 +1,7 @@ +{ + let x := byte(40, "long___value__that___definitely___exceeds___the___thirty___two___byte___limit") +} +// ==== +// dialect: evm +// ---- +// TypeError 3069: (24-103): String literal too long (77 > 32) diff --git a/test/libyul/yulSyntaxTests/string_literal_too_long_immutable.yul b/test/libyul/yulSyntaxTests/string_literal_too_long_immutable.yul new file mode 100644 index 000000000..37ce835df --- /dev/null +++ b/test/libyul/yulSyntaxTests/string_literal_too_long_immutable.yul @@ -0,0 +1,9 @@ +{ + setimmutable( + "long___name___that___definitely___exceeds___the___thirty___two___byte___limit", + 0x1234567890123456789012345678901234567890 + ) +} +// ==== +// dialect: evm +// ----