Skip to content

Support constants in custom storage layout expression #15944

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 44 additions & 11 deletions libsolidity/analysis/PostTypeContractLevelChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <libsolidity/analysis/PostTypeContractLevelChecker.h>

#include <fmt/format.h>
#include <libsolidity/analysis/ConstantEvaluator.h>
#include <libsolidity/ast/AST.h>
#include <libsolidity/ast/ASTUtils.h>
#include <libsolidity/ast/TypeProvider.h>
Expand Down Expand Up @@ -101,8 +102,10 @@ void PostTypeContractLevelChecker::checkStorageLayoutSpecifier(ContractDefinitio
}

auto const* baseSlotExpressionType = type(baseSlotExpression);
auto const* rationalType = dynamic_cast<RationalNumberType const*>(baseSlotExpressionType);
if (!rationalType)
if (
!dynamic_cast<IntegerType const*>(baseSlotExpressionType) &&
!dynamic_cast<RationalNumberType const*>(baseSlotExpressionType)
)
{
m_errorReporter.typeError(
6396_error,
Expand All @@ -112,18 +115,48 @@ void PostTypeContractLevelChecker::checkStorageLayoutSpecifier(ContractDefinitio
return;
}

if (rationalType->isFractional())
rational baseSlotRationalValue;
if (auto const integerType = dynamic_cast<IntegerType const*>(baseSlotExpressionType))
{
m_errorReporter.typeError(
1763_error,
baseSlotExpression.location(),
"The base slot of the storage layout must evaluate to an integer."
);
return;
if (integerType->isSigned())
Copy link
Collaborator Author

@matheusaaguiar matheusaaguiar Mar 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could also be removed from here and then replace the assert in line 173 as suggested in a previous PR #15528 (comment)

{
m_errorReporter.typeError(
1481_error,
baseSlotExpression.location(),
"The base slot expression must have an unsigned integer type."
);
return;
}
std::optional<ConstantEvaluator::TypedRational> typedRational = ConstantEvaluator::evaluate(m_errorReporter, baseSlotExpression);
if (!typedRational)
{
m_errorReporter.typeError(
1505_error,
baseSlotExpression.location(),
"The base slot expression cannot be evaluated during compilation."
);
return;
}
baseSlotRationalValue = typedRational->value;
}
else
{
auto const* rationalType = dynamic_cast<RationalNumberType const*>(baseSlotExpressionType);
solAssert(rationalType);
if (rationalType->isFractional())
{
m_errorReporter.typeError(
1763_error,
baseSlotExpression.location(),
"The base slot of the storage layout must evaluate to an integer."
);
return;
}
baseSlotRationalValue = rationalType->value();
}
solAssert(rationalType->value().denominator() == 1);

bigint baseSlot = rationalType->value().numerator();
solAssert(baseSlotRationalValue.denominator() == 1);
bigint baseSlot = baseSlotRationalValue.numerator();
if (!(0 <= baseSlot && baseSlot <= std::numeric_limits<u256>::max()))
{
m_errorReporter.typeError(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
contract C layout at abi.decode(abi.encode(42), (uint)) {}
// ----
// TypeError 6396: (21-55): The base slot of the storage layout must evaluate to a rational number.
// TypeError 1505: (21-55): The base slot expression cannot be evaluated during compilation.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
address constant x = 0xdCad3a6d3569DF655070DEd06cb7A1b2Ccd1D3AF;
contract C layout at x {

}
// ----
// TypeError 6396: (86-87): The base slot of the storage layout must evaluate to a rational number.
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
contract C layout at ~uint(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) {}
// ----
// TypeError 6396: (21-94): The base slot of the storage layout must evaluate to a rational number.
// TypeError 1505: (21-94): The base slot expression cannot be evaluated during compilation.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
bool constant x = false;
contract C layout at x {}
// ----
// TypeError 6396: (46-47): The base slot of the storage layout must evaluate to a rational number.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
bytes32 constant x = "ABC";
contract A layout at x {}
contract C layout at x[1] {}
// ----
// TypeError 6396: (49-50): The base slot of the storage layout must evaluate to a rational number.
// TypeError 6396: (75-79): The base slot of the storage layout must evaluate to a rational number.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
uint constant N = 100;
contract C layout at N / ~N {}
// ----
// TypeError 6396: (44-50): The base slot of the storage layout must evaluate to a rational number.
// TypeError 3667: (48-50): Arithmetic error when computing constant value.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
uint constant N = 100;
contract C layout at N / 0 {}
// ----
// TypeError 6396: (44-49): The base slot of the storage layout must evaluate to a rational number.
// TypeError 1505: (44-49): The base slot expression cannot be evaluated during compilation.
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ contract A {

contract C is A layout at A.x { }
// ----
// TypeError 6396: (68-71): The base slot of the storage layout must evaluate to a rational number.
// TypeError 1505: (68-71): The base slot expression cannot be evaluated during compilation.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
==== Source: A ====
uint constant x = 77;

==== Source: B ====
import "A" as M;
contract C layout at M.x{ }
// ----
// TypeError 1505: (B:38-41): The base slot expression cannot be evaluated during compilation.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
uint constant x = addmod(10, 2, 8);
uint constant y = mulmod(10, 2, 8);
contract C layout at x {}
contract D layout at y {}
// ----
// TypeError 1505: (93-94): The base slot expression cannot be evaluated during compilation.
// TypeError 1505: (119-120): The base slot expression cannot be evaluated during compilation.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
uint constant x = uint(42);
contract C layout at x {}
// ----
// TypeError 1505: (49-50): The base slot expression cannot be evaluated during compilation.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
uint constant x = 42;
uint constant y = x * 2;
contract C layout at y {}
// ----
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
uint constant x = ((2**5 + 2**5) * (2 ** 10 + 1 << 1)) % 2**256 - 1;
contract C layout at x {}
// ----
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ contract A {
}
contract C is A layout at uint32(this.f.selector) {}
// ----
// TypeError 6396: (68-91): The base slot of the storage layout must evaluate to a rational number.
// TypeError 1505: (68-91): The base slot expression cannot be evaluated during compilation.
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
contract at layout at uint40(bytes5(hex"0011223344")) { }
// ----
// TypeError 6396: (22-53): The base slot of the storage layout must evaluate to a rational number.
// TypeError 1505: (22-53): The base slot expression cannot be evaluated during compilation.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
int constant x = -42;
contract C layout at x {}
// ----
// TypeError 1481: (43-44): The base slot expression must have an unsigned integer type.
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
uint constant X = 42;
contract C layout at 0xffff * (50 - X) { }
// ----
// TypeError 6396: (43-60): The base slot of the storage layout must evaluate to a rational number.
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ interface I {}

contract C layout at uint(bytes32(type(I).interfaceId)) { }
// ----
// TypeError 6396: (37-71): The base slot of the storage layout must evaluate to a rational number.
// TypeError 1505: (37-71): The base slot expression cannot be evaluated during compilation.
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
contract at layout at uint(42) { }
// ----
// TypeError 6396: (22-30): The base slot of the storage layout must evaluate to a rational number.
// TypeError 1505: (22-30): The base slot expression cannot be evaluated during compilation.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
contract A layout at addmod(1, 2, 3) {}
contract B layout at mulmod(3, 2, 1) {}
// ----
// TypeError 6396: (21-36): The base slot of the storage layout must evaluate to a rational number.
// TypeError 6396: (61-76): The base slot of the storage layout must evaluate to a rational number.
// TypeError 1505: (21-36): The base slot expression cannot be evaluated during compilation.
// TypeError 1505: (61-76): The base slot expression cannot be evaluated during compilation.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
contract A layout at true ? 42 : 94 {}
contract B layout at 255 + (true ? 1 : 0) {}
// ----
// TypeError 6396: (21-35): The base slot of the storage layout must evaluate to a rational number.
// TypeError 6396: (60-80): The base slot of the storage layout must evaluate to a rational number.
// TypeError 1505: (21-35): The base slot expression cannot be evaluated during compilation.
// TypeError 1505: (60-80): The base slot expression cannot be evaluated during compilation.
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
contract at layout at type(uint).max { }
// ----
// TypeError 6396: (22-36): The base slot of the storage layout must evaluate to a rational number.
// TypeError 1505: (22-36): The base slot expression cannot be evaluated during compilation.
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ type MyUint is uint128;
MyUint constant x = MyUint.wrap(42);
contract C layout at MyUint.unwrap(x) {}
// ----
// TypeError 6396: (82-98): The base slot of the storage layout must evaluate to a rational number.
// TypeError 1505: (82-98): The base slot expression cannot be evaluated during compilation.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
contract A layout at [1, 2, 3][0] {}
contract B layout at 255 + [1, 2, 3][0] {}
// ----
// TypeError 6396: (21-33): The base slot of the storage layout must evaluate to a rational number.
// TypeError 6396: (58-76): The base slot of the storage layout must evaluate to a rational number.
// TypeError 1505: (21-33): The base slot expression cannot be evaluated during compilation.
// TypeError 1505: (58-76): The base slot expression cannot be evaluated during compilation.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
bytes32 constant b = "Solidity";
contract C layout at uint8(b[1]) {}
// ----
// TypeError 6396: (54-65): The base slot of the storage layout must evaluate to a rational number.
// TypeError 1505: (54-65): The base slot expression cannot be evaluated during compilation.