diff --git a/Changelog.md b/Changelog.md index 0855f466b..f2ac80e91 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,7 @@ Language Features: + * Inline Assembly: Support direct constants of value type in inline assembly. diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 8069bd13b..81b236b6b 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -629,14 +629,27 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) if (auto var = dynamic_cast(declaration)) { solAssert(var->type(), "Expected variable type!"); - if (var->isConstant()) + if (var->isConstant() && (!type(*var)->isValueType() || ( + type(*var->value())->category() != Type::Category::RationalNumber && + dynamic_cast(var->value().get()) == nullptr + ))) { - m_errorReporter.typeError(_identifier.location, "Constant variables not supported by inline assembly."); + m_errorReporter.typeError(_identifier.location, "Only direct number constants are supported by inline assembly."); + return size_t(-1); + } + else if (var->isConstant() && _context == yul::IdentifierContext::LValue) + { + m_errorReporter.typeError(_identifier.location, "Constant variables cannot be assigned to."); return size_t(-1); } else if (requiresStorage) { - if (!var->isStateVariable() && !var->type()->dataStoredIn(DataLocation::Storage)) + if (var->isConstant()) + { + m_errorReporter.typeError(_identifier.location, "The suffixes _offset and _slot can only be used on non-constant storage variables."); + return size_t(-1); + } + else if (!var->isStateVariable() && !var->type()->dataStoredIn(DataLocation::Storage)) { m_errorReporter.typeError(_identifier.location, "The suffixes _offset and _slot can only be used on storage variables."); return size_t(-1); @@ -647,7 +660,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) return size_t(-1); } } - else if (!var->isLocalVariable()) + else if (!var->isConstant() && var->isStateVariable()) { m_errorReporter.typeError(_identifier.location, "Only local variables are supported. To access storage variables, use the _slot and _offset suffixes."); return size_t(-1); diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 6e2e74e45..a9c3990f8 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -629,8 +629,46 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) } else if (auto variable = dynamic_cast(decl)) { - solAssert(!variable->isConstant(), ""); - if (m_context.isStateVariable(decl)) + if (variable->isConstant()) + { + u256 value; + if (variable->value()->annotation().type->category() == Type::Category::RationalNumber) + { + value = dynamic_cast(*variable->value()->annotation().type).literalValue(nullptr); + if (FixedBytesType const* bytesType = dynamic_cast(variable->type())) + value = value << (256 - 8 * bytesType->numBytes()); + else + solAssert(variable->type()->category() == Type::Category::Integer, ""); + } + else if (Literal const* literal = dynamic_cast(variable->value().get())) + { + TypePointer type = literal->annotation().type; + + switch (type->category()) + { + case Type::Category::Bool: + case Type::Category::Address: + solAssert(*type == *variable->annotation().type, ""); + value = type->literalValue(literal); + break; + case Type::Category::StringLiteral: + { + StringLiteralType const& stringLiteral = dynamic_cast(*type); + solAssert(variable->type()->category() == Type::Category::FixedBytes, ""); + unsigned const numBytes = dynamic_cast(*variable->type()).numBytes(); + solAssert(stringLiteral.value().size() <= numBytes, ""); + value = u256(h256(stringLiteral.value(), h256::AlignLeft)); + break; + } + default: + solAssert(false, ""); + } + } + else + solAssert(false, "Invalid constant in inline assembly."); + m_context << value; + } + else if (m_context.isStateVariable(decl)) { auto const& location = m_context.storageLocationOfVariable(*decl); if (ref->second.isSlot) diff --git a/test/libsolidity/semanticTests/inlineAssembly/constant_access.sol b/test/libsolidity/semanticTests/inlineAssembly/constant_access.sol new file mode 100644 index 000000000..835048b85 --- /dev/null +++ b/test/libsolidity/semanticTests/inlineAssembly/constant_access.sol @@ -0,0 +1,18 @@ +contract C { + uint constant a = 2; + bytes2 constant b = 0xabcd; + bytes3 constant c = "abc"; + bool constant d = true; + address payable constant e = 0x1212121212121212121212121212121212121212; + function f() public pure returns (uint w, bytes2 x, bytes3 y, bool z, address t) { + assembly { + w := a + x := b + y := c + z := d + t := e + } + } +} +// ---- +// f() -> 2, left(0xabcd), left(0x616263), true, 0x1212121212121212121212121212121212121212 diff --git a/test/libsolidity/syntaxTests/inlineAssembly/constant_access.sol b/test/libsolidity/syntaxTests/inlineAssembly/constant_access.sol new file mode 100644 index 000000000..9389c87af --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/constant_access.sol @@ -0,0 +1,13 @@ +contract C { + uint constant x = 2**20; + bool constant b = true; + bytes4 constant s = "ab"; + function f() public pure { + assembly { + let c1 := x + let c2 := b + let c3 := s + } + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/inlineAssembly/constant_array.sol b/test/libsolidity/syntaxTests/inlineAssembly/constant_array.sol new file mode 100644 index 000000000..04cb37421 --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/constant_array.sol @@ -0,0 +1,10 @@ +contract C { + string constant x = "abc"; + function f() public pure { + assembly { + let a := x + } + } +} +// ---- +// TypeError: (115-116): Only direct number constants are supported by inline assembly. diff --git a/test/libsolidity/syntaxTests/inlineAssembly/constant_computation.sol b/test/libsolidity/syntaxTests/inlineAssembly/constant_computation.sol new file mode 100644 index 000000000..fc0605704 --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/constant_computation.sol @@ -0,0 +1,9 @@ +contract C { + uint constant x = 2**20; + function f() public pure { + assembly { + let a := x + } + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/inlineAssembly/constant_ref.sol b/test/libsolidity/syntaxTests/inlineAssembly/constant_ref.sol new file mode 100644 index 000000000..eba70edce --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/constant_ref.sol @@ -0,0 +1,11 @@ +contract C { + uint constant a = 2; + uint constant b = a; + function f() public pure { + assembly { + let x := b + } + } +} +// ---- +// TypeError: (134-135): Only direct number constants are supported by inline assembly. diff --git a/test/libsolidity/syntaxTests/inlineAssembly/invalid/constant_access.sol b/test/libsolidity/syntaxTests/inlineAssembly/invalid/constant_access.sol index 03ff9166b..bde3dca76 100644 --- a/test/libsolidity/syntaxTests/inlineAssembly/invalid/constant_access.sol +++ b/test/libsolidity/syntaxTests/inlineAssembly/invalid/constant_access.sol @@ -1,10 +1,9 @@ contract test { uint constant x = 1; - function f() public { + function f() public pure { assembly { let y := x } } } // ---- -// TypeError: (107-108): Constant variables not supported by inline assembly. diff --git a/test/libsolidity/syntaxTests/inlineAssembly/invalid/constant_assignment.sol b/test/libsolidity/syntaxTests/inlineAssembly/invalid/constant_assignment.sol index c8928804f..920b7e42d 100644 --- a/test/libsolidity/syntaxTests/inlineAssembly/invalid/constant_assignment.sol +++ b/test/libsolidity/syntaxTests/inlineAssembly/invalid/constant_assignment.sol @@ -7,4 +7,4 @@ contract test { } } // ---- -// TypeError: (98-99): Constant variables not supported by inline assembly. +// TypeError: (98-99): Constant variables cannot be assigned to. diff --git a/test/libsolidity/syntaxTests/inlineAssembly/invalid/constant_variable_via_offset.sol b/test/libsolidity/syntaxTests/inlineAssembly/invalid/constant_variable_via_offset.sol index 6470a2101..0c0837295 100644 --- a/test/libsolidity/syntaxTests/inlineAssembly/invalid/constant_variable_via_offset.sol +++ b/test/libsolidity/syntaxTests/inlineAssembly/invalid/constant_variable_via_offset.sol @@ -7,4 +7,4 @@ contract test { } } // ---- -// TypeError: (112-120): Constant variables not supported by inline assembly. +// TypeError: (112-120): The suffixes _offset and _slot can only be used on non-constant storage variables.