|
23 | 23 | #include <libsolidity/analysis/ContractLevelChecker.h>
|
24 | 24 |
|
25 | 25 | #include <libsolidity/ast/AST.h>
|
| 26 | +#include <libsolidity/ast/ASTUtils.h> |
26 | 27 | #include <libsolidity/ast/TypeProvider.h>
|
27 | 28 | #include <libsolidity/analysis/TypeChecker.h>
|
28 | 29 | #include <libsolutil/FunctionSelector.h>
|
29 | 30 | #include <liblangutil/ErrorReporter.h>
|
30 | 31 |
|
31 | 32 | #include <fmt/format.h>
|
32 | 33 |
|
| 34 | +#include <range/v3/algorithm/find_if.hpp> |
33 | 35 | #include <range/v3/view/reverse.hpp>
|
34 | 36 |
|
35 | 37 | using namespace solidity;
|
@@ -97,10 +99,44 @@ bool ContractLevelChecker::check(ContractDefinition const& _contract)
|
97 | 99 | checkBaseABICompatibility(_contract);
|
98 | 100 | checkPayableFallbackWithoutReceive(_contract);
|
99 | 101 | checkStorageSize(_contract);
|
| 102 | + checkStorageLayoutSpecifier(_contract); |
100 | 103 |
|
101 | 104 | return !Error::containsErrors(m_errorReporter.errors());
|
102 | 105 | }
|
103 | 106 |
|
| 107 | +void ContractLevelChecker::checkStorageLayoutSpecifier(ContractDefinition const& _contract) |
| 108 | +{ |
| 109 | + if (_contract.storageLayoutSpecifier()) |
| 110 | + { |
| 111 | + solAssert(!_contract.isLibrary() && !_contract.isInterface()); |
| 112 | + |
| 113 | + if (_contract.abstract()) |
| 114 | + m_errorReporter.typeError( |
| 115 | + 7587_error, |
| 116 | + _contract.storageLayoutSpecifier()->location(), |
| 117 | + "Storage layout cannot be specified for abstract contracts." |
| 118 | + ); |
| 119 | + } |
| 120 | + |
| 121 | + for (auto const& baseContractSpecifier: _contract.baseContracts()) |
| 122 | + { |
| 123 | + auto const* baseContract = dynamic_cast<ContractDefinition const*>( |
| 124 | + baseContractSpecifier->name().annotation().referencedDeclaration |
| 125 | + ); |
| 126 | + |
| 127 | + solAssert(baseContract); |
| 128 | + if (baseContract->storageLayoutSpecifier()) |
| 129 | + m_errorReporter.typeError( |
| 130 | + 8894_error, |
| 131 | + baseContractSpecifier->location(), |
| 132 | + SecondarySourceLocation().append( |
| 133 | + "Custom storage layout defined here:", |
| 134 | + baseContract->storageLayoutSpecifier()->location() |
| 135 | + ), |
| 136 | + "Cannot inherit from a contract with a custom storage layout." |
| 137 | + ); |
| 138 | + } |
| 139 | +} |
104 | 140 | void ContractLevelChecker::checkDuplicateFunctions(ContractDefinition const& _contract)
|
105 | 141 | {
|
106 | 142 | /// Checks that two functions with the same name defined in this contract have different
|
@@ -555,16 +591,16 @@ void ContractLevelChecker::checkPayableFallbackWithoutReceive(ContractDefinition
|
555 | 591 |
|
556 | 592 | void ContractLevelChecker::checkStorageSize(ContractDefinition const& _contract)
|
557 | 593 | {
|
558 |
| - bigint size = 0; |
559 |
| - for (ContractDefinition const* contract: _contract.annotation().linearizedBaseContracts | ranges::views::reverse) |
560 |
| - for (VariableDeclaration const* variable: contract->stateVariables()) |
561 |
| - if (!(variable->isConstant() || variable->immutable())) |
562 |
| - { |
563 |
| - size += variable->annotation().type->storageSizeUpperBound(); |
564 |
| - if (size >= bigint(1) << 256) |
565 |
| - { |
566 |
| - m_errorReporter.typeError(7676_error, _contract.location(), "Contract requires too much storage."); |
567 |
| - break; |
568 |
| - } |
569 |
| - } |
| 594 | + using enum VariableDeclaration::Location; |
| 595 | + for (VariableDeclaration::Location location: {Unspecified, Transient}) |
| 596 | + { |
| 597 | + bigint size = contractStorageSizeUpperBound(_contract, location); |
| 598 | + if (size >= bigint(1) << 256) |
| 599 | + { |
| 600 | + if (location == Unspecified) |
| 601 | + m_errorReporter.typeError(7676_error, _contract.location(), "Contract requires too much storage."); |
| 602 | + else |
| 603 | + m_errorReporter.typeError(5026_error, _contract.location(), "Contract requires too much transient storage."); |
| 604 | + } |
| 605 | + } |
570 | 606 | }
|
0 commit comments