@@ -144,4 +144,47 @@ void PostTypeContractLevelChecker::checkStorageLayoutSpecifier(ContractDefinitio
144
144
baseSlotExpression.location (),
145
145
" Contract extends past the end of storage when this base slot value is specified."
146
146
);
147
+
148
+ warnStorageLayoutBaseNearStorageEnd (_contract);
147
149
}
150
+
151
+ void PostTypeContractLevelChecker::warnStorageLayoutBaseNearStorageEnd (ContractDefinition const & _contract)
152
+ {
153
+ if (Error::containsErrors (m_errorReporter.errors ()))
154
+ return ;
155
+
156
+ auto storageSize = u256 (contractStorageSizeUpperBound (_contract, VariableDeclaration::Location::Unspecified));
157
+ auto baseSlot = layoutBaseForInheritanceHierarchy (_contract, DataLocation::Storage);
158
+ if (
159
+ u256 slotsLeft = std::numeric_limits<u256>::max () - baseSlot - storageSize;
160
+ !Error::containsErrors (m_errorReporter.errors ()) &&
161
+ slotsLeft <= u256 (1 ) << 64
162
+ )
163
+ {
164
+ auto const & location = _contract.storageLayoutSpecifier () ?
165
+ _contract.storageLayoutSpecifier ()->location () :
166
+ _contract.location ()
167
+ ;
168
+
169
+ auto errorID = 3495_error;
170
+ std::string errorMsg = " This contract is very close to the end of storage. This limits its future upgradability." ;
171
+ if (_contract.stateVariables ().size () > 0 )
172
+ m_errorReporter.warning (
173
+ errorID,
174
+ location,
175
+ errorMsg,
176
+ SecondarySourceLocation{}.append (
177
+ fmt::format (
178
+ " There are {} slots between this state variable and the end of the storage." ,
179
+ formatNumberReadable (slotsLeft)
180
+ ),
181
+ _contract.stateVariables ().back ()->location ()
182
+ ));
183
+ else
184
+ m_errorReporter.warning (
185
+ errorID,
186
+ location,
187
+ errorMsg
188
+ );
189
+ }
190
+ }
0 commit comments