2222
2323#include < libsolidity/analysis/PostTypeContractLevelChecker.h>
2424
25+ #include < fmt/format.h>
2526#include < libsolidity/ast/AST.h>
27+ #include < libsolidity/ast/ASTUtils.h>
28+ #include < libsolidity/ast/TypeProvider.h>
2629#include < libsolutil/FunctionSelector.h>
2730#include < liblangutil/ErrorReporter.h>
2831
32+ #include < limits>
33+
2934using namespace solidity ;
3035using namespace solidity ::langutil;
3136using namespace solidity ::frontend;
37+ using namespace solidity ::util;
3238
3339bool PostTypeContractLevelChecker::check (SourceUnit const & _sourceUnit)
3440{
@@ -51,7 +57,7 @@ bool PostTypeContractLevelChecker::check(ContractDefinition const& _contract)
5157 for (ErrorDefinition const * error: _contract.interfaceErrors ())
5258 {
5359 std::string signature = error->functionType (true )->externalSignature ();
54- uint32_t hash = util:: selectorFromSignatureU32 (signature);
60+ uint32_t hash = selectorFromSignatureU32 (signature);
5561 // Fail if there is a different signature for the same hash.
5662 if (!errorHashes[hash].empty () && !errorHashes[hash].count (signature))
5763 {
@@ -67,5 +73,66 @@ bool PostTypeContractLevelChecker::check(ContractDefinition const& _contract)
6773 errorHashes[hash][signature] = error->location ();
6874 }
6975
76+ if (auto const * layoutSpecifier = _contract.storageLayoutSpecifier ())
77+ checkStorageLayoutSpecifier (*layoutSpecifier);
78+
7079 return !Error::containsErrors (m_errorReporter.errors ());
7180}
81+
82+ void PostTypeContractLevelChecker::checkStorageLayoutSpecifier (StorageLayoutSpecifier const & _storageLayoutSpecifier)
83+ {
84+ Expression const & baseSlotExpression = _storageLayoutSpecifier.baseSlotExpression ();
85+
86+ if (!*baseSlotExpression.annotation ().isPure )
87+ {
88+ // TODO: introduce and handle erc7201 as a builtin function
89+ m_errorReporter.typeError (
90+ 1139_error,
91+ baseSlotExpression.location (),
92+ " The base slot of the storage layout must be a compile-time constant expression."
93+ );
94+ return ;
95+ }
96+
97+ auto const * baseSlotExpressionType = type (baseSlotExpression);
98+ auto const * rationalType = dynamic_cast <RationalNumberType const *>(baseSlotExpressionType);
99+ if (!rationalType)
100+ {
101+ m_errorReporter.typeError (
102+ 6396_error,
103+ baseSlotExpression.location (),
104+ " The base slot of the storage layout must evaluate to a rational number."
105+ );
106+ return ;
107+ }
108+
109+ if (rationalType->isFractional ())
110+ {
111+ m_errorReporter.typeError (
112+ 1763_error,
113+ baseSlotExpression.location (),
114+ " The base slot of the storage layout must evaluate to an integer."
115+ );
116+ return ;
117+ }
118+ solAssert (rationalType->value ().denominator () == 1 );
119+
120+ if (
121+ rationalType->value ().numerator () < 0 ||
122+ rationalType->value ().numerator () > std::numeric_limits<u256>::max ()
123+ )
124+ {
125+ m_errorReporter.typeError (
126+ 6753_error,
127+ baseSlotExpression.location (),
128+ fmt::format (
129+ " The base slot of the storage layout evaluates to {}, which is outside the range of type uint256." ,
130+ formatNumberReadable (rationalType->value ().numerator ())
131+ )
132+ );
133+ return ;
134+ }
135+
136+ solAssert (baseSlotExpressionType->isImplicitlyConvertibleTo (*TypeProvider::uint256 ()));
137+ _storageLayoutSpecifier.annotation ().baseSlot = u256 (rationalType->value ().numerator ());
138+ }
0 commit comments