mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge remote-tracking branch 'origin/develop' into breaking
This commit is contained in:
commit
8155ad2187
@ -110,7 +110,7 @@ matrix:
|
|||||||
before_install:
|
before_install:
|
||||||
- nvm install 8
|
- nvm install 8
|
||||||
- nvm use 8
|
- nvm use 8
|
||||||
- docker pull ethereum/solidity-buildpack-deps:emsdk-1.39.15-1
|
- docker pull ethereum/solidity-buildpack-deps:emsdk-1.39.15-2
|
||||||
env:
|
env:
|
||||||
- SOLC_EMSCRIPTEN=On
|
- SOLC_EMSCRIPTEN=On
|
||||||
- SOLC_INSTALL_DEPS_TRAVIS=Off
|
- SOLC_INSTALL_DEPS_TRAVIS=Off
|
||||||
|
22
Changelog.md
22
Changelog.md
@ -20,18 +20,38 @@ Bugfixes:
|
|||||||
* NatSpec: Constructors and functions have consistent userdoc output.
|
* NatSpec: Constructors and functions have consistent userdoc output.
|
||||||
|
|
||||||
|
|
||||||
### 0.6.10 (unreleased)
|
### 0.6.11 (unreleased)
|
||||||
|
|
||||||
|
|
||||||
Language Features:
|
Language Features:
|
||||||
|
|
||||||
|
|
||||||
Compiler Features:
|
Compiler Features:
|
||||||
|
* NatSpec: Add fields "kind" and "version" to the JSON output.
|
||||||
|
|
||||||
|
|
||||||
|
Bugfixes:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 0.6.10 (2020-06-11)
|
||||||
|
|
||||||
|
Important Bugfixes:
|
||||||
|
* Fixed a bug related to internal library functions with ``calldata`` parameters called via ``using for``.
|
||||||
|
|
||||||
|
|
||||||
|
Compiler Features:
|
||||||
|
* Commandline Interface: Re-group help screen.
|
||||||
|
* Output compilation error codes in standard-json and when using ``--error-codes``.
|
||||||
* Yul: Raise warning for switch statements that only have a default and no other cases.
|
* Yul: Raise warning for switch statements that only have a default and no other cases.
|
||||||
|
|
||||||
|
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
* SMTChecker: Fix internal error when encoding tuples of tuples.
|
* SMTChecker: Fix internal error when encoding tuples of tuples.
|
||||||
* SMTChecker: Fix aliasing soundness after pushing to an array pointer.
|
* SMTChecker: Fix aliasing soundness after pushing to an array pointer.
|
||||||
|
* Type system: Fix internal compiler error on calling externally a function that returns variables with calldata location.
|
||||||
|
* Type system: Fix bug where a bound function was not found if ``using for`` is applied to explicit reference types.
|
||||||
|
|
||||||
|
|
||||||
### 0.6.9 (2020-06-04)
|
### 0.6.9 (2020-06-04)
|
||||||
|
@ -1,4 +1,12 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"name": "UsingForCalldata",
|
||||||
|
"summary": "Function calls to internal library functions with calldata parameters called via ``using for`` can result in invalid data being read.",
|
||||||
|
"description": "Function calls to internal library functions using the ``using for`` mechanism copied all calldata parameters to memory first and passed them on like that, regardless of whether it was an internal or an external call. Due to that, the called function would receive a memory pointer that is interpreted as a calldata pointer. Since dynamically sized arrays are passed using two stack slots for calldata, but only one for memory, this can lead to stack corruption. An affected library call will consider the JUMPDEST to which it is supposed to return as part of its arguments and will instead jump out to whatever was on the stack before the call.",
|
||||||
|
"introduced": "0.6.9",
|
||||||
|
"fixed": "0.6.10",
|
||||||
|
"severity": "very low"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "MissingEscapingInFormatting",
|
"name": "MissingEscapingInFormatting",
|
||||||
"summary": "String literals containing double backslash characters passed directly to external or encoding function calls can lead to a different string being used when ABIEncoderV2 is enabled.",
|
"summary": "String literals containing double backslash characters passed directly to external or encoding function calls can lead to a different string being used when ABIEncoderV2 is enabled.",
|
||||||
|
@ -1105,6 +1105,10 @@
|
|||||||
],
|
],
|
||||||
"released": "2020-01-02"
|
"released": "2020-01-02"
|
||||||
},
|
},
|
||||||
|
"0.6.10": {
|
||||||
|
"bugs": [],
|
||||||
|
"released": "2020-06-11"
|
||||||
|
},
|
||||||
"0.6.2": {
|
"0.6.2": {
|
||||||
"bugs": [
|
"bugs": [
|
||||||
"MissingEscapingInFormatting",
|
"MissingEscapingInFormatting",
|
||||||
@ -1165,7 +1169,9 @@
|
|||||||
"released": "2020-05-14"
|
"released": "2020-05-14"
|
||||||
},
|
},
|
||||||
"0.6.9": {
|
"0.6.9": {
|
||||||
"bugs": [],
|
"bugs": [
|
||||||
|
"UsingForCalldata"
|
||||||
|
],
|
||||||
"released": "2020-06-04"
|
"released": "2020-06-04"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -430,7 +430,13 @@ Array slices are useful to ABI-decode secondary data passed in function paramete
|
|||||||
/// Forward call to "setOwner(address)" that is implemented by client
|
/// Forward call to "setOwner(address)" that is implemented by client
|
||||||
/// after doing basic validation on the address argument.
|
/// after doing basic validation on the address argument.
|
||||||
function forward(bytes calldata _payload) external {
|
function forward(bytes calldata _payload) external {
|
||||||
bytes4 sig = abi.decode(_payload[:4], (bytes4));
|
// Since ABI decoding requires padded data, we cannot
|
||||||
|
// use abi.decode(_payload[:4], (bytes4)).
|
||||||
|
bytes4 sig =
|
||||||
|
_payload[0] |
|
||||||
|
(bytes4(_payload[1]) >> 8) |
|
||||||
|
(bytes4(_payload[2]) >> 16) |
|
||||||
|
(bytes4(_payload[3]) >> 24);
|
||||||
if (sig == bytes4(keccak256("setOwner(address)"))) {
|
if (sig == bytes4(keccak256("setOwner(address)"))) {
|
||||||
address owner = abi.decode(_payload[4:], (address));
|
address owner = abi.decode(_payload[4:], (address));
|
||||||
require(owner != address(0), "Address of owner cannot be zero.");
|
require(owner != address(0), "Address of owner cannot be zero.");
|
||||||
|
@ -374,8 +374,10 @@ Output Description
|
|||||||
"component": "general",
|
"component": "general",
|
||||||
// Mandatory ("error" or "warning")
|
// Mandatory ("error" or "warning")
|
||||||
"severity": "error",
|
"severity": "error",
|
||||||
|
// Optional: unique code for the cause of the error
|
||||||
|
"errorCode": "3141",
|
||||||
// Mandatory
|
// Mandatory
|
||||||
"message": "Invalid keyword"
|
"message": "Invalid keyword",
|
||||||
// Optional: the message formatted with source location
|
// Optional: the message formatted with source location
|
||||||
"formattedMessage": "sourceFile.sol:100: Invalid keyword"
|
"formattedMessage": "sourceFile.sol:100: Invalid keyword"
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ void AssemblyItem::setPushTagSubIdAndTag(size_t _subId, size_t _tag)
|
|||||||
setData(data);
|
setData(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned AssemblyItem::bytesRequired(unsigned _addressLength) const
|
size_t AssemblyItem::bytesRequired(size_t _addressLength) const
|
||||||
{
|
{
|
||||||
switch (m_type)
|
switch (m_type)
|
||||||
{
|
{
|
||||||
@ -69,7 +69,7 @@ unsigned AssemblyItem::bytesRequired(unsigned _addressLength) const
|
|||||||
case PushString:
|
case PushString:
|
||||||
return 1 + 32;
|
return 1 + 32;
|
||||||
case Push:
|
case Push:
|
||||||
return 1 + max<unsigned>(1, util::bytesRequired(data()));
|
return 1 + max<size_t>(1, util::bytesRequired(data()));
|
||||||
case PushSubSize:
|
case PushSubSize:
|
||||||
case PushProgramSize:
|
case PushProgramSize:
|
||||||
return 1 + 4; // worst case: a 16MB program
|
return 1 + 4; // worst case: a 16MB program
|
||||||
|
@ -133,7 +133,7 @@ public:
|
|||||||
|
|
||||||
/// @returns an upper bound for the number of bytes required by this item, assuming that
|
/// @returns an upper bound for the number of bytes required by this item, assuming that
|
||||||
/// the value of a jump tag takes @a _addressLength bytes.
|
/// the value of a jump tag takes @a _addressLength bytes.
|
||||||
unsigned bytesRequired(unsigned _addressLength) const;
|
size_t bytesRequired(size_t _addressLength) const;
|
||||||
size_t arguments() const;
|
size_t arguments() const;
|
||||||
size_t returnValues() const;
|
size_t returnValues() const;
|
||||||
size_t deposit() const { return returnValues() - arguments(); }
|
size_t deposit() const { return returnValues() - arguments(); }
|
||||||
|
@ -107,7 +107,7 @@ tuple<int, int> CharStream::translatePositionToLineColumn(int _position) const
|
|||||||
using size_type = string::size_type;
|
using size_type = string::size_type;
|
||||||
using diff_type = string::difference_type;
|
using diff_type = string::difference_type;
|
||||||
size_type searchPosition = min<size_type>(m_source.size(), size_type(_position));
|
size_type searchPosition = min<size_type>(m_source.size(), size_type(_position));
|
||||||
int lineNumber = count(m_source.begin(), m_source.begin() + diff_type(searchPosition), '\n');
|
int lineNumber = static_cast<int>(count(m_source.begin(), m_source.begin() + diff_type(searchPosition), '\n'));
|
||||||
size_type lineStart;
|
size_type lineStart;
|
||||||
if (searchPosition == 0)
|
if (searchPosition == 0)
|
||||||
lineStart = 0;
|
lineStart = 0;
|
||||||
|
@ -179,7 +179,7 @@ bool Scanner::scanHexByte(char& o_scannedByte)
|
|||||||
rollback(i);
|
rollback(i);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
x = x * 16 + d;
|
x = static_cast<char>(x * 16 + d);
|
||||||
advance();
|
advance();
|
||||||
}
|
}
|
||||||
o_scannedByte = x;
|
o_scannedByte = x;
|
||||||
@ -197,7 +197,7 @@ std::optional<unsigned> Scanner::scanUnicode()
|
|||||||
rollback(i);
|
rollback(i);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
x = x * 16 + static_cast<size_t>(d);
|
x = x * 16 + static_cast<unsigned>(d);
|
||||||
advance();
|
advance();
|
||||||
}
|
}
|
||||||
return x;
|
return x;
|
||||||
|
@ -38,7 +38,15 @@ SourceReferenceExtractor::Message SourceReferenceExtractor::extract(util::Except
|
|||||||
for (auto const& info: secondaryLocation->infos)
|
for (auto const& info: secondaryLocation->infos)
|
||||||
secondary.emplace_back(extract(&info.second, info.first));
|
secondary.emplace_back(extract(&info.second, info.first));
|
||||||
|
|
||||||
return Message{std::move(primary), _category, std::move(secondary)};
|
return Message{std::move(primary), _category, std::move(secondary), nullopt};
|
||||||
|
}
|
||||||
|
|
||||||
|
SourceReferenceExtractor::Message SourceReferenceExtractor::extract(Error const& _error)
|
||||||
|
{
|
||||||
|
string category = (_error.type() == Error::Type::Warning) ? "Warning" : "Error";
|
||||||
|
Message message = extract(_error, category);
|
||||||
|
message.errorId = _error.errorId();
|
||||||
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceReference SourceReferenceExtractor::extract(SourceLocation const* _location, std::string message)
|
SourceReference SourceReferenceExtractor::extract(SourceLocation const* _location, std::string message)
|
||||||
|
@ -16,16 +16,14 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <liblangutil/Exceptions.h>
|
||||||
|
|
||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace solidity::util
|
|
||||||
{
|
|
||||||
struct Exception;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace solidity::langutil
|
namespace solidity::langutil
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -58,8 +56,6 @@ struct SourceReference
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SourceLocation;
|
|
||||||
|
|
||||||
namespace SourceReferenceExtractor
|
namespace SourceReferenceExtractor
|
||||||
{
|
{
|
||||||
struct Message
|
struct Message
|
||||||
@ -67,9 +63,11 @@ namespace SourceReferenceExtractor
|
|||||||
SourceReference primary;
|
SourceReference primary;
|
||||||
std::string category; // "Error", "Warning", ...
|
std::string category; // "Error", "Warning", ...
|
||||||
std::vector<SourceReference> secondary;
|
std::vector<SourceReference> secondary;
|
||||||
|
std::optional<ErrorId> errorId;
|
||||||
};
|
};
|
||||||
|
|
||||||
Message extract(util::Exception const& _exception, std::string _category);
|
Message extract(util::Exception const& _exception, std::string _category);
|
||||||
|
Message extract(Error const& _error);
|
||||||
SourceReference extract(SourceLocation const* _location, std::string message = "");
|
SourceReference extract(SourceLocation const* _location, std::string message = "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,10 +80,7 @@ void SourceReferenceFormatter::printExceptionInformation(util::Exception const&
|
|||||||
|
|
||||||
void SourceReferenceFormatter::printErrorInformation(Error const& _error)
|
void SourceReferenceFormatter::printErrorInformation(Error const& _error)
|
||||||
{
|
{
|
||||||
printExceptionInformation(
|
printExceptionInformation(SourceReferenceExtractor::extract(_error));
|
||||||
_error,
|
|
||||||
(_error.type() == Error::Type::Warning) ? "Warning" : "Error"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SourceReferenceFormatter::printExceptionInformation(SourceReferenceExtractor::Message const& _msg)
|
void SourceReferenceFormatter::printExceptionInformation(SourceReferenceExtractor::Message const& _msg)
|
||||||
|
@ -151,6 +151,8 @@ void SourceReferenceFormatterHuman::printExceptionInformation(SourceReferenceExt
|
|||||||
{
|
{
|
||||||
// exception header line
|
// exception header line
|
||||||
errorColored() << _msg.category;
|
errorColored() << _msg.category;
|
||||||
|
if (m_withErrorIds && _msg.errorId.has_value())
|
||||||
|
errorColored() << " (" << _msg.errorId.value().error << ")";
|
||||||
messageColored() << ": " << _msg.primary.message << '\n';
|
messageColored() << ": " << _msg.primary.message << '\n';
|
||||||
|
|
||||||
printSourceLocation(_msg.primary);
|
printSourceLocation(_msg.primary);
|
||||||
|
@ -29,22 +29,14 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
namespace solidity::util
|
|
||||||
{
|
|
||||||
struct Exception; // forward
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace solidity::langutil
|
namespace solidity::langutil
|
||||||
{
|
{
|
||||||
|
|
||||||
struct SourceLocation;
|
|
||||||
struct SourceReference;
|
|
||||||
|
|
||||||
class SourceReferenceFormatterHuman: public SourceReferenceFormatter
|
class SourceReferenceFormatterHuman: public SourceReferenceFormatter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SourceReferenceFormatterHuman(std::ostream& _stream, bool colored):
|
SourceReferenceFormatterHuman(std::ostream& _stream, bool _colored, bool _withErrorIds):
|
||||||
SourceReferenceFormatter{_stream}, m_colored{colored}
|
SourceReferenceFormatter{_stream}, m_colored{_colored}, m_withErrorIds(_withErrorIds)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void printSourceLocation(SourceReference const& _ref) override;
|
void printSourceLocation(SourceReference const& _ref) override;
|
||||||
@ -54,12 +46,13 @@ public:
|
|||||||
static std::string formatExceptionInformation(
|
static std::string formatExceptionInformation(
|
||||||
util::Exception const& _exception,
|
util::Exception const& _exception,
|
||||||
std::string const& _name,
|
std::string const& _name,
|
||||||
bool colored = false
|
bool _colored = false,
|
||||||
|
bool _withErrorIds = false
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
std::ostringstream errorOutput;
|
std::ostringstream errorOutput;
|
||||||
|
|
||||||
SourceReferenceFormatterHuman formatter(errorOutput, colored);
|
SourceReferenceFormatterHuman formatter(errorOutput, _colored, _withErrorIds);
|
||||||
formatter.printExceptionInformation(_exception, _name);
|
formatter.printExceptionInformation(_exception, _name);
|
||||||
return errorOutput.str();
|
return errorOutput.str();
|
||||||
}
|
}
|
||||||
@ -75,6 +68,7 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_colored;
|
bool m_colored;
|
||||||
|
bool m_withErrorIds;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ struct OverrideGraph
|
|||||||
std::map<OverrideProxy, int> nodes;
|
std::map<OverrideProxy, int> nodes;
|
||||||
std::map<int, OverrideProxy> nodeInv;
|
std::map<int, OverrideProxy> nodeInv;
|
||||||
std::map<int, std::set<int>> edges;
|
std::map<int, std::set<int>> edges;
|
||||||
int numNodes = 2;
|
size_t numNodes = 2;
|
||||||
void addEdge(int _a, int _b)
|
void addEdge(int _a, int _b)
|
||||||
{
|
{
|
||||||
edges[_a].insert(_b);
|
edges[_a].insert(_b);
|
||||||
@ -82,7 +82,7 @@ private:
|
|||||||
auto it = nodes.find(_function);
|
auto it = nodes.find(_function);
|
||||||
if (it != nodes.end())
|
if (it != nodes.end())
|
||||||
return it->second;
|
return it->second;
|
||||||
int currentNode = numNodes++;
|
int currentNode = static_cast<int>(numNodes++);
|
||||||
nodes[_function] = currentNode;
|
nodes[_function] = currentNode;
|
||||||
nodeInv[currentNode] = _function;
|
nodeInv[currentNode] = _function;
|
||||||
if (_function.overrides())
|
if (_function.overrides())
|
||||||
@ -116,21 +116,24 @@ private:
|
|||||||
std::vector<int> m_parent = std::vector<int>(m_graph.numNodes, -1);
|
std::vector<int> m_parent = std::vector<int>(m_graph.numNodes, -1);
|
||||||
std::set<OverrideProxy> m_cutVertices{};
|
std::set<OverrideProxy> m_cutVertices{};
|
||||||
|
|
||||||
void run(int _u = 0, int _depth = 0)
|
void run(size_t _u = 0, size_t _depth = 0)
|
||||||
{
|
{
|
||||||
m_visited.at(_u) = true;
|
m_visited.at(_u) = true;
|
||||||
m_depths.at(_u) = m_low.at(_u) = _depth;
|
m_depths.at(_u) = m_low.at(_u) = static_cast<int>(_depth);
|
||||||
for (int v: m_graph.edges.at(_u))
|
for (int const v: m_graph.edges.at(static_cast<int>(_u)))
|
||||||
if (!m_visited.at(v))
|
|
||||||
{
|
{
|
||||||
m_parent[v] = _u;
|
auto const vInd = static_cast<size_t>(v);
|
||||||
run(v, _depth + 1);
|
if (!m_visited.at(vInd))
|
||||||
if (m_low[v] >= m_depths[_u] && m_parent[_u] != -1)
|
{
|
||||||
m_cutVertices.insert(m_graph.nodeInv.at(_u));
|
m_parent[vInd] = static_cast<int>(_u);
|
||||||
m_low[_u] = min(m_low[_u], m_low[v]);
|
run(vInd, _depth + 1);
|
||||||
|
if (m_low[vInd] >= m_depths[_u] && m_parent[_u] != -1)
|
||||||
|
m_cutVertices.insert(m_graph.nodeInv.at(static_cast<int>(_u)));
|
||||||
|
m_low[_u] = min(m_low[_u], m_low[vInd]);
|
||||||
}
|
}
|
||||||
else if (v != m_parent[_u])
|
else if (v != m_parent[_u])
|
||||||
m_low[_u] = min(m_low[_u], m_depths[v]);
|
m_low[_u] = min(m_low[_u], m_depths[vInd]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -213,7 +216,7 @@ bool OverrideProxy::CompareBySignature::operator()(OverrideProxy const& _a, Over
|
|||||||
size_t OverrideProxy::id() const
|
size_t OverrideProxy::id() const
|
||||||
{
|
{
|
||||||
return std::visit(GenericVisitor{
|
return std::visit(GenericVisitor{
|
||||||
[&](auto const* _item) -> size_t { return _item->id(); }
|
[&](auto const* _item) -> size_t { return static_cast<size_t>(_item->id()); }
|
||||||
}, m_item);
|
}, m_item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -668,7 +668,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
{
|
{
|
||||||
auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier);
|
auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier);
|
||||||
if (ref == _inlineAssembly.annotation().externalReferences.end())
|
if (ref == _inlineAssembly.annotation().externalReferences.end())
|
||||||
return size_t(-1);
|
return numeric_limits<size_t>::max();
|
||||||
Declaration const* declaration = ref->second.declaration;
|
Declaration const* declaration = ref->second.declaration;
|
||||||
solAssert(!!declaration, "");
|
solAssert(!!declaration, "");
|
||||||
bool requiresStorage = ref->second.isSlot || ref->second.isOffset;
|
bool requiresStorage = ref->second.isSlot || ref->second.isOffset;
|
||||||
@ -678,7 +678,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
if (var->immutable())
|
if (var->immutable())
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(3773_error, _identifier.location, "Assembly access to immutable variables is not supported.");
|
m_errorReporter.typeError(3773_error, _identifier.location, "Assembly access to immutable variables is not supported.");
|
||||||
return size_t(-1);
|
return numeric_limits<size_t>::max();
|
||||||
}
|
}
|
||||||
if (var->isConstant())
|
if (var->isConstant())
|
||||||
{
|
{
|
||||||
@ -687,17 +687,17 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
if (var && !var->value())
|
if (var && !var->value())
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(3224_error, _identifier.location, "Constant has no value.");
|
m_errorReporter.typeError(3224_error, _identifier.location, "Constant has no value.");
|
||||||
return size_t(-1);
|
return numeric_limits<size_t>::max();
|
||||||
}
|
}
|
||||||
else if (_context == yul::IdentifierContext::LValue)
|
else if (_context == yul::IdentifierContext::LValue)
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(6252_error, _identifier.location, "Constant variables cannot be assigned to.");
|
m_errorReporter.typeError(6252_error, _identifier.location, "Constant variables cannot be assigned to.");
|
||||||
return size_t(-1);
|
return numeric_limits<size_t>::max();
|
||||||
}
|
}
|
||||||
else if (requiresStorage)
|
else if (requiresStorage)
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(6617_error, _identifier.location, "The suffixes _offset and _slot can only be used on non-constant storage variables.");
|
m_errorReporter.typeError(6617_error, _identifier.location, "The suffixes _offset and _slot can only be used on non-constant storage variables.");
|
||||||
return size_t(-1);
|
return numeric_limits<size_t>::max();
|
||||||
}
|
}
|
||||||
else if (var && var->value() && !var->value()->annotation().type && !dynamic_cast<Literal const*>(var->value().get()))
|
else if (var && var->value() && !var->value()->annotation().type && !dynamic_cast<Literal const*>(var->value().get()))
|
||||||
{
|
{
|
||||||
@ -725,19 +725,19 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
if (!var->isStateVariable() && !var->type()->dataStoredIn(DataLocation::Storage))
|
if (!var->isStateVariable() && !var->type()->dataStoredIn(DataLocation::Storage))
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(3622_error, _identifier.location, "The suffixes _offset and _slot can only be used on storage variables.");
|
m_errorReporter.typeError(3622_error, _identifier.location, "The suffixes _offset and _slot can only be used on storage variables.");
|
||||||
return size_t(-1);
|
return numeric_limits<size_t>::max();
|
||||||
}
|
}
|
||||||
else if (_context == yul::IdentifierContext::LValue)
|
else if (_context == yul::IdentifierContext::LValue)
|
||||||
{
|
{
|
||||||
if (var->isStateVariable())
|
if (var->isStateVariable())
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(4713_error, _identifier.location, "State variables cannot be assigned to - you have to use \"sstore()\".");
|
m_errorReporter.typeError(4713_error, _identifier.location, "State variables cannot be assigned to - you have to use \"sstore()\".");
|
||||||
return size_t(-1);
|
return numeric_limits<size_t>::max();
|
||||||
}
|
}
|
||||||
else if (ref->second.isOffset)
|
else if (ref->second.isOffset)
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(9739_error, _identifier.location, "Only _slot can be assigned to.");
|
m_errorReporter.typeError(9739_error, _identifier.location, "Only _slot can be assigned to.");
|
||||||
return size_t(-1);
|
return numeric_limits<size_t>::max();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
solAssert(ref->second.isSlot, "");
|
solAssert(ref->second.isSlot, "");
|
||||||
@ -746,12 +746,12 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
else if (!var->isConstant() && var->isStateVariable())
|
else if (!var->isConstant() && var->isStateVariable())
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(1408_error, _identifier.location, "Only local variables are supported. To access storage variables, use the _slot and _offset suffixes.");
|
m_errorReporter.typeError(1408_error, _identifier.location, "Only local variables are supported. To access storage variables, use the _slot and _offset suffixes.");
|
||||||
return size_t(-1);
|
return numeric_limits<size_t>::max();
|
||||||
}
|
}
|
||||||
else if (var->type()->dataStoredIn(DataLocation::Storage))
|
else if (var->type()->dataStoredIn(DataLocation::Storage))
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(9068_error, _identifier.location, "You have to use the _slot or _offset suffix to access storage reference variables.");
|
m_errorReporter.typeError(9068_error, _identifier.location, "You have to use the _slot or _offset suffix to access storage reference variables.");
|
||||||
return size_t(-1);
|
return numeric_limits<size_t>::max();
|
||||||
}
|
}
|
||||||
else if (var->type()->sizeOnStack() != 1)
|
else if (var->type()->sizeOnStack() != 1)
|
||||||
{
|
{
|
||||||
@ -759,21 +759,21 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
m_errorReporter.typeError(2370_error, _identifier.location, "Call data elements cannot be accessed directly. Copy to a local variable first or use \"calldataload\" or \"calldatacopy\" with manually determined offsets and sizes.");
|
m_errorReporter.typeError(2370_error, _identifier.location, "Call data elements cannot be accessed directly. Copy to a local variable first or use \"calldataload\" or \"calldatacopy\" with manually determined offsets and sizes.");
|
||||||
else
|
else
|
||||||
m_errorReporter.typeError(9857_error, _identifier.location, "Only types that use one stack slot are supported.");
|
m_errorReporter.typeError(9857_error, _identifier.location, "Only types that use one stack slot are supported.");
|
||||||
return size_t(-1);
|
return numeric_limits<size_t>::max();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (requiresStorage)
|
else if (requiresStorage)
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(7944_error, _identifier.location, "The suffixes _offset and _slot can only be used on storage variables.");
|
m_errorReporter.typeError(7944_error, _identifier.location, "The suffixes _offset and _slot can only be used on storage variables.");
|
||||||
return size_t(-1);
|
return numeric_limits<size_t>::max();
|
||||||
}
|
}
|
||||||
else if (_context == yul::IdentifierContext::LValue)
|
else if (_context == yul::IdentifierContext::LValue)
|
||||||
{
|
{
|
||||||
if (dynamic_cast<MagicVariableDeclaration const*>(declaration))
|
if (dynamic_cast<MagicVariableDeclaration const*>(declaration))
|
||||||
return size_t(-1);
|
return numeric_limits<size_t>::max();
|
||||||
|
|
||||||
m_errorReporter.typeError(1990_error, _identifier.location, "Only local variables can be assigned to in inline assembly.");
|
m_errorReporter.typeError(1990_error, _identifier.location, "Only local variables can be assigned to in inline assembly.");
|
||||||
return size_t(-1);
|
return numeric_limits<size_t>::max();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_context == yul::IdentifierContext::RValue)
|
if (_context == yul::IdentifierContext::RValue)
|
||||||
@ -782,7 +782,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
if (dynamic_cast<FunctionDefinition const*>(declaration))
|
if (dynamic_cast<FunctionDefinition const*>(declaration))
|
||||||
{
|
{
|
||||||
m_errorReporter.declarationError(2025_error, _identifier.location, "Access to functions is not allowed in inline assembly.");
|
m_errorReporter.declarationError(2025_error, _identifier.location, "Access to functions is not allowed in inline assembly.");
|
||||||
return size_t(-1);
|
return numeric_limits<size_t>::max();
|
||||||
}
|
}
|
||||||
else if (dynamic_cast<VariableDeclaration const*>(declaration))
|
else if (dynamic_cast<VariableDeclaration const*>(declaration))
|
||||||
{
|
{
|
||||||
@ -792,11 +792,11 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
if (!contract->isLibrary())
|
if (!contract->isLibrary())
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(4977_error, _identifier.location, "Expected a library.");
|
m_errorReporter.typeError(4977_error, _identifier.location, "Expected a library.");
|
||||||
return size_t(-1);
|
return numeric_limits<size_t>::max();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return size_t(-1);
|
return numeric_limits<size_t>::max();
|
||||||
}
|
}
|
||||||
ref->second.valueSize = 1;
|
ref->second.valueSize = 1;
|
||||||
return size_t(1);
|
return size_t(1);
|
||||||
|
@ -38,7 +38,7 @@ using namespace solidity;
|
|||||||
using namespace solidity::frontend;
|
using namespace solidity::frontend;
|
||||||
|
|
||||||
ASTNode::ASTNode(int64_t _id, SourceLocation _location):
|
ASTNode::ASTNode(int64_t _id, SourceLocation _location):
|
||||||
m_id(_id),
|
m_id(static_cast<size_t>(_id)),
|
||||||
m_location(std::move(_location))
|
m_location(std::move(_location))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ public:
|
|||||||
virtual ~ASTNode() {}
|
virtual ~ASTNode() {}
|
||||||
|
|
||||||
/// @returns an identifier of this AST node that is unique for a single compilation run.
|
/// @returns an identifier of this AST node that is unique for a single compilation run.
|
||||||
int64_t id() const { return m_id; }
|
int64_t id() const { return int64_t(m_id); }
|
||||||
|
|
||||||
virtual void accept(ASTVisitor& _visitor) = 0;
|
virtual void accept(ASTVisitor& _visitor) = 0;
|
||||||
virtual void accept(ASTConstVisitor& _visitor) const = 0;
|
virtual void accept(ASTConstVisitor& _visitor) const = 0;
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace solidity::langutil;
|
using namespace solidity::langutil;
|
||||||
@ -134,7 +135,7 @@ size_t ASTJsonConverter::sourceIndexFromLocation(SourceLocation const& _location
|
|||||||
if (_location.source && m_sourceIndices.count(_location.source->name()))
|
if (_location.source && m_sourceIndices.count(_location.source->name()))
|
||||||
return m_sourceIndices.at(_location.source->name());
|
return m_sourceIndices.at(_location.source->name());
|
||||||
else
|
else
|
||||||
return size_t(-1);
|
return numeric_limits<size_t>::max();
|
||||||
}
|
}
|
||||||
|
|
||||||
string ASTJsonConverter::sourceLocationToString(SourceLocation const& _location) const
|
string ASTJsonConverter::sourceLocationToString(SourceLocation const& _location) const
|
||||||
|
@ -92,7 +92,7 @@ SourceLocation const ASTJsonImporter::createSourceLocation(Json::Value const& _n
|
|||||||
{
|
{
|
||||||
astAssert(member(_node, "src").isString(), "'src' must be a string");
|
astAssert(member(_node, "src").isString(), "'src' must be a string");
|
||||||
|
|
||||||
return solidity::langutil::parseSourceLocation(_node["src"].asString(), m_currentSourceName, int(m_sourceLocations.size()));
|
return solidity::langutil::parseSourceLocation(_node["src"].asString(), m_currentSourceName, m_sourceLocations.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
|
@ -113,14 +113,22 @@ public:
|
|||||||
/// @returns a copy of @a _type having the same location as this (and is not a pointer type)
|
/// @returns a copy of @a _type having the same location as this (and is not a pointer type)
|
||||||
/// if _type is a reference type and an unmodified copy of _type otherwise.
|
/// if _type is a reference type and an unmodified copy of _type otherwise.
|
||||||
/// This function is mostly useful to modify inner types appropriately.
|
/// This function is mostly useful to modify inner types appropriately.
|
||||||
static Type const* withLocationIfReference(DataLocation _location, Type const* _type)
|
static Type const* withLocationIfReference(DataLocation _location, Type const* _type, bool _isPointer = false)
|
||||||
{
|
{
|
||||||
if (auto refType = dynamic_cast<ReferenceType const*>(_type))
|
if (auto refType = dynamic_cast<ReferenceType const*>(_type))
|
||||||
return withLocation(refType, _location, false);
|
return withLocation(refType, _location, _isPointer);
|
||||||
|
|
||||||
return _type;
|
return _type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool isReferenceWithLocation(Type const* _type, DataLocation _location)
|
||||||
|
{
|
||||||
|
if (auto const* refType = dynamic_cast<ReferenceType const*>(_type))
|
||||||
|
if (refType->location() == _location)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// @returns the internally-facing or externally-facing type of a function or the type of a function declaration.
|
/// @returns the internally-facing or externally-facing type of a function or the type of a function declaration.
|
||||||
static FunctionType const* function(FunctionDefinition const& _function, FunctionType::Kind _kind = FunctionType::Kind::Declaration);
|
static FunctionType const* function(FunctionDefinition const& _function, FunctionType::Kind _kind = FunctionType::Kind::Declaration);
|
||||||
|
|
||||||
|
@ -356,10 +356,18 @@ MemberList::MemberMap Type::boundFunctions(Type const& _type, ContractDefinition
|
|||||||
for (ContractDefinition const* contract: _scope.annotation().linearizedBaseContracts)
|
for (ContractDefinition const* contract: _scope.annotation().linearizedBaseContracts)
|
||||||
for (UsingForDirective const* ufd: contract->usingForDirectives())
|
for (UsingForDirective const* ufd: contract->usingForDirectives())
|
||||||
{
|
{
|
||||||
if (ufd->typeName() && _type != *TypeProvider::withLocationIfReference(
|
// Convert both types to pointers for comparison to see if the `using for`
|
||||||
|
// directive applies.
|
||||||
|
// Further down, we check more detailed for each function if `_type` is
|
||||||
|
// convertible to the function parameter type.
|
||||||
|
if (ufd->typeName() &&
|
||||||
|
*TypeProvider::withLocationIfReference(typeLocation, &_type, true) !=
|
||||||
|
*TypeProvider::withLocationIfReference(
|
||||||
typeLocation,
|
typeLocation,
|
||||||
ufd->typeName()->annotation().type
|
ufd->typeName()->annotation().type,
|
||||||
))
|
true
|
||||||
|
)
|
||||||
|
)
|
||||||
continue;
|
continue;
|
||||||
auto const& library = dynamic_cast<ContractDefinition const&>(
|
auto const& library = dynamic_cast<ContractDefinition const&>(
|
||||||
*ufd->libraryName().annotation().referencedDeclaration
|
*ufd->libraryName().annotation().referencedDeclaration
|
||||||
@ -371,7 +379,8 @@ MemberList::MemberMap Type::boundFunctions(Type const& _type, ContractDefinition
|
|||||||
seenFunctions.insert(function);
|
seenFunctions.insert(function);
|
||||||
if (function->parameters().empty())
|
if (function->parameters().empty())
|
||||||
continue;
|
continue;
|
||||||
FunctionTypePointer fun = FunctionType(*function, FunctionType::Kind::External).asExternallyCallableFunction(true, true);
|
FunctionTypePointer fun =
|
||||||
|
dynamic_cast<FunctionType const&>(*function->typeViaContractName()).asBoundFunction();
|
||||||
if (_type.isImplicitlyConvertibleTo(*fun->selfType()))
|
if (_type.isImplicitlyConvertibleTo(*fun->selfType()))
|
||||||
members.emplace_back(function->name(), fun, function);
|
members.emplace_back(function->name(), fun, function);
|
||||||
}
|
}
|
||||||
@ -773,7 +782,7 @@ tuple<bool, rational> RationalNumberType::parseRational(string const& _value)
|
|||||||
denominator = bigint(string(fractionalBegin, _value.end()));
|
denominator = bigint(string(fractionalBegin, _value.end()));
|
||||||
denominator /= boost::multiprecision::pow(
|
denominator /= boost::multiprecision::pow(
|
||||||
bigint(10),
|
bigint(10),
|
||||||
distance(radixPoint + 1, _value.end())
|
static_cast<size_t>(distance(radixPoint + 1, _value.end()))
|
||||||
);
|
);
|
||||||
numerator = bigint(string(_value.begin(), radixPoint));
|
numerator = bigint(string(_value.begin(), radixPoint));
|
||||||
value = numerator + denominator;
|
value = numerator + denominator;
|
||||||
@ -1093,7 +1102,7 @@ TypeResult RationalNumberType::binaryOperatorResult(Token _operator, Type const*
|
|||||||
if (_base == 1)
|
if (_base == 1)
|
||||||
return 1;
|
return 1;
|
||||||
else if (_base == -1)
|
else if (_base == -1)
|
||||||
return 1 - 2 * int(_exponent & 1);
|
return 1 - 2 * static_cast<int>(_exponent & 1);
|
||||||
else
|
else
|
||||||
return boost::multiprecision::pow(_base, _exponent);
|
return boost::multiprecision::pow(_base, _exponent);
|
||||||
};
|
};
|
||||||
@ -1199,7 +1208,7 @@ string RationalNumberType::bigintToReadableString(bigint const& _num)
|
|||||||
string str = _num.str();
|
string str = _num.str();
|
||||||
if (str.size() > 32)
|
if (str.size() > 32)
|
||||||
{
|
{
|
||||||
int omitted = str.size() - 8;
|
size_t omitted = str.size() - 8;
|
||||||
str = str.substr(0, 4) + "...(" + to_string(omitted) + " digits omitted)..." + str.substr(str.size() - 4, 4);
|
str = str.substr(0, 4) + "...(" + to_string(omitted) + " digits omitted)..." + str.substr(str.size() - 4, 4);
|
||||||
}
|
}
|
||||||
return str;
|
return str;
|
||||||
@ -1229,7 +1238,7 @@ u256 RationalNumberType::literalValue(Literal const*) const
|
|||||||
{
|
{
|
||||||
auto fixed = fixedPointType();
|
auto fixed = fixedPointType();
|
||||||
solAssert(fixed, "Rational number cannot be represented as fixed point type.");
|
solAssert(fixed, "Rational number cannot be represented as fixed point type.");
|
||||||
int fractionalDigits = fixed->fractionalDigits();
|
unsigned fractionalDigits = fixed->fractionalDigits();
|
||||||
shiftedValue = m_value.numerator() * boost::multiprecision::pow(bigint(10), fractionalDigits) / m_value.denominator();
|
shiftedValue = m_value.numerator() * boost::multiprecision::pow(bigint(10), fractionalDigits) / m_value.denominator();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1319,7 +1328,7 @@ StringLiteralType::StringLiteralType(string _value):
|
|||||||
BoolResult StringLiteralType::isImplicitlyConvertibleTo(Type const& _convertTo) const
|
BoolResult StringLiteralType::isImplicitlyConvertibleTo(Type const& _convertTo) const
|
||||||
{
|
{
|
||||||
if (auto fixedBytes = dynamic_cast<FixedBytesType const*>(&_convertTo))
|
if (auto fixedBytes = dynamic_cast<FixedBytesType const*>(&_convertTo))
|
||||||
return size_t(fixedBytes->numBytes()) >= m_value.size();
|
return static_cast<size_t>(fixedBytes->numBytes()) >= m_value.size();
|
||||||
else if (auto arrayType = dynamic_cast<ArrayType const*>(&_convertTo))
|
else if (auto arrayType = dynamic_cast<ArrayType const*>(&_convertTo))
|
||||||
return
|
return
|
||||||
arrayType->isByteArray() &&
|
arrayType->isByteArray() &&
|
||||||
@ -2485,6 +2494,21 @@ set<string> StructType::membersMissingInMemory() const
|
|||||||
return missing;
|
return missing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vector<tuple<string, TypePointer>> StructType::makeStackItems() const
|
||||||
|
{
|
||||||
|
switch (m_location)
|
||||||
|
{
|
||||||
|
case DataLocation::CallData:
|
||||||
|
return {std::make_tuple("offset", TypeProvider::uint256())};
|
||||||
|
case DataLocation::Memory:
|
||||||
|
return {std::make_tuple("mpos", TypeProvider::uint256())};
|
||||||
|
case DataLocation::Storage:
|
||||||
|
return {std::make_tuple("slot", TypeProvider::uint256())};
|
||||||
|
}
|
||||||
|
solAssert(false, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
TypePointer EnumType::encodingType() const
|
TypePointer EnumType::encodingType() const
|
||||||
{
|
{
|
||||||
return TypeProvider::uint(8 * storageBytes());
|
return TypeProvider::uint(8 * storageBytes());
|
||||||
@ -3466,34 +3490,61 @@ TypePointer FunctionType::copyAndSetCallOptions(bool _setGas, bool _setValue, bo
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionTypePointer FunctionType::asExternallyCallableFunction(bool _inLibrary, bool _bound) const
|
FunctionTypePointer FunctionType::asBoundFunction() const
|
||||||
{
|
{
|
||||||
if (_bound)
|
|
||||||
solAssert(!m_parameterTypes.empty(), "");
|
solAssert(!m_parameterTypes.empty(), "");
|
||||||
|
FunctionDefinition const* fun = dynamic_cast<FunctionDefinition const*>(m_declaration);
|
||||||
|
solAssert(fun && fun->libraryFunction(), "");
|
||||||
|
solAssert(!m_gasSet, "");
|
||||||
|
solAssert(!m_valueSet, "");
|
||||||
|
solAssert(!m_saltSet, "");
|
||||||
|
return TypeProvider::function(
|
||||||
|
m_parameterTypes,
|
||||||
|
m_returnParameterTypes,
|
||||||
|
m_parameterNames,
|
||||||
|
m_returnParameterNames,
|
||||||
|
m_kind,
|
||||||
|
m_arbitraryParameters,
|
||||||
|
m_stateMutability,
|
||||||
|
m_declaration,
|
||||||
|
m_gasSet,
|
||||||
|
m_valueSet,
|
||||||
|
m_saltSet,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
FunctionTypePointer FunctionType::asExternallyCallableFunction(bool _inLibrary) const
|
||||||
|
{
|
||||||
TypePointers parameterTypes;
|
TypePointers parameterTypes;
|
||||||
for (auto const& t: m_parameterTypes)
|
for (auto const& t: m_parameterTypes)
|
||||||
{
|
if (TypeProvider::isReferenceWithLocation(t, DataLocation::CallData))
|
||||||
auto refType = dynamic_cast<ReferenceType const*>(t);
|
parameterTypes.push_back(
|
||||||
if (refType && refType->location() == DataLocation::CallData)
|
TypeProvider::withLocationIfReference(DataLocation::Memory, t, true)
|
||||||
parameterTypes.push_back(TypeProvider::withLocation(refType, DataLocation::Memory, true));
|
);
|
||||||
else
|
else
|
||||||
parameterTypes.push_back(t);
|
parameterTypes.push_back(t);
|
||||||
}
|
|
||||||
|
TypePointers returnParameterTypes;
|
||||||
|
for (auto const& returnParamType: m_returnParameterTypes)
|
||||||
|
if (TypeProvider::isReferenceWithLocation(returnParamType, DataLocation::CallData))
|
||||||
|
returnParameterTypes.push_back(
|
||||||
|
TypeProvider::withLocationIfReference(DataLocation::Memory, returnParamType, true)
|
||||||
|
);
|
||||||
|
else
|
||||||
|
returnParameterTypes.push_back(returnParamType);
|
||||||
|
|
||||||
Kind kind = m_kind;
|
Kind kind = m_kind;
|
||||||
if (_inLibrary)
|
if (_inLibrary)
|
||||||
{
|
{
|
||||||
solAssert(!!m_declaration, "Declaration has to be available.");
|
solAssert(!!m_declaration, "Declaration has to be available.");
|
||||||
if (!m_declaration->isPublic())
|
solAssert(m_declaration->isPublic(), "");
|
||||||
kind = Kind::Internal; // will be inlined
|
|
||||||
else
|
|
||||||
kind = Kind::DelegateCall;
|
kind = Kind::DelegateCall;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TypeProvider::function(
|
return TypeProvider::function(
|
||||||
parameterTypes,
|
parameterTypes,
|
||||||
m_returnParameterTypes,
|
returnParameterTypes,
|
||||||
m_parameterNames,
|
m_parameterNames,
|
||||||
m_returnParameterNames,
|
m_returnParameterNames,
|
||||||
kind,
|
kind,
|
||||||
@ -3503,7 +3554,7 @@ FunctionTypePointer FunctionType::asExternallyCallableFunction(bool _inLibrary,
|
|||||||
m_gasSet,
|
m_gasSet,
|
||||||
m_valueSet,
|
m_valueSet,
|
||||||
m_saltSet,
|
m_saltSet,
|
||||||
_bound
|
m_bound
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -980,6 +980,8 @@ public:
|
|||||||
|
|
||||||
void clearCache() const override;
|
void clearCache() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::vector<std::tuple<std::string, TypePointer>> makeStackItems() const override;
|
||||||
private:
|
private:
|
||||||
StructDefinition const& m_struct;
|
StructDefinition const& m_struct;
|
||||||
// Caches for interfaceType(bool)
|
// Caches for interfaceType(bool)
|
||||||
@ -1302,13 +1304,16 @@ public:
|
|||||||
/// of the parameters to false.
|
/// of the parameters to false.
|
||||||
TypePointer copyAndSetCallOptions(bool _setGas, bool _setValue, bool _setSalt) const;
|
TypePointer copyAndSetCallOptions(bool _setGas, bool _setValue, bool _setSalt) const;
|
||||||
|
|
||||||
|
/// @returns a copy of this function type with the `bound` flag set to true.
|
||||||
|
/// Should only be called on library functions.
|
||||||
|
FunctionTypePointer asBoundFunction() const;
|
||||||
|
|
||||||
/// @returns a copy of this function type where the location of reference types is changed
|
/// @returns a copy of this function type where the location of reference types is changed
|
||||||
/// from CallData to Memory. This is the type that would be used when the function is
|
/// from CallData to Memory. This is the type that would be used when the function is
|
||||||
/// called externally, as opposed to the parameter types that are available inside the function body.
|
/// called externally, as opposed to the parameter types that are available inside the function body.
|
||||||
/// Also supports variants to be used for library or bound calls.
|
/// Also supports variants to be used for library or bound calls.
|
||||||
/// @param _inLibrary if true, uses DelegateCall as location.
|
/// @param _inLibrary if true, uses DelegateCall as location.
|
||||||
/// @param _bound if true, the function type is set to be bound.
|
FunctionTypePointer asExternallyCallableFunction(bool _inLibrary) const;
|
||||||
FunctionTypePointer asExternallyCallableFunction(bool _inLibrary, bool _bound = false) const;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::vector<std::tuple<std::string, TypePointer>> makeStackItems() const override;
|
std::vector<std::tuple<std::string, TypePointer>> makeStackItems() const override;
|
||||||
|
@ -725,7 +725,7 @@ string ABIFunctions::abiEncodingFunctionCompactStorageArray(
|
|||||||
size_t itemsPerSlot = 32 / storageBytes;
|
size_t itemsPerSlot = 32 / storageBytes;
|
||||||
solAssert(itemsPerSlot > 0, "");
|
solAssert(itemsPerSlot > 0, "");
|
||||||
// The number of elements we need to handle manually after the loop.
|
// The number of elements we need to handle manually after the loop.
|
||||||
size_t spill = size_t(_from.length() % itemsPerSlot);
|
size_t spill = static_cast<size_t>(_from.length() % itemsPerSlot);
|
||||||
Whiskers templ(
|
Whiskers templ(
|
||||||
R"(
|
R"(
|
||||||
// <readableTypeNameFrom> -> <readableTypeNameTo>
|
// <readableTypeNameFrom> -> <readableTypeNameTo>
|
||||||
|
@ -56,7 +56,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
|||||||
bool directCopy = sourceIsStorage && sourceBaseType->isValueType() && *sourceBaseType == *targetBaseType;
|
bool directCopy = sourceIsStorage && sourceBaseType->isValueType() && *sourceBaseType == *targetBaseType;
|
||||||
bool haveByteOffsetSource = !directCopy && sourceIsStorage && sourceBaseType->storageBytes() <= 16;
|
bool haveByteOffsetSource = !directCopy && sourceIsStorage && sourceBaseType->storageBytes() <= 16;
|
||||||
bool haveByteOffsetTarget = !directCopy && targetBaseType->storageBytes() <= 16;
|
bool haveByteOffsetTarget = !directCopy && targetBaseType->storageBytes() <= 16;
|
||||||
unsigned byteOffsetSize = (haveByteOffsetSource ? 1 : 0) + (haveByteOffsetTarget ? 1 : 0);
|
unsigned byteOffsetSize = (haveByteOffsetSource ? 1u : 0u) + (haveByteOffsetTarget ? 1u : 0u);
|
||||||
|
|
||||||
// stack: source_ref [source_length] target_ref
|
// stack: source_ref [source_length] target_ref
|
||||||
// store target_ref
|
// store target_ref
|
||||||
|
@ -133,7 +133,7 @@ void CompilerContext::callLowLevelFunction(
|
|||||||
*this << lowLevelFunctionTag(_name, _inArgs, _outArgs, _generator);
|
*this << lowLevelFunctionTag(_name, _inArgs, _outArgs, _generator);
|
||||||
|
|
||||||
appendJump(evmasm::AssemblyItem::JumpType::IntoFunction);
|
appendJump(evmasm::AssemblyItem::JumpType::IntoFunction);
|
||||||
adjustStackOffset(int(_outArgs) - 1 - _inArgs);
|
adjustStackOffset(static_cast<int>(_outArgs) - 1 - static_cast<int>(_inArgs));
|
||||||
*this << retTag.tag();
|
*this << retTag.tag();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,7 +147,7 @@ void CompilerContext::callYulFunction(
|
|||||||
auto const retTag = pushNewTag();
|
auto const retTag = pushNewTag();
|
||||||
CompilerUtils(*this).moveIntoStack(_inArgs);
|
CompilerUtils(*this).moveIntoStack(_inArgs);
|
||||||
appendJumpTo(namedTag(_name));
|
appendJumpTo(namedTag(_name));
|
||||||
adjustStackOffset(int(_outArgs) - 1 - _inArgs);
|
adjustStackOffset(static_cast<int>(_outArgs) - 1 - static_cast<int>(_inArgs));
|
||||||
*this << retTag.tag();
|
*this << retTag.tag();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,7 +181,7 @@ void CompilerContext::appendMissingLowLevelFunctions()
|
|||||||
tie(name, inArgs, outArgs, generator) = m_lowLevelFunctionGenerationQueue.front();
|
tie(name, inArgs, outArgs, generator) = m_lowLevelFunctionGenerationQueue.front();
|
||||||
m_lowLevelFunctionGenerationQueue.pop();
|
m_lowLevelFunctionGenerationQueue.pop();
|
||||||
|
|
||||||
setStackOffset(inArgs + 1);
|
setStackOffset(static_cast<int>(inArgs) + 1);
|
||||||
*this << m_lowLevelFunctions.at(name).tag();
|
*this << m_lowLevelFunctions.at(name).tag();
|
||||||
generator(*this);
|
generator(*this);
|
||||||
CompilerUtils(*this).moveToStackTop(outArgs);
|
CompilerUtils(*this).moveToStackTop(outArgs);
|
||||||
@ -298,12 +298,12 @@ unsigned CompilerContext::baseStackOffsetOfVariable(Declaration const& _declarat
|
|||||||
|
|
||||||
unsigned CompilerContext::baseToCurrentStackOffset(unsigned _baseOffset) const
|
unsigned CompilerContext::baseToCurrentStackOffset(unsigned _baseOffset) const
|
||||||
{
|
{
|
||||||
return m_asm->deposit() - _baseOffset - 1;
|
return static_cast<unsigned>(m_asm->deposit()) - _baseOffset - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned CompilerContext::currentToBaseStackOffset(unsigned _offset) const
|
unsigned CompilerContext::currentToBaseStackOffset(unsigned _offset) const
|
||||||
{
|
{
|
||||||
return m_asm->deposit() - _offset - 1;
|
return static_cast<unsigned>(m_asm->deposit()) - _offset - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pair<u256, unsigned> CompilerContext::storageLocationOfVariable(Declaration const& _declaration) const
|
pair<u256, unsigned> CompilerContext::storageLocationOfVariable(Declaration const& _declaration) const
|
||||||
@ -371,7 +371,7 @@ void CompilerContext::appendInlineAssembly(
|
|||||||
OptimiserSettings const& _optimiserSettings
|
OptimiserSettings const& _optimiserSettings
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
int startStackHeight = stackHeight();
|
unsigned startStackHeight = stackHeight();
|
||||||
|
|
||||||
set<yul::YulString> externallyUsedIdentifiers;
|
set<yul::YulString> externallyUsedIdentifiers;
|
||||||
for (auto const& fun: _externallyUsedFunctions)
|
for (auto const& fun: _externallyUsedFunctions)
|
||||||
@ -387,9 +387,9 @@ void CompilerContext::appendInlineAssembly(
|
|||||||
) -> size_t
|
) -> size_t
|
||||||
{
|
{
|
||||||
if (_insideFunction)
|
if (_insideFunction)
|
||||||
return size_t(-1);
|
return numeric_limits<size_t>::max();
|
||||||
auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name.str());
|
auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name.str());
|
||||||
return it == _localVariables.end() ? size_t(-1) : 1;
|
return it == _localVariables.end() ? numeric_limits<size_t>::max() : 1;
|
||||||
};
|
};
|
||||||
identifierAccess.generateCode = [&](
|
identifierAccess.generateCode = [&](
|
||||||
yul::Identifier const& _identifier,
|
yul::Identifier const& _identifier,
|
||||||
@ -399,8 +399,8 @@ void CompilerContext::appendInlineAssembly(
|
|||||||
{
|
{
|
||||||
auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name.str());
|
auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name.str());
|
||||||
solAssert(it != _localVariables.end(), "");
|
solAssert(it != _localVariables.end(), "");
|
||||||
int stackDepth = _localVariables.end() - it;
|
auto stackDepth = static_cast<size_t>(distance(it, _localVariables.end()));
|
||||||
int stackDiff = _assembly.stackHeight() - startStackHeight + stackDepth;
|
size_t stackDiff = static_cast<size_t>(_assembly.stackHeight()) - startStackHeight + stackDepth;
|
||||||
if (_context == yul::IdentifierContext::LValue)
|
if (_context == yul::IdentifierContext::LValue)
|
||||||
stackDiff -= 1;
|
stackDiff -= 1;
|
||||||
if (stackDiff < 1 || stackDiff > 16)
|
if (stackDiff < 1 || stackDiff > 16)
|
||||||
|
@ -377,7 +377,7 @@ private:
|
|||||||
/// The runtime context if in Creation mode, this is used for generating tags that would be stored into the storage and then used at runtime.
|
/// The runtime context if in Creation mode, this is used for generating tags that would be stored into the storage and then used at runtime.
|
||||||
CompilerContext *m_runtimeContext;
|
CompilerContext *m_runtimeContext;
|
||||||
/// The index of the runtime subroutine.
|
/// The index of the runtime subroutine.
|
||||||
size_t m_runtimeSub = -1;
|
size_t m_runtimeSub = std::numeric_limits<size_t>::max();
|
||||||
/// An index of low-level function labels by name.
|
/// An index of low-level function labels by name.
|
||||||
std::map<std::string, evmasm::AssemblyItem> m_lowLevelFunctions;
|
std::map<std::string, evmasm::AssemblyItem> m_lowLevelFunctions;
|
||||||
/// Collector for yul functions.
|
/// Collector for yul functions.
|
||||||
|
@ -1351,7 +1351,7 @@ void CompilerUtils::popAndJump(unsigned _toHeight, evmasm::AssemblyItem const& _
|
|||||||
unsigned amount = m_context.stackHeight() - _toHeight;
|
unsigned amount = m_context.stackHeight() - _toHeight;
|
||||||
popStackSlots(amount);
|
popStackSlots(amount);
|
||||||
m_context.appendJumpTo(_jumpTo);
|
m_context.appendJumpTo(_jumpTo);
|
||||||
m_context.adjustStackOffset(amount);
|
m_context.adjustStackOffset(static_cast<int>(amount));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned CompilerUtils::sizeOnStack(vector<Type const*> const& _variableTypes)
|
unsigned CompilerUtils::sizeOnStack(vector<Type const*> const& _variableTypes)
|
||||||
@ -1436,7 +1436,7 @@ unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCallda
|
|||||||
{
|
{
|
||||||
bool leftAligned = _type.category() == Type::Category::FixedBytes;
|
bool leftAligned = _type.category() == Type::Category::FixedBytes;
|
||||||
// add leading or trailing zeros by dividing/multiplying depending on alignment
|
// add leading or trailing zeros by dividing/multiplying depending on alignment
|
||||||
int shiftFactor = (32 - numBytes) * 8;
|
unsigned shiftFactor = (32 - numBytes) * 8;
|
||||||
rightShiftNumberOnStack(shiftFactor);
|
rightShiftNumberOnStack(shiftFactor);
|
||||||
if (leftAligned)
|
if (leftAligned)
|
||||||
{
|
{
|
||||||
|
@ -185,7 +185,7 @@ size_t ContractCompiler::packIntoContractCreator(ContractDefinition const& _cont
|
|||||||
CompilerContext::LocationSetter locationSetter(m_context, _contract);
|
CompilerContext::LocationSetter locationSetter(m_context, _contract);
|
||||||
m_context << deployRoutine;
|
m_context << deployRoutine;
|
||||||
|
|
||||||
solAssert(m_context.runtimeSub() != size_t(-1), "Runtime sub not registered");
|
solAssert(m_context.runtimeSub() != numeric_limits<size_t>::max(), "Runtime sub not registered");
|
||||||
|
|
||||||
ContractType contractType(_contract);
|
ContractType contractType(_contract);
|
||||||
auto const& immutables = contractType.immutableVariables();
|
auto const& immutables = contractType.immutableVariables();
|
||||||
@ -221,7 +221,7 @@ size_t ContractCompiler::deployLibrary(ContractDefinition const& _contract)
|
|||||||
|
|
||||||
CompilerContext::LocationSetter locationSetter(m_context, _contract);
|
CompilerContext::LocationSetter locationSetter(m_context, _contract);
|
||||||
|
|
||||||
solAssert(m_context.runtimeSub() != size_t(-1), "Runtime sub not registered");
|
solAssert(m_context.runtimeSub() != numeric_limits<size_t>::max(), "Runtime sub not registered");
|
||||||
m_context.pushSubroutineSize(m_context.runtimeSub());
|
m_context.pushSubroutineSize(m_context.runtimeSub());
|
||||||
m_context.pushSubroutineOffset(m_context.runtimeSub());
|
m_context.pushSubroutineOffset(m_context.runtimeSub());
|
||||||
// This code replaces the address added by appendDeployTimeAddress().
|
// This code replaces the address added by appendDeployTimeAddress().
|
||||||
@ -349,11 +349,11 @@ void ContractCompiler::appendInternalSelector(
|
|||||||
m_context << dupInstruction(1) << u256(FixedHash<4>::Arith(pivot)) << Instruction::GT;
|
m_context << dupInstruction(1) << u256(FixedHash<4>::Arith(pivot)) << Instruction::GT;
|
||||||
evmasm::AssemblyItem lessTag{m_context.appendConditionalJump()};
|
evmasm::AssemblyItem lessTag{m_context.appendConditionalJump()};
|
||||||
// Here, we have funid >= pivot
|
// Here, we have funid >= pivot
|
||||||
vector<FixedHash<4>> larger{_ids.begin() + pivotIndex, _ids.end()};
|
vector<FixedHash<4>> larger{_ids.begin() + static_cast<ptrdiff_t>(pivotIndex), _ids.end()};
|
||||||
appendInternalSelector(_entryPoints, larger, _notFoundTag, _runs);
|
appendInternalSelector(_entryPoints, larger, _notFoundTag, _runs);
|
||||||
m_context << lessTag;
|
m_context << lessTag;
|
||||||
// Here, we have funid < pivot
|
// Here, we have funid < pivot
|
||||||
vector<FixedHash<4>> smaller{_ids.begin(), _ids.begin() + pivotIndex};
|
vector<FixedHash<4>> smaller{_ids.begin(), _ids.begin() + static_cast<ptrdiff_t>(pivotIndex)};
|
||||||
appendInternalSelector(_entryPoints, smaller, _notFoundTag, _runs);
|
appendInternalSelector(_entryPoints, smaller, _notFoundTag, _runs);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -512,8 +512,8 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac
|
|||||||
m_context << returnTag;
|
m_context << returnTag;
|
||||||
// Return tag and input parameters get consumed.
|
// Return tag and input parameters get consumed.
|
||||||
m_context.adjustStackOffset(
|
m_context.adjustStackOffset(
|
||||||
CompilerUtils(m_context).sizeOnStack(functionType->returnParameterTypes()) -
|
static_cast<int>(CompilerUtils::sizeOnStack(functionType->returnParameterTypes())) -
|
||||||
CompilerUtils(m_context).sizeOnStack(functionType->parameterTypes()) -
|
static_cast<int>(CompilerUtils::sizeOnStack(functionType->parameterTypes())) -
|
||||||
1
|
1
|
||||||
);
|
);
|
||||||
// Consumes the return parameters.
|
// Consumes the return parameters.
|
||||||
@ -589,7 +589,7 @@ bool ContractCompiler::visit(FunctionDefinition const& _function)
|
|||||||
unsigned parametersSize = CompilerUtils::sizeOnStack(_function.parameters());
|
unsigned parametersSize = CompilerUtils::sizeOnStack(_function.parameters());
|
||||||
if (!_function.isConstructor())
|
if (!_function.isConstructor())
|
||||||
// adding 1 for return address.
|
// adding 1 for return address.
|
||||||
m_context.adjustStackOffset(parametersSize + 1);
|
m_context.adjustStackOffset(static_cast<int>(parametersSize) + 1);
|
||||||
for (ASTPointer<VariableDeclaration> const& variable: _function.parameters())
|
for (ASTPointer<VariableDeclaration> const& variable: _function.parameters())
|
||||||
{
|
{
|
||||||
m_context.addVariable(*variable, parametersSize);
|
m_context.addVariable(*variable, parametersSize);
|
||||||
@ -609,7 +609,7 @@ bool ContractCompiler::visit(FunctionDefinition const& _function)
|
|||||||
m_breakTags.clear();
|
m_breakTags.clear();
|
||||||
m_continueTags.clear();
|
m_continueTags.clear();
|
||||||
m_currentFunction = &_function;
|
m_currentFunction = &_function;
|
||||||
m_modifierDepth = -1;
|
m_modifierDepth = numeric_limits<unsigned>::max();
|
||||||
m_scopeStackHeight.clear();
|
m_scopeStackHeight.clear();
|
||||||
m_context.setModifierDepth(0);
|
m_context.setModifierDepth(0);
|
||||||
|
|
||||||
@ -627,10 +627,10 @@ bool ContractCompiler::visit(FunctionDefinition const& _function)
|
|||||||
unsigned const c_returnValuesSize = CompilerUtils::sizeOnStack(_function.returnParameters());
|
unsigned const c_returnValuesSize = CompilerUtils::sizeOnStack(_function.returnParameters());
|
||||||
|
|
||||||
vector<int> stackLayout;
|
vector<int> stackLayout;
|
||||||
stackLayout.push_back(c_returnValuesSize); // target of return address
|
stackLayout.push_back(static_cast<int>(c_returnValuesSize)); // target of return address
|
||||||
stackLayout += vector<int>(c_argumentsSize, -1); // discard all arguments
|
stackLayout += vector<int>(c_argumentsSize, -1); // discard all arguments
|
||||||
for (unsigned i = 0; i < c_returnValuesSize; ++i)
|
for (size_t i = 0; i < c_returnValuesSize; ++i)
|
||||||
stackLayout.push_back(i);
|
stackLayout.push_back(static_cast<int>(i));
|
||||||
|
|
||||||
if (stackLayout.size() > 17)
|
if (stackLayout.size() > 17)
|
||||||
BOOST_THROW_EXCEPTION(
|
BOOST_THROW_EXCEPTION(
|
||||||
@ -638,7 +638,7 @@ bool ContractCompiler::visit(FunctionDefinition const& _function)
|
|||||||
errinfo_sourceLocation(_function.location()) <<
|
errinfo_sourceLocation(_function.location()) <<
|
||||||
errinfo_comment("Stack too deep, try removing local variables.")
|
errinfo_comment("Stack too deep, try removing local variables.")
|
||||||
);
|
);
|
||||||
while (stackLayout.back() != int(stackLayout.size() - 1))
|
while (stackLayout.back() != static_cast<int>(stackLayout.size() - 1))
|
||||||
if (stackLayout.back() < 0)
|
if (stackLayout.back() < 0)
|
||||||
{
|
{
|
||||||
m_context << Instruction::POP;
|
m_context << Instruction::POP;
|
||||||
@ -646,11 +646,11 @@ bool ContractCompiler::visit(FunctionDefinition const& _function)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_context << swapInstruction(stackLayout.size() - stackLayout.back() - 1);
|
m_context << swapInstruction(stackLayout.size() - static_cast<size_t>(stackLayout.back()) - 1);
|
||||||
swap(stackLayout[stackLayout.back()], stackLayout.back());
|
swap(stackLayout[static_cast<size_t>(stackLayout.back())], stackLayout.back());
|
||||||
}
|
}
|
||||||
for (int i = 0; i < int(stackLayout.size()); ++i)
|
for (size_t i = 0; i < stackLayout.size(); ++i)
|
||||||
if (stackLayout[i] != i)
|
if (stackLayout[i] != static_cast<int>(i))
|
||||||
solAssert(false, "Invalid stack layout on cleanup.");
|
solAssert(false, "Invalid stack layout on cleanup.");
|
||||||
|
|
||||||
for (ASTPointer<VariableDeclaration> const& variable: _function.parameters() + _function.returnParameters())
|
for (ASTPointer<VariableDeclaration> const& variable: _function.parameters() + _function.returnParameters())
|
||||||
@ -677,7 +677,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
{
|
{
|
||||||
auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier);
|
auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier);
|
||||||
if (ref == _inlineAssembly.annotation().externalReferences.end())
|
if (ref == _inlineAssembly.annotation().externalReferences.end())
|
||||||
return size_t(-1);
|
return numeric_limits<size_t>::max();
|
||||||
return ref->second.valueSize;
|
return ref->second.valueSize;
|
||||||
};
|
};
|
||||||
identifierAccess.generateCode = [&](yul::Identifier const& _identifier, yul::IdentifierContext _context, yul::AbstractAssembly& _assembly)
|
identifierAccess.generateCode = [&](yul::Identifier const& _identifier, yul::IdentifierContext _context, yul::AbstractAssembly& _assembly)
|
||||||
@ -696,7 +696,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
functionDef = &functionDef->resolveVirtual(m_context.mostDerivedContract());
|
functionDef = &functionDef->resolveVirtual(m_context.mostDerivedContract());
|
||||||
auto functionEntryLabel = m_context.functionEntryLabel(*functionDef).pushTag();
|
auto functionEntryLabel = m_context.functionEntryLabel(*functionDef).pushTag();
|
||||||
solAssert(functionEntryLabel.data() <= std::numeric_limits<size_t>::max(), "");
|
solAssert(functionEntryLabel.data() <= std::numeric_limits<size_t>::max(), "");
|
||||||
_assembly.appendLabelReference(size_t(functionEntryLabel.data()));
|
_assembly.appendLabelReference(static_cast<size_t>(functionEntryLabel.data()));
|
||||||
// If there is a runtime context, we have to merge both labels into the same
|
// If there is a runtime context, we have to merge both labels into the same
|
||||||
// stack slot in case we store it in storage.
|
// stack slot in case we store it in storage.
|
||||||
if (CompilerContext* rtc = m_context.runtimeContext())
|
if (CompilerContext* rtc = m_context.runtimeContext())
|
||||||
@ -705,7 +705,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
_assembly.appendInstruction(Instruction::MUL);
|
_assembly.appendInstruction(Instruction::MUL);
|
||||||
auto runtimeEntryLabel = rtc->functionEntryLabel(*functionDef).toSubAssemblyTag(m_context.runtimeSub());
|
auto runtimeEntryLabel = rtc->functionEntryLabel(*functionDef).toSubAssemblyTag(m_context.runtimeSub());
|
||||||
solAssert(runtimeEntryLabel.data() <= std::numeric_limits<size_t>::max(), "");
|
solAssert(runtimeEntryLabel.data() <= std::numeric_limits<size_t>::max(), "");
|
||||||
_assembly.appendLabelReference(size_t(runtimeEntryLabel.data()));
|
_assembly.appendLabelReference(static_cast<size_t>(runtimeEntryLabel.data()));
|
||||||
_assembly.appendInstruction(Instruction::OR);
|
_assembly.appendInstruction(Instruction::OR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -772,7 +772,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
}
|
}
|
||||||
else if (m_context.isLocalVariable(decl))
|
else if (m_context.isLocalVariable(decl))
|
||||||
{
|
{
|
||||||
int stackDiff = _assembly.stackHeight() - m_context.baseStackOffsetOfVariable(*variable);
|
unsigned stackDiff = static_cast<unsigned>(_assembly.stackHeight()) - m_context.baseStackOffsetOfVariable(*variable);
|
||||||
if (ref->second.isSlot || ref->second.isOffset)
|
if (ref->second.isSlot || ref->second.isOffset)
|
||||||
{
|
{
|
||||||
solAssert(variable->type()->dataStoredIn(DataLocation::Storage), "");
|
solAssert(variable->type()->dataStoredIn(DataLocation::Storage), "");
|
||||||
@ -816,7 +816,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
solAssert(false, "Invalid declaration type.");
|
solAssert(false, "Invalid declaration type.");
|
||||||
solAssert(_assembly.stackHeight() - depositBefore == int(ref->second.valueSize), "");
|
solAssert(_assembly.stackHeight() - depositBefore == static_cast<int>(ref->second.valueSize), "");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -828,7 +828,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
"Can only assign to stack variables in inline assembly."
|
"Can only assign to stack variables in inline assembly."
|
||||||
);
|
);
|
||||||
solAssert(variable->type()->sizeOnStack() == 1, "");
|
solAssert(variable->type()->sizeOnStack() == 1, "");
|
||||||
int stackDiff = _assembly.stackHeight() - m_context.baseStackOffsetOfVariable(*variable) - 1;
|
unsigned stackDiff = static_cast<unsigned>(_assembly.stackHeight()) - m_context.baseStackOffsetOfVariable(*variable) - 1;
|
||||||
if (stackDiff > 16 || stackDiff < 1)
|
if (stackDiff > 16 || stackDiff < 1)
|
||||||
BOOST_THROW_EXCEPTION(
|
BOOST_THROW_EXCEPTION(
|
||||||
CompilerError() <<
|
CompilerError() <<
|
||||||
@ -875,7 +875,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
false,
|
false,
|
||||||
m_optimiserSettings.optimizeStackAllocation
|
m_optimiserSettings.optimizeStackAllocation
|
||||||
);
|
);
|
||||||
m_context.setStackOffset(startStackHeight);
|
m_context.setStackOffset(static_cast<int>(startStackHeight));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -914,7 +914,7 @@ bool ContractCompiler::visit(TryStatement const& _tryStatement)
|
|||||||
solAssert(params[i] && exprTypes[i] && *params[i]->annotation().type == *exprTypes[i], "");
|
solAssert(params[i] && exprTypes[i] && *params[i]->annotation().type == *exprTypes[i], "");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
CompilerUtils(m_context).popStackSlots(returnSize);
|
CompilerUtils(m_context).popStackSlots(static_cast<size_t>(returnSize));
|
||||||
|
|
||||||
_tryStatement.clauses().front()->accept(*this);
|
_tryStatement.clauses().front()->accept(*this);
|
||||||
}
|
}
|
||||||
@ -937,7 +937,7 @@ void ContractCompiler::handleCatch(vector<ASTPointer<TryCatchClause>> const& _ca
|
|||||||
else
|
else
|
||||||
solAssert(false, "");
|
solAssert(false, "");
|
||||||
|
|
||||||
solAssert(_catchClauses.size() == size_t(1 + (structured ? 1 : 0) + (fallback ? 1 : 0)), "");
|
solAssert(_catchClauses.size() == 1ul + (structured ? 1 : 0) + (fallback ? 1 : 0), "");
|
||||||
|
|
||||||
evmasm::AssemblyItem endTag = m_context.newTag();
|
evmasm::AssemblyItem endTag = m_context.newTag();
|
||||||
evmasm::AssemblyItem fallbackTag = m_context.newTag();
|
evmasm::AssemblyItem fallbackTag = m_context.newTag();
|
||||||
|
@ -100,7 +100,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
|
|||||||
if (_varDecl.immutable())
|
if (_varDecl.immutable())
|
||||||
solAssert(paramTypes.empty(), "");
|
solAssert(paramTypes.empty(), "");
|
||||||
|
|
||||||
m_context.adjustStackOffset(1 + CompilerUtils::sizeOnStack(paramTypes));
|
m_context.adjustStackOffset(static_cast<int>(1 + CompilerUtils::sizeOnStack(paramTypes)));
|
||||||
|
|
||||||
if (!_varDecl.immutable())
|
if (!_varDecl.immutable())
|
||||||
{
|
{
|
||||||
@ -242,7 +242,7 @@ bool ExpressionCompiler::visit(Conditional const& _condition)
|
|||||||
acceptAndConvert(_condition.falseExpression(), *_condition.annotation().type);
|
acceptAndConvert(_condition.falseExpression(), *_condition.annotation().type);
|
||||||
evmasm::AssemblyItem endTag = m_context.appendJumpToNew();
|
evmasm::AssemblyItem endTag = m_context.appendJumpToNew();
|
||||||
m_context << trueTag;
|
m_context << trueTag;
|
||||||
int offset = _condition.annotation().type->sizeOnStack();
|
int offset = static_cast<int>(_condition.annotation().type->sizeOnStack());
|
||||||
m_context.adjustStackOffset(-offset);
|
m_context.adjustStackOffset(-offset);
|
||||||
acceptAndConvert(_condition.trueExpression(), *_condition.annotation().type);
|
acceptAndConvert(_condition.trueExpression(), *_condition.annotation().type);
|
||||||
m_context << endTag;
|
m_context << endTag;
|
||||||
@ -619,7 +619,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
|
|
||||||
unsigned returnParametersSize = CompilerUtils::sizeOnStack(function.returnParameterTypes());
|
unsigned returnParametersSize = CompilerUtils::sizeOnStack(function.returnParameterTypes());
|
||||||
// callee adds return parameters, but removes arguments and return label
|
// callee adds return parameters, but removes arguments and return label
|
||||||
m_context.adjustStackOffset(returnParametersSize - parameterSize - 1);
|
m_context.adjustStackOffset(static_cast<int>(returnParametersSize - parameterSize) - 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FunctionType::Kind::BareCall:
|
case FunctionType::Kind::BareCall:
|
||||||
@ -705,7 +705,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
acceptAndConvert(*arguments.front(), *TypeProvider::uint256(), true);
|
acceptAndConvert(*arguments.front(), *TypeProvider::uint256(), true);
|
||||||
// Note that function is not the original function, but the ".gas" function.
|
// Note that function is not the original function, but the ".gas" function.
|
||||||
// Its values of gasSet and valueSet is equal to the original function's though.
|
// Its values of gasSet and valueSet is equal to the original function's though.
|
||||||
unsigned stackDepth = (function.gasSet() ? 1 : 0) + (function.valueSet() ? 1 : 0);
|
unsigned stackDepth = (function.gasSet() ? 1u : 0u) + (function.valueSet() ? 1u : 0u);
|
||||||
if (stackDepth > 0)
|
if (stackDepth > 0)
|
||||||
m_context << swapInstruction(stackDepth);
|
m_context << swapInstruction(stackDepth);
|
||||||
if (function.gasSet())
|
if (function.gasSet())
|
||||||
@ -814,7 +814,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
case FunctionType::Kind::Log3:
|
case FunctionType::Kind::Log3:
|
||||||
case FunctionType::Kind::Log4:
|
case FunctionType::Kind::Log4:
|
||||||
{
|
{
|
||||||
unsigned logNumber = int(function.kind()) - int(FunctionType::Kind::Log0);
|
unsigned logNumber = static_cast<unsigned>(function.kind()) - static_cast<unsigned>(FunctionType::Kind::Log0);
|
||||||
for (unsigned arg = logNumber; arg > 0; --arg)
|
for (unsigned arg = logNumber; arg > 0; --arg)
|
||||||
acceptAndConvert(*arguments[arg], *function.parameterTypes()[arg], true);
|
acceptAndConvert(*arguments[arg], *function.parameterTypes()[arg], true);
|
||||||
arguments.front()->accept(*this);
|
arguments.front()->accept(*this);
|
||||||
@ -1088,7 +1088,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
{
|
{
|
||||||
utils().revertWithStringData(*arguments.at(1)->annotation().type);
|
utils().revertWithStringData(*arguments.at(1)->annotation().type);
|
||||||
// Here, the argument is consumed, but in the other branch, it is still there.
|
// Here, the argument is consumed, but in the other branch, it is still there.
|
||||||
m_context.adjustStackOffset(arguments.at(1)->annotation().type->sizeOnStack());
|
m_context.adjustStackOffset(static_cast<int>(arguments.at(1)->annotation().type->sizeOnStack()));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
m_context.appendRevert();
|
m_context.appendRevert();
|
||||||
@ -1271,9 +1271,9 @@ bool ExpressionCompiler::visit(FunctionCallOptions const& _functionCallOptions)
|
|||||||
acceptAndConvert(*_functionCallOptions.options()[i], *requiredType);
|
acceptAndConvert(*_functionCallOptions.options()[i], *requiredType);
|
||||||
|
|
||||||
solAssert(!contains(presentOptions, newOption), "");
|
solAssert(!contains(presentOptions, newOption), "");
|
||||||
size_t insertPos = presentOptions.end() - lower_bound(presentOptions.begin(), presentOptions.end(), newOption);
|
ptrdiff_t insertPos = presentOptions.end() - lower_bound(presentOptions.begin(), presentOptions.end(), newOption);
|
||||||
|
|
||||||
utils().moveIntoStack(insertPos, 1);
|
utils().moveIntoStack(static_cast<size_t>(insertPos), 1);
|
||||||
presentOptions.insert(presentOptions.end() - insertPos, newOption);
|
presentOptions.insert(presentOptions.end() - insertPos, newOption);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2190,7 +2190,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
|||||||
// contract address
|
// contract address
|
||||||
|
|
||||||
unsigned selfSize = _functionType.bound() ? _functionType.selfType()->sizeOnStack() : 0;
|
unsigned selfSize = _functionType.bound() ? _functionType.selfType()->sizeOnStack() : 0;
|
||||||
unsigned gasValueSize = (_functionType.gasSet() ? 1 : 0) + (_functionType.valueSet() ? 1 : 0);
|
unsigned gasValueSize = (_functionType.gasSet() ? 1u : 0u) + (_functionType.valueSet() ? 1u : 0u);
|
||||||
unsigned contractStackPos = m_context.currentToBaseStackOffset(1 + gasValueSize + selfSize + (_functionType.isBareCall() ? 0 : 1));
|
unsigned contractStackPos = m_context.currentToBaseStackOffset(1 + gasValueSize + selfSize + (_functionType.isBareCall() ? 0 : 1));
|
||||||
unsigned gasStackPos = m_context.currentToBaseStackOffset(gasValueSize);
|
unsigned gasStackPos = m_context.currentToBaseStackOffset(gasValueSize);
|
||||||
unsigned valueStackPos = m_context.currentToBaseStackOffset(1);
|
unsigned valueStackPos = m_context.currentToBaseStackOffset(1);
|
||||||
@ -2361,7 +2361,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
|||||||
m_context << Instruction::CALL;
|
m_context << Instruction::CALL;
|
||||||
|
|
||||||
unsigned remainsSize =
|
unsigned remainsSize =
|
||||||
2 + // contract address, input_memory_end
|
2u + // contract address, input_memory_end
|
||||||
(_functionType.valueSet() ? 1 : 0) +
|
(_functionType.valueSet() ? 1 : 0) +
|
||||||
(_functionType.gasSet() ? 1 : 0) +
|
(_functionType.gasSet() ? 1 : 0) +
|
||||||
(!_functionType.isBareCall() ? 1 : 0);
|
(!_functionType.isBareCall() ? 1 : 0);
|
||||||
|
@ -1652,8 +1652,7 @@ string YulUtilFunctions::allocateAndInitializeMemoryStructFunction(StructType co
|
|||||||
return m_functionCollector.createFunction(functionName, [&]() {
|
return m_functionCollector.createFunction(functionName, [&]() {
|
||||||
Whiskers templ(R"(
|
Whiskers templ(R"(
|
||||||
function <functionName>() -> memPtr {
|
function <functionName>() -> memPtr {
|
||||||
let allocSize := <allocSize>()
|
memPtr := <alloc>(<allocSize>)
|
||||||
memPtr := <alloc>(allocSize)
|
|
||||||
let offset := memPtr
|
let offset := memPtr
|
||||||
<#member>
|
<#member>
|
||||||
mstore(offset, <zeroValue>())
|
mstore(offset, <zeroValue>())
|
||||||
|
@ -636,7 +636,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
});
|
});
|
||||||
|
|
||||||
solAssert(it != callArgumentNames.cend(), "");
|
solAssert(it != callArgumentNames.cend(), "");
|
||||||
arguments.push_back(callArguments[std::distance(callArgumentNames.begin(), it)]);
|
arguments.push_back(callArguments[static_cast<size_t>(std::distance(callArgumentNames.begin(), it))]);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto memberAccess = dynamic_cast<MemberAccess const*>(&_functionCall.expression());
|
auto memberAccess = dynamic_cast<MemberAccess const*>(&_functionCall.expression());
|
||||||
@ -1092,7 +1092,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
case FunctionType::Kind::Log3:
|
case FunctionType::Kind::Log3:
|
||||||
case FunctionType::Kind::Log4:
|
case FunctionType::Kind::Log4:
|
||||||
{
|
{
|
||||||
unsigned logNumber = int(functionType->kind()) - int(FunctionType::Kind::Log0);
|
unsigned logNumber = static_cast<unsigned>(functionType->kind()) - static_cast<unsigned>(FunctionType::Kind::Log0);
|
||||||
solAssert(arguments.size() == logNumber + 1, "");
|
solAssert(arguments.size() == logNumber + 1, "");
|
||||||
ABIFunctions abi(m_context.evmVersion(), m_context.revertStrings(), m_context.functionCollector());
|
ABIFunctions abi(m_context.evmVersion(), m_context.revertStrings(), m_context.functionCollector());
|
||||||
string indexedArgs;
|
string indexedArgs;
|
||||||
@ -1477,7 +1477,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
|||||||
pair<u256, unsigned> const& offsets = structType.storageOffsetsOfMember(member);
|
pair<u256, unsigned> const& offsets = structType.storageOffsetsOfMember(member);
|
||||||
string slot = m_context.newYulVariable();
|
string slot = m_context.newYulVariable();
|
||||||
m_code << "let " << slot << " := " <<
|
m_code << "let " << slot << " := " <<
|
||||||
("add(" + expression.name() + ", " + offsets.first.str() + ")\n");
|
("add(" + expression.part("slot").name() + ", " + offsets.first.str() + ")\n");
|
||||||
setLValue(_memberAccess, IRLValue{
|
setLValue(_memberAccess, IRLValue{
|
||||||
type(_memberAccess),
|
type(_memberAccess),
|
||||||
IRLValue::Storage{slot, offsets.second}
|
IRLValue::Storage{slot, offsets.second}
|
||||||
@ -1497,7 +1497,25 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
|||||||
}
|
}
|
||||||
case DataLocation::CallData:
|
case DataLocation::CallData:
|
||||||
{
|
{
|
||||||
solUnimplementedAssert(false, "");
|
string baseRef = expression.part("offset").name();
|
||||||
|
string offset = m_context.newYulVariable();
|
||||||
|
m_code << "let " << offset << " := " << "add(" << baseRef << ", " << to_string(structType.calldataOffsetOfMember(member)) << ")\n";
|
||||||
|
if (_memberAccess.annotation().type->isDynamicallyEncoded())
|
||||||
|
define(_memberAccess) <<
|
||||||
|
m_utils.accessCalldataTailFunction(*_memberAccess.annotation().type) <<
|
||||||
|
"(" <<
|
||||||
|
baseRef <<
|
||||||
|
", " <<
|
||||||
|
offset <<
|
||||||
|
")" <<
|
||||||
|
std::endl;
|
||||||
|
else
|
||||||
|
define(_memberAccess) <<
|
||||||
|
m_utils.readFromCalldata(*_memberAccess.annotation().type) <<
|
||||||
|
"(" <<
|
||||||
|
offset <<
|
||||||
|
")" <<
|
||||||
|
std::endl;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -104,7 +104,7 @@ void CHC::analyze(SourceUnit const& _source)
|
|||||||
for (auto const* assertion: assertions)
|
for (auto const* assertion: assertions)
|
||||||
{
|
{
|
||||||
createErrorBlock();
|
createErrorBlock();
|
||||||
connectBlocks(target.value, error(), target.constraints && (target.errorId == assertion->id()));
|
connectBlocks(target.value, error(), target.constraints && (target.errorId == static_cast<size_t>(assertion->id())));
|
||||||
auto [result, model] = query(error(), assertion->location());
|
auto [result, model] = query(error(), assertion->location());
|
||||||
// This should be fine but it's a bug in the old compiler
|
// This should be fine but it's a bug in the old compiler
|
||||||
(void)model;
|
(void)model;
|
||||||
@ -116,7 +116,7 @@ void CHC::analyze(SourceUnit const& _source)
|
|||||||
{
|
{
|
||||||
solAssert(dynamic_cast<FunctionCall const*>(scope), "");
|
solAssert(dynamic_cast<FunctionCall const*>(scope), "");
|
||||||
createErrorBlock();
|
createErrorBlock();
|
||||||
connectBlocks(target.value, error(), target.constraints && (target.errorId == scope->id()));
|
connectBlocks(target.value, error(), target.constraints && (target.errorId == static_cast<size_t>(scope->id())));
|
||||||
auto [result, model] = query(error(), scope->location());
|
auto [result, model] = query(error(), scope->location());
|
||||||
// This should be fine but it's a bug in the old compiler
|
// This should be fine but it's a bug in the old compiler
|
||||||
(void)model;
|
(void)model;
|
||||||
@ -533,7 +533,9 @@ void CHC::visitAssert(FunctionCall const& _funCall)
|
|||||||
connectBlocks(
|
connectBlocks(
|
||||||
m_currentBlock,
|
m_currentBlock,
|
||||||
m_currentFunction->isConstructor() ? summary(*m_currentContract) : summary(*m_currentFunction),
|
m_currentFunction->isConstructor() ? summary(*m_currentContract) : summary(*m_currentFunction),
|
||||||
currentPathConditions() && !m_context.expression(*args.front())->currentValue() && (m_error.currentValue() == _funCall.id())
|
currentPathConditions() && !m_context.expression(*args.front())->currentValue() && (
|
||||||
|
m_error.currentValue() == static_cast<size_t>(_funCall.id())
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
m_context.addAssertion(m_error.currentValue() == previousError);
|
m_context.addAssertion(m_error.currentValue() == previousError);
|
||||||
@ -601,7 +603,7 @@ void CHC::makeArrayPopVerificationTarget(FunctionCall const& _arrayPop)
|
|||||||
connectBlocks(
|
connectBlocks(
|
||||||
m_currentBlock,
|
m_currentBlock,
|
||||||
m_currentFunction->isConstructor() ? summary(*m_currentContract) : summary(*m_currentFunction),
|
m_currentFunction->isConstructor() ? summary(*m_currentContract) : summary(*m_currentFunction),
|
||||||
currentPathConditions() && symbArray->length() <= 0 && m_error.currentValue() == _arrayPop.id()
|
currentPathConditions() && symbArray->length() <= 0 && m_error.currentValue() == static_cast<size_t>(_arrayPop.id())
|
||||||
);
|
);
|
||||||
|
|
||||||
m_context.addAssertion(m_error.currentValue() == previousError);
|
m_context.addAssertion(m_error.currentValue() == previousError);
|
||||||
@ -891,13 +893,13 @@ vector<smtutil::Expression> CHC::initialStateVariables()
|
|||||||
return stateVariablesAtIndex(0);
|
return stateVariablesAtIndex(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<smtutil::Expression> CHC::stateVariablesAtIndex(int _index)
|
vector<smtutil::Expression> CHC::stateVariablesAtIndex(unsigned _index)
|
||||||
{
|
{
|
||||||
solAssert(m_currentContract, "");
|
solAssert(m_currentContract, "");
|
||||||
return applyMap(m_stateVariables, [&](auto _var) { return valueAtIndex(*_var, _index); });
|
return applyMap(m_stateVariables, [&](auto _var) { return valueAtIndex(*_var, _index); });
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<smtutil::Expression> CHC::stateVariablesAtIndex(int _index, ContractDefinition const& _contract)
|
vector<smtutil::Expression> CHC::stateVariablesAtIndex(unsigned _index, ContractDefinition const& _contract)
|
||||||
{
|
{
|
||||||
return applyMap(
|
return applyMap(
|
||||||
stateVariablesIncludingInheritedAndPrivate(_contract),
|
stateVariablesIncludingInheritedAndPrivate(_contract),
|
||||||
|
@ -149,8 +149,8 @@ private:
|
|||||||
/// @returns the symbolic values of the state variables at the beginning
|
/// @returns the symbolic values of the state variables at the beginning
|
||||||
/// of the current transaction.
|
/// of the current transaction.
|
||||||
std::vector<smtutil::Expression> initialStateVariables();
|
std::vector<smtutil::Expression> initialStateVariables();
|
||||||
std::vector<smtutil::Expression> stateVariablesAtIndex(int _index);
|
std::vector<smtutil::Expression> stateVariablesAtIndex(unsigned _index);
|
||||||
std::vector<smtutil::Expression> stateVariablesAtIndex(int _index, ContractDefinition const& _contract);
|
std::vector<smtutil::Expression> stateVariablesAtIndex(unsigned _index, ContractDefinition const& _contract);
|
||||||
/// @returns the current symbolic values of the current state variables.
|
/// @returns the current symbolic values of the current state variables.
|
||||||
std::vector<smtutil::Expression> currentStateVariables();
|
std::vector<smtutil::Expression> currentStateVariables();
|
||||||
|
|
||||||
|
@ -32,12 +32,23 @@ EncodingContext::EncodingContext():
|
|||||||
void EncodingContext::reset()
|
void EncodingContext::reset()
|
||||||
{
|
{
|
||||||
resetAllVariables();
|
resetAllVariables();
|
||||||
|
resetSlackId();
|
||||||
m_expressions.clear();
|
m_expressions.clear();
|
||||||
m_globalContext.clear();
|
m_globalContext.clear();
|
||||||
m_state.reset();
|
m_state.reset();
|
||||||
m_assertions.clear();
|
m_assertions.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EncodingContext::resetSlackId()
|
||||||
|
{
|
||||||
|
m_nextSlackId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned EncodingContext::newSlackId()
|
||||||
|
{
|
||||||
|
return m_nextSlackId++;
|
||||||
|
}
|
||||||
|
|
||||||
void EncodingContext::clear()
|
void EncodingContext::clear()
|
||||||
{
|
{
|
||||||
m_variables.clear();
|
m_variables.clear();
|
||||||
|
@ -40,6 +40,10 @@ public:
|
|||||||
/// alive because of state variables and inlined function calls.
|
/// alive because of state variables and inlined function calls.
|
||||||
/// To be used in the beginning of a root function visit.
|
/// To be used in the beginning of a root function visit.
|
||||||
void reset();
|
void reset();
|
||||||
|
/// Resets the fresh id for slack variables.
|
||||||
|
void resetSlackId();
|
||||||
|
/// Returns the current fresh slack id and increments it.
|
||||||
|
unsigned newSlackId();
|
||||||
/// Clears the entire context, erasing everything.
|
/// Clears the entire context, erasing everything.
|
||||||
/// To be used before a model checking engine starts.
|
/// To be used before a model checking engine starts.
|
||||||
void clear();
|
void clear();
|
||||||
@ -168,6 +172,9 @@ private:
|
|||||||
/// Whether to conjoin assertions in the assertion stack.
|
/// Whether to conjoin assertions in the assertion stack.
|
||||||
bool m_accumulateAssertions = true;
|
bool m_accumulateAssertions = true;
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
/// Fresh ids for slack variables to be created deterministically.
|
||||||
|
unsigned m_nextSlackId = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -154,15 +154,16 @@ void SMTEncoder::visitFunctionOrModifier()
|
|||||||
++m_modifierDepthStack.back();
|
++m_modifierDepthStack.back();
|
||||||
FunctionDefinition const& function = dynamic_cast<FunctionDefinition const&>(*m_callStack.back().first);
|
FunctionDefinition const& function = dynamic_cast<FunctionDefinition const&>(*m_callStack.back().first);
|
||||||
|
|
||||||
if (m_modifierDepthStack.back() == int(function.modifiers().size()))
|
if (m_modifierDepthStack.back() == static_cast<int>(function.modifiers().size()))
|
||||||
{
|
{
|
||||||
if (function.isImplemented())
|
if (function.isImplemented())
|
||||||
function.body().accept(*this);
|
function.body().accept(*this);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
solAssert(m_modifierDepthStack.back() < int(function.modifiers().size()), "");
|
solAssert(m_modifierDepthStack.back() < static_cast<int>(function.modifiers().size()), "");
|
||||||
ASTPointer<ModifierInvocation> const& modifierInvocation = function.modifiers()[m_modifierDepthStack.back()];
|
ASTPointer<ModifierInvocation> const& modifierInvocation =
|
||||||
|
function.modifiers()[static_cast<size_t>(m_modifierDepthStack.back())];
|
||||||
solAssert(modifierInvocation, "");
|
solAssert(modifierInvocation, "");
|
||||||
auto refDecl = modifierInvocation->name()->annotation().referencedDeclaration;
|
auto refDecl = modifierInvocation->name()->annotation().referencedDeclaration;
|
||||||
if (dynamic_cast<ContractDefinition const*>(refDecl))
|
if (dynamic_cast<ContractDefinition const*>(refDecl))
|
||||||
@ -1203,7 +1204,7 @@ pair<smtutil::Expression, smtutil::Expression> SMTEncoder::arithmeticOperation(
|
|||||||
smtutil::Expression const& _left,
|
smtutil::Expression const& _left,
|
||||||
smtutil::Expression const& _right,
|
smtutil::Expression const& _right,
|
||||||
TypePointer const& _commonType,
|
TypePointer const& _commonType,
|
||||||
Expression const&
|
Expression const& _operation
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
static set<Token> validOperators{
|
static set<Token> validOperators{
|
||||||
@ -1226,39 +1227,66 @@ pair<smtutil::Expression, smtutil::Expression> SMTEncoder::arithmeticOperation(
|
|||||||
else
|
else
|
||||||
intType = TypeProvider::uint256();
|
intType = TypeProvider::uint256();
|
||||||
|
|
||||||
smtutil::Expression valueNoMod(
|
auto valueUnbounded = [&]() -> smtutil::Expression {
|
||||||
_op == Token::Add ? _left + _right :
|
switch (_op)
|
||||||
_op == Token::Sub ? _left - _right :
|
{
|
||||||
_op == Token::Div ? division(_left, _right, *intType) :
|
case Token::Add: return _left + _right;
|
||||||
_op == Token::Mul ? _left * _right :
|
case Token::Sub: return _left - _right;
|
||||||
/*_op == Token::Mod*/ _left % _right
|
case Token::Mul: return _left * _right;
|
||||||
);
|
case Token::Div: return division(_left, _right, *intType);
|
||||||
|
case Token::Mod: return _left % _right;
|
||||||
|
default: solAssert(false, "");
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
if (_op == Token::Div || _op == Token::Mod)
|
if (_op == Token::Div || _op == Token::Mod)
|
||||||
|
{
|
||||||
m_context.addAssertion(_right != 0);
|
m_context.addAssertion(_right != 0);
|
||||||
|
|
||||||
|
// mod and unsigned division never underflow/overflow
|
||||||
|
if (_op == Token::Mod || !intType->isSigned())
|
||||||
|
return {valueUnbounded, valueUnbounded};
|
||||||
|
|
||||||
|
// The only case where division overflows is
|
||||||
|
// - type is signed
|
||||||
|
// - LHS is type.min
|
||||||
|
// - RHS is -1
|
||||||
|
// the result is then -(type.min), which wraps back to type.min
|
||||||
|
smtutil::Expression maxLeft = _left == smt::minValue(*intType);
|
||||||
|
smtutil::Expression minusOneRight = _right == -1;
|
||||||
|
smtutil::Expression wrap = smtutil::Expression::ite(maxLeft && minusOneRight, smt::minValue(*intType), valueUnbounded);
|
||||||
|
return {wrap, valueUnbounded};
|
||||||
|
}
|
||||||
|
|
||||||
auto symbMin = smt::minValue(*intType);
|
auto symbMin = smt::minValue(*intType);
|
||||||
auto symbMax = smt::maxValue(*intType);
|
auto symbMax = smt::maxValue(*intType);
|
||||||
|
|
||||||
smtutil::Expression intValueRange = (0 - symbMin) + symbMax + 1;
|
smtutil::Expression intValueRange = (0 - symbMin) + symbMax + 1;
|
||||||
|
string suffix = to_string(_operation.id()) + "_" + to_string(m_context.newSlackId());
|
||||||
|
smt::SymbolicIntVariable k(intType, intType, "k_" + suffix, m_context);
|
||||||
|
smt::SymbolicIntVariable m(intType, intType, "m_" + suffix, m_context);
|
||||||
|
|
||||||
|
// To wrap around valueUnbounded in case of overflow or underflow, we replace it with a k, given:
|
||||||
|
// 1. k + m * intValueRange = valueUnbounded
|
||||||
|
// 2. k is in range of the desired integer type
|
||||||
|
auto wrap = k.currentValue();
|
||||||
|
m_context.addAssertion(valueUnbounded == (k.currentValue() + intValueRange * m.currentValue()));
|
||||||
|
m_context.addAssertion(k.currentValue() >= symbMin);
|
||||||
|
m_context.addAssertion(k.currentValue() <= symbMax);
|
||||||
|
|
||||||
|
// TODO this could be refined:
|
||||||
|
// for unsigned types it's enough to check only the upper bound.
|
||||||
auto value = smtutil::Expression::ite(
|
auto value = smtutil::Expression::ite(
|
||||||
valueNoMod > symbMax,
|
valueUnbounded > symbMax,
|
||||||
valueNoMod % intValueRange,
|
wrap,
|
||||||
smtutil::Expression::ite(
|
smtutil::Expression::ite(
|
||||||
valueNoMod < symbMin,
|
valueUnbounded < symbMin,
|
||||||
valueNoMod % intValueRange,
|
wrap,
|
||||||
valueNoMod
|
valueUnbounded
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (intType->isSigned())
|
return {value, valueUnbounded};
|
||||||
value = smtutil::Expression::ite(
|
|
||||||
value > symbMax,
|
|
||||||
value - intValueRange,
|
|
||||||
value
|
|
||||||
);
|
|
||||||
|
|
||||||
return {value, valueNoMod};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMTEncoder::compareOperation(BinaryOperation const& _op)
|
void SMTEncoder::compareOperation(BinaryOperation const& _op)
|
||||||
@ -1679,8 +1707,8 @@ void SMTEncoder::mergeVariables(set<VariableDeclaration const*> const& _variable
|
|||||||
for (auto const* decl: sortedVars)
|
for (auto const* decl: sortedVars)
|
||||||
{
|
{
|
||||||
solAssert(_indicesEndTrue.count(decl) && _indicesEndFalse.count(decl), "");
|
solAssert(_indicesEndTrue.count(decl) && _indicesEndFalse.count(decl), "");
|
||||||
int trueIndex = _indicesEndTrue.at(decl);
|
auto trueIndex = static_cast<unsigned>(_indicesEndTrue.at(decl));
|
||||||
int falseIndex = _indicesEndFalse.at(decl);
|
auto falseIndex = static_cast<unsigned>(_indicesEndFalse.at(decl));
|
||||||
solAssert(trueIndex != falseIndex, "");
|
solAssert(trueIndex != falseIndex, "");
|
||||||
m_context.addAssertion(m_context.newValue(*decl) == smtutil::Expression::ite(
|
m_context.addAssertion(m_context.newValue(*decl) == smtutil::Expression::ite(
|
||||||
_condition,
|
_condition,
|
||||||
@ -1696,7 +1724,7 @@ smtutil::Expression SMTEncoder::currentValue(VariableDeclaration const& _decl)
|
|||||||
return m_context.variable(_decl)->currentValue();
|
return m_context.variable(_decl)->currentValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
smtutil::Expression SMTEncoder::valueAtIndex(VariableDeclaration const& _decl, int _index)
|
smtutil::Expression SMTEncoder::valueAtIndex(VariableDeclaration const& _decl, unsigned _index)
|
||||||
{
|
{
|
||||||
solAssert(m_context.knownVariable(_decl), "");
|
solAssert(m_context.knownVariable(_decl), "");
|
||||||
return m_context.variable(_decl)->valueAtIndex(_index);
|
return m_context.variable(_decl)->valueAtIndex(_index);
|
||||||
@ -1819,7 +1847,7 @@ SMTEncoder::VariableIndices SMTEncoder::copyVariableIndices()
|
|||||||
void SMTEncoder::resetVariableIndices(VariableIndices const& _indices)
|
void SMTEncoder::resetVariableIndices(VariableIndices const& _indices)
|
||||||
{
|
{
|
||||||
for (auto const& var: _indices)
|
for (auto const& var: _indices)
|
||||||
m_context.variable(*var.first)->setIndex(var.second);
|
m_context.variable(*var.first)->setIndex(static_cast<unsigned>(var.second));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMTEncoder::clearIndices(ContractDefinition const* _contract, FunctionDefinition const* _function)
|
void SMTEncoder::clearIndices(ContractDefinition const* _contract, FunctionDefinition const* _function)
|
||||||
|
@ -201,7 +201,7 @@ protected:
|
|||||||
smtutil::Expression currentValue(VariableDeclaration const& _decl);
|
smtutil::Expression currentValue(VariableDeclaration const& _decl);
|
||||||
/// @returns an expression denoting the value of the variable declared in @a _decl
|
/// @returns an expression denoting the value of the variable declared in @a _decl
|
||||||
/// at the given index. Does not ensure that this index exists.
|
/// at the given index. Does not ensure that this index exists.
|
||||||
smtutil::Expression valueAtIndex(VariableDeclaration const& _decl, int _index);
|
smtutil::Expression valueAtIndex(VariableDeclaration const& _decl, unsigned _index);
|
||||||
/// Returns the expression corresponding to the AST node.
|
/// Returns the expression corresponding to the AST node.
|
||||||
/// If _targetType is not null apply conversion.
|
/// If _targetType is not null apply conversion.
|
||||||
/// Throws if the expression does not exist.
|
/// Throws if the expression does not exist.
|
||||||
|
@ -66,12 +66,12 @@ string SymbolicVariable::currentName() const
|
|||||||
return uniqueSymbol(m_ssa->index());
|
return uniqueSymbol(m_ssa->index());
|
||||||
}
|
}
|
||||||
|
|
||||||
smtutil::Expression SymbolicVariable::valueAtIndex(int _index) const
|
smtutil::Expression SymbolicVariable::valueAtIndex(unsigned _index) const
|
||||||
{
|
{
|
||||||
return m_context.newVariable(uniqueSymbol(_index), m_sort);
|
return m_context.newVariable(uniqueSymbol(_index), m_sort);
|
||||||
}
|
}
|
||||||
|
|
||||||
string SymbolicVariable::nameAtIndex(int _index) const
|
string SymbolicVariable::nameAtIndex(unsigned _index) const
|
||||||
{
|
{
|
||||||
return uniqueSymbol(_index);
|
return uniqueSymbol(_index);
|
||||||
}
|
}
|
||||||
@ -170,12 +170,12 @@ smtutil::Expression SymbolicFunctionVariable::currentFunctionValue() const
|
|||||||
return m_declaration;
|
return m_declaration;
|
||||||
}
|
}
|
||||||
|
|
||||||
smtutil::Expression SymbolicFunctionVariable::valueAtIndex(int _index) const
|
smtutil::Expression SymbolicFunctionVariable::valueAtIndex(unsigned _index) const
|
||||||
{
|
{
|
||||||
return m_abstract.valueAtIndex(_index);
|
return m_abstract.valueAtIndex(_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
smtutil::Expression SymbolicFunctionVariable::functionValueAtIndex(int _index) const
|
smtutil::Expression SymbolicFunctionVariable::functionValueAtIndex(unsigned _index) const
|
||||||
{
|
{
|
||||||
return SymbolicVariable::valueAtIndex(_index);
|
return SymbolicVariable::valueAtIndex(_index);
|
||||||
}
|
}
|
||||||
@ -304,7 +304,7 @@ smtutil::Expression SymbolicArrayVariable::currentValue(frontend::TypePointer co
|
|||||||
return m_pair.currentValue();
|
return m_pair.currentValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
smtutil::Expression SymbolicArrayVariable::valueAtIndex(int _index) const
|
smtutil::Expression SymbolicArrayVariable::valueAtIndex(unsigned _index) const
|
||||||
{
|
{
|
||||||
return m_pair.valueAtIndex(_index);
|
return m_pair.valueAtIndex(_index);
|
||||||
}
|
}
|
||||||
|
@ -54,8 +54,8 @@ public:
|
|||||||
|
|
||||||
virtual smtutil::Expression currentValue(frontend::TypePointer const& _targetType = TypePointer{}) const;
|
virtual smtutil::Expression currentValue(frontend::TypePointer const& _targetType = TypePointer{}) const;
|
||||||
std::string currentName() const;
|
std::string currentName() const;
|
||||||
virtual smtutil::Expression valueAtIndex(int _index) const;
|
virtual smtutil::Expression valueAtIndex(unsigned _index) const;
|
||||||
virtual std::string nameAtIndex(int _index) const;
|
virtual std::string nameAtIndex(unsigned _index) const;
|
||||||
virtual smtutil::Expression resetIndex();
|
virtual smtutil::Expression resetIndex();
|
||||||
virtual smtutil::Expression setIndex(unsigned _index);
|
virtual smtutil::Expression setIndex(unsigned _index);
|
||||||
virtual smtutil::Expression increaseIndex();
|
virtual smtutil::Expression increaseIndex();
|
||||||
@ -165,10 +165,10 @@ public:
|
|||||||
// Explicit request the function declaration.
|
// Explicit request the function declaration.
|
||||||
smtutil::Expression currentFunctionValue() const;
|
smtutil::Expression currentFunctionValue() const;
|
||||||
|
|
||||||
smtutil::Expression valueAtIndex(int _index) const override;
|
smtutil::Expression valueAtIndex(unsigned _index) const override;
|
||||||
|
|
||||||
// Explicit request the function declaration.
|
// Explicit request the function declaration.
|
||||||
smtutil::Expression functionValueAtIndex(int _index) const;
|
smtutil::Expression functionValueAtIndex(unsigned _index) const;
|
||||||
|
|
||||||
smtutil::Expression resetIndex() override;
|
smtutil::Expression resetIndex() override;
|
||||||
smtutil::Expression setIndex(unsigned _index) override;
|
smtutil::Expression setIndex(unsigned _index) override;
|
||||||
@ -251,7 +251,7 @@ public:
|
|||||||
SymbolicArrayVariable(SymbolicArrayVariable&&) = default;
|
SymbolicArrayVariable(SymbolicArrayVariable&&) = default;
|
||||||
|
|
||||||
smtutil::Expression currentValue(frontend::TypePointer const& _targetType = TypePointer{}) const override;
|
smtutil::Expression currentValue(frontend::TypePointer const& _targetType = TypePointer{}) const override;
|
||||||
smtutil::Expression valueAtIndex(int _index) const override;
|
smtutil::Expression valueAtIndex(unsigned _index) const override;
|
||||||
smtutil::Expression resetIndex() override { SymbolicVariable::resetIndex(); return m_pair.resetIndex(); }
|
smtutil::Expression resetIndex() override { SymbolicVariable::resetIndex(); return m_pair.resetIndex(); }
|
||||||
smtutil::Expression setIndex(unsigned _index) override { SymbolicVariable::setIndex(_index); return m_pair.setIndex(_index); }
|
smtutil::Expression setIndex(unsigned _index) override { SymbolicVariable::setIndex(_index); return m_pair.setIndex(_index); }
|
||||||
smtutil::Expression increaseIndex() override { SymbolicVariable::increaseIndex(); return m_pair.increaseIndex(); }
|
smtutil::Expression increaseIndex() override { SymbolicVariable::increaseIndex(); return m_pair.increaseIndex(); }
|
||||||
|
@ -982,7 +982,7 @@ string CompilerStack::applyRemapping(string const& _path, string const& _context
|
|||||||
bestMatchTarget = util::sanitizePath(redir.target);
|
bestMatchTarget = util::sanitizePath(redir.target);
|
||||||
}
|
}
|
||||||
string path = bestMatchTarget;
|
string path = bestMatchTarget;
|
||||||
path.append(_path.begin() + longestPrefix, _path.end());
|
path.append(_path.begin() + static_cast<string::difference_type>(longestPrefix), _path.end());
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,8 +54,8 @@ GasEstimator::ASTGasConsumptionSelfAccumulated GasEstimator::structuralEstimatio
|
|||||||
{
|
{
|
||||||
solAssert(!!block.startState, "");
|
solAssert(!!block.startState, "");
|
||||||
GasMeter meter(block.startState->copy(), m_evmVersion);
|
GasMeter meter(block.startState->copy(), m_evmVersion);
|
||||||
auto const end = _items.begin() + block.end;
|
auto const end = _items.begin() + static_cast<ptrdiff_t>(block.end);
|
||||||
for (auto iter = _items.begin() + block.begin; iter != end; ++iter)
|
for (auto iter = _items.begin() + static_cast<ptrdiff_t>(block.begin); iter != end; ++iter)
|
||||||
particularCosts[iter->location()] += meter.estimateMax(*iter);
|
particularCosts[iter->location()] += meter.estimateMax(*iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,6 +37,9 @@ Json::Value Natspec::userDocumentation(ContractDefinition const& _contractDef)
|
|||||||
Json::Value doc;
|
Json::Value doc;
|
||||||
Json::Value methods(Json::objectValue);
|
Json::Value methods(Json::objectValue);
|
||||||
|
|
||||||
|
doc["version"] = Json::Value(c_natspecVersion);
|
||||||
|
doc["kind"] = Json::Value("user");
|
||||||
|
|
||||||
auto constructorDefinition(_contractDef.constructor());
|
auto constructorDefinition(_contractDef.constructor());
|
||||||
if (constructorDefinition)
|
if (constructorDefinition)
|
||||||
{
|
{
|
||||||
@ -91,6 +94,9 @@ Json::Value Natspec::devDocumentation(ContractDefinition const& _contractDef)
|
|||||||
Json::Value doc;
|
Json::Value doc;
|
||||||
Json::Value methods(Json::objectValue);
|
Json::Value methods(Json::objectValue);
|
||||||
|
|
||||||
|
doc["version"] = Json::Value(c_natspecVersion);
|
||||||
|
doc["kind"] = Json::Value("dev");
|
||||||
|
|
||||||
auto author = extractDoc(_contractDef.annotation().docTags, "author");
|
auto author = extractDoc(_contractDef.annotation().docTags, "author");
|
||||||
if (!author.empty())
|
if (!author.empty())
|
||||||
doc["author"] = author;
|
doc["author"] = author;
|
||||||
|
@ -40,6 +40,8 @@ struct DocTag;
|
|||||||
class Natspec
|
class Natspec
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
static unsigned int constexpr c_natspecVersion = 1;
|
||||||
|
|
||||||
/// Get the User documentation of the contract
|
/// Get the User documentation of the contract
|
||||||
/// @param _contractDef The contract definition
|
/// @param _contractDef The contract definition
|
||||||
/// @return A JSON representation of the contract's user documentation
|
/// @return A JSON representation of the contract's user documentation
|
||||||
|
@ -111,7 +111,8 @@ Json::Value formatErrorWithException(
|
|||||||
bool const& _warning,
|
bool const& _warning,
|
||||||
string const& _type,
|
string const& _type,
|
||||||
string const& _component,
|
string const& _component,
|
||||||
string const& _message
|
string const& _message,
|
||||||
|
optional<ErrorId> _errorId = nullopt
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
string message;
|
string message;
|
||||||
@ -122,7 +123,7 @@ Json::Value formatErrorWithException(
|
|||||||
else
|
else
|
||||||
message = _message;
|
message = _message;
|
||||||
|
|
||||||
return formatError(
|
Json::Value error = formatError(
|
||||||
_warning,
|
_warning,
|
||||||
_type,
|
_type,
|
||||||
_component,
|
_component,
|
||||||
@ -131,6 +132,11 @@ Json::Value formatErrorWithException(
|
|||||||
formatSourceLocation(boost::get_error_info<errinfo_sourceLocation>(_exception)),
|
formatSourceLocation(boost::get_error_info<errinfo_sourceLocation>(_exception)),
|
||||||
formatSecondarySourceLocation(boost::get_error_info<errinfo_secondarySourceLocation>(_exception))
|
formatSecondarySourceLocation(boost::get_error_info<errinfo_secondarySourceLocation>(_exception))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (_errorId)
|
||||||
|
error["errorCode"] = to_string(_errorId.value().error);
|
||||||
|
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
map<string, set<string>> requestedContractNames(Json::Value const& _outputSelection)
|
map<string, set<string>> requestedContractNames(Json::Value const& _outputSelection)
|
||||||
@ -857,7 +863,8 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
|
|||||||
err.type() == Error::Type::Warning,
|
err.type() == Error::Type::Warning,
|
||||||
err.typeName(),
|
err.typeName(),
|
||||||
"general",
|
"general",
|
||||||
""
|
"",
|
||||||
|
err.errorId()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ Json::Value StorageLayout::generate(VariableDeclaration const& _var, u256 const&
|
|||||||
TypePointer varType = _var.type();
|
TypePointer varType = _var.type();
|
||||||
|
|
||||||
varEntry["label"] = _var.name();
|
varEntry["label"] = _var.name();
|
||||||
varEntry["astId"] = int(_var.id());
|
varEntry["astId"] = static_cast<int>(_var.id());
|
||||||
varEntry["contract"] = m_contract->fullyQualifiedName();
|
varEntry["contract"] = m_contract->fullyQualifiedName();
|
||||||
varEntry["slot"] = _slot.str();
|
varEntry["slot"] = _slot.str();
|
||||||
varEntry["offset"] = _offset;
|
varEntry["offset"] = _offset;
|
||||||
|
@ -106,7 +106,7 @@ bytes solidity::util::fromHex(std::string const& _s, WhenError _throw)
|
|||||||
{
|
{
|
||||||
int h = fromHex(_s[s++], _throw);
|
int h = fromHex(_s[s++], _throw);
|
||||||
if (h != -1)
|
if (h != -1)
|
||||||
ret.push_back(h);
|
ret.push_back(static_cast<uint8_t>(h));
|
||||||
else
|
else
|
||||||
return bytes();
|
return bytes();
|
||||||
}
|
}
|
||||||
@ -115,7 +115,7 @@ bytes solidity::util::fromHex(std::string const& _s, WhenError _throw)
|
|||||||
int h = fromHex(_s[i], _throw);
|
int h = fromHex(_s[i], _throw);
|
||||||
int l = fromHex(_s[i + 1], _throw);
|
int l = fromHex(_s[i + 1], _throw);
|
||||||
if (h != -1 && l != -1)
|
if (h != -1 && l != -1)
|
||||||
ret.push_back((uint8_t)(h * 16 + l));
|
ret.push_back(static_cast<uint8_t>(h * 16 + l));
|
||||||
else
|
else
|
||||||
return bytes();
|
return bytes();
|
||||||
}
|
}
|
||||||
@ -148,14 +148,14 @@ string solidity::util::getChecksummedAddress(string const& _addr)
|
|||||||
h256 hash = keccak256(boost::algorithm::to_lower_copy(s, std::locale::classic()));
|
h256 hash = keccak256(boost::algorithm::to_lower_copy(s, std::locale::classic()));
|
||||||
|
|
||||||
string ret = "0x";
|
string ret = "0x";
|
||||||
for (size_t i = 0; i < 40; ++i)
|
for (unsigned i = 0; i < 40; ++i)
|
||||||
{
|
{
|
||||||
char addressCharacter = s[i];
|
char addressCharacter = s[i];
|
||||||
unsigned nibble = (unsigned(hash[i / 2]) >> (4 * (1 - (i % 2)))) & 0xf;
|
uint8_t nibble = hash[i / 2u] >> (4u * (1u - (i % 2u))) & 0xf;
|
||||||
if (nibble >= 8)
|
if (nibble >= 8)
|
||||||
ret += toupper(addressCharacter);
|
ret += static_cast<char>(toupper(addressCharacter));
|
||||||
else
|
else
|
||||||
ret += tolower(addressCharacter);
|
ret += static_cast<char>(tolower(addressCharacter));
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -64,10 +64,44 @@ public:
|
|||||||
FixedHash(Arith const& _arith) { toBigEndian(_arith, m_data); }
|
FixedHash(Arith const& _arith) { toBigEndian(_arith, m_data); }
|
||||||
|
|
||||||
/// Explicitly construct, copying from a byte array.
|
/// Explicitly construct, copying from a byte array.
|
||||||
explicit FixedHash(bytes const& _b, ConstructFromHashType _t = FailIfDifferent) { if (_b.size() == N) memcpy(m_data.data(), _b.data(), std::min<unsigned>(_b.size(), N)); else { m_data.fill(0); if (_t != FailIfDifferent) { auto c = std::min<unsigned>(_b.size(), N); for (unsigned i = 0; i < c; ++i) m_data[_t == AlignRight ? N - 1 - i : i] = _b[_t == AlignRight ? _b.size() - 1 - i : i]; } } }
|
explicit FixedHash(bytes const& _array, ConstructFromHashType _sizeMismatchBehavior = FailIfDifferent)
|
||||||
|
{
|
||||||
|
if (_array.size() == N)
|
||||||
|
memcpy(m_data.data(), _array.data(), _array.size());
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_data.fill(0);
|
||||||
|
if (_sizeMismatchBehavior != FailIfDifferent)
|
||||||
|
{
|
||||||
|
auto bytesToCopy = std::min<size_t>(_array.size(), N);
|
||||||
|
for (size_t i = 0; i < bytesToCopy; ++i)
|
||||||
|
if (_sizeMismatchBehavior == AlignRight)
|
||||||
|
m_data[N - 1 - i] = _array[_array.size() - 1 - i];
|
||||||
|
else
|
||||||
|
m_data[i] = _array[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Explicitly construct, copying from a byte array.
|
/// Explicitly construct, copying from a byte array.
|
||||||
explicit FixedHash(bytesConstRef _b, ConstructFromHashType _t = FailIfDifferent) { if (_b.size() == N) memcpy(m_data.data(), _b.data(), std::min<unsigned>(_b.size(), N)); else { m_data.fill(0); if (_t != FailIfDifferent) { auto c = std::min<unsigned>(_b.size(), N); for (unsigned i = 0; i < c; ++i) m_data[_t == AlignRight ? N - 1 - i : i] = _b[_t == AlignRight ? _b.size() - 1 - i : i]; } } }
|
explicit FixedHash(bytesConstRef _b, ConstructFromHashType _t = FailIfDifferent)
|
||||||
|
{
|
||||||
|
if (_b.size() == N)
|
||||||
|
memcpy(m_data.data(), _b.data(), std::min<size_t>(_b.size(), N));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_data.fill(0);
|
||||||
|
if (_t != FailIfDifferent)
|
||||||
|
{
|
||||||
|
auto c = std::min<size_t>(_b.size(), N);
|
||||||
|
for (size_t i = 0; i < c; ++i)
|
||||||
|
if (_t == AlignRight)
|
||||||
|
m_data[N - 1 - i] = _b[_b.size() - 1 - i];
|
||||||
|
else
|
||||||
|
m_data[i] = _b[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Explicitly construct, copying from a string.
|
/// Explicitly construct, copying from a string.
|
||||||
explicit FixedHash(std::string const& _s, ConstructFromStringType _t = FromHex, ConstructFromHashType _ht = FailIfDifferent): FixedHash(_t == FromHex ? fromHex(_s, WhenError::Throw) : solidity::util::asBytes(_s), _ht) {}
|
explicit FixedHash(std::string const& _s, ConstructFromStringType _t = FromHex, ConstructFromHashType _ht = FailIfDifferent): FixedHash(_t == FromHex ? fromHex(_s, WhenError::Throw) : solidity::util::asBytes(_s), _ht) {}
|
||||||
|
@ -69,25 +69,25 @@ static uint64_t const RC[24] = \
|
|||||||
#define REPEAT6(e) e e e e e e
|
#define REPEAT6(e) e e e e e e
|
||||||
#define REPEAT24(e) REPEAT6(e e e e)
|
#define REPEAT24(e) REPEAT6(e e e e)
|
||||||
#define REPEAT5(e) e e e e e
|
#define REPEAT5(e) e e e e e
|
||||||
#define FOR5(v, s, e) \
|
#define FOR5(type, v, s, e) \
|
||||||
v = 0; \
|
v = 0; \
|
||||||
REPEAT5(e; v += s;)
|
REPEAT5(e; v = static_cast<type>(v + s);)
|
||||||
|
|
||||||
/*** Keccak-f[1600] ***/
|
/*** Keccak-f[1600] ***/
|
||||||
static inline void keccakf(void* state) {
|
static inline void keccakf(void* state) {
|
||||||
uint64_t* a = (uint64_t*)state;
|
auto* a = static_cast<uint64_t*>(state);
|
||||||
uint64_t b[5] = {0};
|
uint64_t b[5] = {0};
|
||||||
|
|
||||||
for (int i = 0; i < 24; i++)
|
for (int i = 0; i < 24; i++)
|
||||||
{
|
{
|
||||||
uint8_t x, y;
|
uint8_t x, y;
|
||||||
// Theta
|
// Theta
|
||||||
FOR5(x, 1,
|
FOR5(uint8_t, x, 1,
|
||||||
b[x] = 0;
|
b[x] = 0;
|
||||||
FOR5(y, 5,
|
FOR5(uint8_t, y, 5,
|
||||||
b[x] ^= a[x + y]; ))
|
b[x] ^= a[x + y]; ))
|
||||||
FOR5(x, 1,
|
FOR5(uint8_t, x, 1,
|
||||||
FOR5(y, 5,
|
FOR5(uint8_t, y, 5,
|
||||||
a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); ))
|
a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); ))
|
||||||
// Rho and pi
|
// Rho and pi
|
||||||
uint64_t t = a[1];
|
uint64_t t = a[1];
|
||||||
@ -97,11 +97,12 @@ static inline void keccakf(void* state) {
|
|||||||
t = b[0];
|
t = b[0];
|
||||||
x++; )
|
x++; )
|
||||||
// Chi
|
// Chi
|
||||||
FOR5(y,
|
FOR5(uint8_t,
|
||||||
|
y,
|
||||||
5,
|
5,
|
||||||
FOR5(x, 1,
|
FOR5(uint8_t, x, 1,
|
||||||
b[x] = a[y + x];)
|
b[x] = a[y + x];)
|
||||||
FOR5(x, 1,
|
FOR5(uint8_t, x, 1,
|
||||||
a[y + x] = b[x] ^ ((~b[(x + 1) % 5]) & b[(x + 2) % 5]); ))
|
a[y + x] = b[x] ^ ((~b[(x + 1) % 5]) & b[(x + 2) % 5]); ))
|
||||||
// Iota
|
// Iota
|
||||||
a[0] ^= RC[i];
|
a[0] ^= RC[i];
|
||||||
|
@ -137,7 +137,7 @@ vector<YulString> AsmAnalyzer::operator()(Identifier const& _identifier)
|
|||||||
{
|
{
|
||||||
bool insideFunction = m_currentScope->insideFunction();
|
bool insideFunction = m_currentScope->insideFunction();
|
||||||
size_t stackSize = m_resolver(_identifier, yul::IdentifierContext::RValue, insideFunction);
|
size_t stackSize = m_resolver(_identifier, yul::IdentifierContext::RValue, insideFunction);
|
||||||
if (stackSize != size_t(-1))
|
if (stackSize != numeric_limits<size_t>::max())
|
||||||
{
|
{
|
||||||
found = true;
|
found = true;
|
||||||
yulAssert(stackSize == 1, "Invalid stack size of external reference.");
|
yulAssert(stackSize == 1, "Invalid stack size of external reference.");
|
||||||
@ -479,7 +479,7 @@ void AsmAnalyzer::checkAssignment(Identifier const& _variable, YulString _valueT
|
|||||||
{
|
{
|
||||||
bool insideFunction = m_currentScope->insideFunction();
|
bool insideFunction = m_currentScope->insideFunction();
|
||||||
size_t variableSize = m_resolver(_variable, yul::IdentifierContext::LValue, insideFunction);
|
size_t variableSize = m_resolver(_variable, yul::IdentifierContext::LValue, insideFunction);
|
||||||
if (variableSize != size_t(-1))
|
if (variableSize != numeric_limits<size_t>::max())
|
||||||
{
|
{
|
||||||
found = true;
|
found = true;
|
||||||
variableType = &m_dialect.defaultType;
|
variableType = &m_dialect.defaultType;
|
||||||
|
@ -45,7 +45,7 @@ string solidity::yul::reindent(string const& _code)
|
|||||||
auto const static countBraces = [](string const& _s) noexcept -> int
|
auto const static countBraces = [](string const& _s) noexcept -> int
|
||||||
{
|
{
|
||||||
auto const i = _s.find("//");
|
auto const i = _s.find("//");
|
||||||
auto const e = i == _s.npos ? end(_s) : next(begin(_s), i);
|
auto const e = i == _s.npos ? end(_s) : next(begin(_s), static_cast<ptrdiff_t>(i));
|
||||||
auto const opening = count_if(begin(_s), e, [](auto ch) { return ch == '{' || ch == '('; });
|
auto const opening = count_if(begin(_s), e, [](auto ch) { return ch == '{' || ch == '('; });
|
||||||
auto const closing = count_if(begin(_s), e, [](auto ch) { return ch == '}' || ch == ')'; });
|
auto const closing = count_if(begin(_s), e, [](auto ch) { return ch == '}' || ch == ')'; });
|
||||||
return opening - closing;
|
return opening - closing;
|
||||||
|
@ -71,10 +71,10 @@ public:
|
|||||||
{
|
{
|
||||||
// FNV hash - can be replaced by a better one, e.g. xxhash64
|
// FNV hash - can be replaced by a better one, e.g. xxhash64
|
||||||
std::uint64_t hash = emptyHash();
|
std::uint64_t hash = emptyHash();
|
||||||
for (auto c: v)
|
for (char c: v)
|
||||||
{
|
{
|
||||||
hash *= 1099511628211u;
|
hash *= 1099511628211u;
|
||||||
hash ^= c;
|
hash ^= static_cast<uint64_t>(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
return hash;
|
return hash;
|
||||||
|
@ -143,14 +143,14 @@ pair<shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> EthAssemblyAdapter::
|
|||||||
{
|
{
|
||||||
shared_ptr<evmasm::Assembly> assembly{make_shared<evmasm::Assembly>()};
|
shared_ptr<evmasm::Assembly> assembly{make_shared<evmasm::Assembly>()};
|
||||||
auto sub = m_assembly.newSub(assembly);
|
auto sub = m_assembly.newSub(assembly);
|
||||||
return {make_shared<EthAssemblyAdapter>(*assembly), size_t(sub.data())};
|
return {make_shared<EthAssemblyAdapter>(*assembly), static_cast<size_t>(sub.data())};
|
||||||
}
|
}
|
||||||
|
|
||||||
void EthAssemblyAdapter::appendDataOffset(AbstractAssembly::SubID _sub)
|
void EthAssemblyAdapter::appendDataOffset(AbstractAssembly::SubID _sub)
|
||||||
{
|
{
|
||||||
auto it = m_dataHashBySubId.find(_sub);
|
auto it = m_dataHashBySubId.find(_sub);
|
||||||
if (it == m_dataHashBySubId.end())
|
if (it == m_dataHashBySubId.end())
|
||||||
m_assembly.pushSubroutineOffset(size_t(_sub));
|
m_assembly.pushSubroutineOffset(_sub);
|
||||||
else
|
else
|
||||||
m_assembly << evmasm::AssemblyItem(evmasm::PushData, it->second);
|
m_assembly << evmasm::AssemblyItem(evmasm::PushData, it->second);
|
||||||
}
|
}
|
||||||
@ -159,7 +159,7 @@ void EthAssemblyAdapter::appendDataSize(AbstractAssembly::SubID _sub)
|
|||||||
{
|
{
|
||||||
auto it = m_dataHashBySubId.find(_sub);
|
auto it = m_dataHashBySubId.find(_sub);
|
||||||
if (it == m_dataHashBySubId.end())
|
if (it == m_dataHashBySubId.end())
|
||||||
m_assembly.pushSubroutineSize(size_t(_sub));
|
m_assembly.pushSubroutineSize(static_cast<size_t>(_sub));
|
||||||
else
|
else
|
||||||
m_assembly << u256(m_assembly.data(h256(it->second)).size());
|
m_assembly << u256(m_assembly.data(h256(it->second)).size());
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,7 @@ void EVMAssembly::appendLabelReference(LabelID _labelId)
|
|||||||
|
|
||||||
EVMAssembly::LabelID EVMAssembly::newLabelId()
|
EVMAssembly::LabelID EVMAssembly::newLabelId()
|
||||||
{
|
{
|
||||||
m_labelPositions[m_nextLabelId] = size_t(-1);
|
m_labelPositions[m_nextLabelId] = numeric_limits<size_t>::max();
|
||||||
return m_nextLabelId++;
|
return m_nextLabelId++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,7 +165,7 @@ evmasm::LinkerObject EVMAssembly::finalize()
|
|||||||
size_t referencePos = ref.first;
|
size_t referencePos = ref.first;
|
||||||
yulAssert(m_labelPositions.count(ref.second), "");
|
yulAssert(m_labelPositions.count(ref.second), "");
|
||||||
size_t labelPos = m_labelPositions.at(ref.second);
|
size_t labelPos = m_labelPositions.at(ref.second);
|
||||||
yulAssert(labelPos != size_t(-1), "Undefined but allocated label used.");
|
yulAssert(labelPos != numeric_limits<size_t>::max(), "Undefined but allocated label used.");
|
||||||
updateReference(referencePos, labelReferenceSize, u256(labelPos));
|
updateReference(referencePos, labelReferenceSize, u256(labelPos));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,7 +177,7 @@ evmasm::LinkerObject EVMAssembly::finalize()
|
|||||||
void EVMAssembly::setLabelToCurrentPosition(LabelID _labelId)
|
void EVMAssembly::setLabelToCurrentPosition(LabelID _labelId)
|
||||||
{
|
{
|
||||||
yulAssert(m_labelPositions.count(_labelId), "Label not found.");
|
yulAssert(m_labelPositions.count(_labelId), "Label not found.");
|
||||||
yulAssert(m_labelPositions[_labelId] == size_t(-1), "Label already set.");
|
yulAssert(m_labelPositions[_labelId] == numeric_limits<size_t>::max(), "Label already set.");
|
||||||
m_labelPositions[_labelId] = m_bytecode.size();
|
m_labelPositions[_labelId] = m_bytecode.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,28 +175,29 @@ void CodeTransform::operator()(VariableDeclaration const& _varDecl)
|
|||||||
{
|
{
|
||||||
yulAssert(m_scope, "");
|
yulAssert(m_scope, "");
|
||||||
|
|
||||||
int const numVariables = _varDecl.variables.size();
|
size_t const numVariables = _varDecl.variables.size();
|
||||||
int heightAtStart = m_assembly.stackHeight();
|
auto heightAtStart = static_cast<size_t>(m_assembly.stackHeight());
|
||||||
if (_varDecl.value)
|
if (_varDecl.value)
|
||||||
{
|
{
|
||||||
std::visit(*this, *_varDecl.value);
|
std::visit(*this, *_varDecl.value);
|
||||||
expectDeposit(numVariables, heightAtStart);
|
expectDeposit(static_cast<int>(numVariables), static_cast<int>(heightAtStart));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_assembly.setSourceLocation(_varDecl.location);
|
m_assembly.setSourceLocation(_varDecl.location);
|
||||||
int variablesLeft = numVariables;
|
size_t variablesLeft = numVariables;
|
||||||
while (variablesLeft--)
|
while (variablesLeft--)
|
||||||
m_assembly.appendConstant(u256(0));
|
m_assembly.appendConstant(u256(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
m_assembly.setSourceLocation(_varDecl.location);
|
m_assembly.setSourceLocation(_varDecl.location);
|
||||||
bool atTopOfStack = true;
|
bool atTopOfStack = true;
|
||||||
for (int varIndex = numVariables - 1; varIndex >= 0; --varIndex)
|
for (size_t varIndex = 0; varIndex < numVariables; ++varIndex)
|
||||||
{
|
{
|
||||||
YulString varName = _varDecl.variables[varIndex].name;
|
size_t varIndexReverse = numVariables - 1 - varIndex;
|
||||||
|
YulString varName = _varDecl.variables[varIndexReverse].name;
|
||||||
auto& var = std::get<Scope::Variable>(m_scope->identifiers.at(varName));
|
auto& var = std::get<Scope::Variable>(m_scope->identifiers.at(varName));
|
||||||
m_context->variableStackHeights[&var] = heightAtStart + varIndex;
|
m_context->variableStackHeights[&var] = heightAtStart + varIndexReverse;
|
||||||
if (!m_allowStackOpt)
|
if (!m_allowStackOpt)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -214,10 +215,10 @@ void CodeTransform::operator()(VariableDeclaration const& _varDecl)
|
|||||||
atTopOfStack = false;
|
atTopOfStack = false;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int slot = *m_unusedStackSlots.begin();
|
auto slot = static_cast<size_t>(*m_unusedStackSlots.begin());
|
||||||
m_unusedStackSlots.erase(m_unusedStackSlots.begin());
|
m_unusedStackSlots.erase(m_unusedStackSlots.begin());
|
||||||
m_context->variableStackHeights[&var] = slot;
|
m_context->variableStackHeights[&var] = slot;
|
||||||
if (int heightDiff = variableHeightDiff(var, varName, true))
|
if (size_t heightDiff = variableHeightDiff(var, varName, true))
|
||||||
m_assembly.appendInstruction(evmasm::swapInstruction(heightDiff - 1));
|
m_assembly.appendInstruction(evmasm::swapInstruction(heightDiff - 1));
|
||||||
m_assembly.appendInstruction(evmasm::Instruction::POP);
|
m_assembly.appendInstruction(evmasm::Instruction::POP);
|
||||||
}
|
}
|
||||||
@ -240,7 +241,7 @@ void CodeTransform::operator()(Assignment const& _assignment)
|
|||||||
{
|
{
|
||||||
int height = m_assembly.stackHeight();
|
int height = m_assembly.stackHeight();
|
||||||
std::visit(*this, *_assignment.value);
|
std::visit(*this, *_assignment.value);
|
||||||
expectDeposit(_assignment.variableNames.size(), height);
|
expectDeposit(static_cast<int>(_assignment.variableNames.size()), height);
|
||||||
|
|
||||||
m_assembly.setSourceLocation(_assignment.location);
|
m_assembly.setSourceLocation(_assignment.location);
|
||||||
generateMultiAssignment(_assignment.variableNames);
|
generateMultiAssignment(_assignment.variableNames);
|
||||||
@ -263,7 +264,7 @@ void CodeTransform::operator()(FunctionCall const& _call)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_assembly.setSourceLocation(_call.location);
|
m_assembly.setSourceLocation(_call.location);
|
||||||
EVMAssembly::LabelID returnLabel(-1); // only used for evm 1.0
|
EVMAssembly::LabelID returnLabel(numeric_limits<EVMAssembly::LabelID>::max()); // only used for evm 1.0
|
||||||
if (!m_evm15)
|
if (!m_evm15)
|
||||||
{
|
{
|
||||||
returnLabel = m_assembly.newLabelId();
|
returnLabel = m_assembly.newLabelId();
|
||||||
@ -281,10 +282,17 @@ void CodeTransform::operator()(FunctionCall const& _call)
|
|||||||
visitExpression(arg);
|
visitExpression(arg);
|
||||||
m_assembly.setSourceLocation(_call.location);
|
m_assembly.setSourceLocation(_call.location);
|
||||||
if (m_evm15)
|
if (m_evm15)
|
||||||
m_assembly.appendJumpsub(functionEntryID(_call.functionName.name, *function), function->arguments.size(), function->returns.size());
|
m_assembly.appendJumpsub(
|
||||||
|
functionEntryID(_call.functionName.name, *function),
|
||||||
|
static_cast<int>(function->arguments.size()),
|
||||||
|
static_cast<int>(function->returns.size())
|
||||||
|
);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_assembly.appendJumpTo(functionEntryID(_call.functionName.name, *function), function->returns.size() - function->arguments.size() - 1);
|
m_assembly.appendJumpTo(
|
||||||
|
functionEntryID(_call.functionName.name, *function),
|
||||||
|
static_cast<int>(function->returns.size() - function->arguments.size()) - 1
|
||||||
|
);
|
||||||
m_assembly.appendLabel(returnLabel);
|
m_assembly.appendLabel(returnLabel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -300,7 +308,7 @@ void CodeTransform::operator()(Identifier const& _identifier)
|
|||||||
{
|
{
|
||||||
// TODO: opportunity for optimization: Do not DUP if this is the last reference
|
// TODO: opportunity for optimization: Do not DUP if this is the last reference
|
||||||
// to the top most element of the stack
|
// to the top most element of the stack
|
||||||
if (int heightDiff = variableHeightDiff(_var, _identifier.name, false))
|
if (size_t heightDiff = variableHeightDiff(_var, _identifier.name, false))
|
||||||
m_assembly.appendInstruction(evmasm::dupInstruction(heightDiff));
|
m_assembly.appendInstruction(evmasm::dupInstruction(heightDiff));
|
||||||
else
|
else
|
||||||
// Store something to balance the stack
|
// Store something to balance the stack
|
||||||
@ -407,7 +415,7 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
|
|||||||
int const stackHeightBefore = m_assembly.stackHeight();
|
int const stackHeightBefore = m_assembly.stackHeight();
|
||||||
|
|
||||||
if (m_evm15)
|
if (m_evm15)
|
||||||
m_assembly.appendBeginsub(functionEntryID(_function.name, function), _function.parameters.size());
|
m_assembly.appendBeginsub(functionEntryID(_function.name, function), static_cast<int>(_function.parameters.size()));
|
||||||
else
|
else
|
||||||
m_assembly.appendLabel(functionEntryID(_function.name, function));
|
m_assembly.appendLabel(functionEntryID(_function.name, function));
|
||||||
|
|
||||||
@ -465,15 +473,15 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
|
|||||||
// modified parallel to the actual stack.
|
// modified parallel to the actual stack.
|
||||||
vector<int> stackLayout;
|
vector<int> stackLayout;
|
||||||
if (!m_evm15)
|
if (!m_evm15)
|
||||||
stackLayout.push_back(_function.returnVariables.size()); // Move return label to the top
|
stackLayout.push_back(static_cast<int>(_function.returnVariables.size())); // Move return label to the top
|
||||||
stackLayout += vector<int>(_function.parameters.size(), -1); // discard all arguments
|
stackLayout += vector<int>(_function.parameters.size(), -1); // discard all arguments
|
||||||
|
|
||||||
for (size_t i = 0; i < _function.returnVariables.size(); ++i)
|
for (size_t i = 0; i < _function.returnVariables.size(); ++i)
|
||||||
stackLayout.push_back(i); // Move return values down, but keep order.
|
stackLayout.push_back(static_cast<int>(i)); // Move return values down, but keep order.
|
||||||
|
|
||||||
if (stackLayout.size() > 17)
|
if (stackLayout.size() > 17)
|
||||||
{
|
{
|
||||||
StackTooDeepError error(_function.name, YulString{}, stackLayout.size() - 17);
|
StackTooDeepError error(_function.name, YulString{}, static_cast<int>(stackLayout.size()) - 17);
|
||||||
error << errinfo_comment(
|
error << errinfo_comment(
|
||||||
"The function " +
|
"The function " +
|
||||||
_function.name.str() +
|
_function.name.str() +
|
||||||
@ -481,11 +489,11 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
|
|||||||
to_string(stackLayout.size() - 17) +
|
to_string(stackLayout.size() - 17) +
|
||||||
" parameters or return variables too many to fit the stack size."
|
" parameters or return variables too many to fit the stack size."
|
||||||
);
|
);
|
||||||
stackError(std::move(error), m_assembly.stackHeight() - _function.parameters.size());
|
stackError(std::move(error), m_assembly.stackHeight() - static_cast<int>(_function.parameters.size()));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
while (!stackLayout.empty() && stackLayout.back() != int(stackLayout.size() - 1))
|
while (!stackLayout.empty() && stackLayout.back() != static_cast<int>(stackLayout.size() - 1))
|
||||||
if (stackLayout.back() < 0)
|
if (stackLayout.back() < 0)
|
||||||
{
|
{
|
||||||
m_assembly.appendInstruction(evmasm::Instruction::POP);
|
m_assembly.appendInstruction(evmasm::Instruction::POP);
|
||||||
@ -493,17 +501,17 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_assembly.appendInstruction(evmasm::swapInstruction(stackLayout.size() - stackLayout.back() - 1));
|
m_assembly.appendInstruction(evmasm::swapInstruction(stackLayout.size() - static_cast<size_t>(stackLayout.back()) - 1));
|
||||||
swap(stackLayout[stackLayout.back()], stackLayout.back());
|
swap(stackLayout[static_cast<size_t>(stackLayout.back())], stackLayout.back());
|
||||||
}
|
}
|
||||||
for (int i = 0; size_t(i) < stackLayout.size(); ++i)
|
for (size_t i = 0; i < stackLayout.size(); ++i)
|
||||||
yulAssert(i == stackLayout[i], "Error reshuffling stack.");
|
yulAssert(i == static_cast<size_t>(stackLayout[i]), "Error reshuffling stack.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (m_evm15)
|
if (m_evm15)
|
||||||
m_assembly.appendReturnsub(_function.returnVariables.size(), stackHeightBefore);
|
m_assembly.appendReturnsub(static_cast<int>(_function.returnVariables.size()), stackHeightBefore);
|
||||||
else
|
else
|
||||||
m_assembly.appendJump(stackHeightBefore - _function.returnVariables.size());
|
m_assembly.appendJump(stackHeightBefore - static_cast<int>(_function.returnVariables.size()));
|
||||||
m_assembly.setStackHeight(stackHeightBefore);
|
m_assembly.setStackHeight(stackHeightBefore);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -683,7 +691,7 @@ void CodeTransform::generateAssignment(Identifier const& _variableName)
|
|||||||
if (auto var = m_scope->lookup(_variableName.name))
|
if (auto var = m_scope->lookup(_variableName.name))
|
||||||
{
|
{
|
||||||
Scope::Variable const& _var = std::get<Scope::Variable>(*var);
|
Scope::Variable const& _var = std::get<Scope::Variable>(*var);
|
||||||
if (int heightDiff = variableHeightDiff(_var, _variableName.name, true))
|
if (size_t heightDiff = variableHeightDiff(_var, _variableName.name, true))
|
||||||
m_assembly.appendInstruction(evmasm::swapInstruction(heightDiff - 1));
|
m_assembly.appendInstruction(evmasm::swapInstruction(heightDiff - 1));
|
||||||
m_assembly.appendInstruction(evmasm::Instruction::POP);
|
m_assembly.appendInstruction(evmasm::Instruction::POP);
|
||||||
decreaseReference(_variableName.name, _var);
|
decreaseReference(_variableName.name, _var);
|
||||||
@ -698,12 +706,12 @@ void CodeTransform::generateAssignment(Identifier const& _variableName)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int CodeTransform::variableHeightDiff(Scope::Variable const& _var, YulString _varName, bool _forSwap)
|
size_t CodeTransform::variableHeightDiff(Scope::Variable const& _var, YulString _varName, bool _forSwap)
|
||||||
{
|
{
|
||||||
yulAssert(m_context->variableStackHeights.count(&_var), "");
|
yulAssert(m_context->variableStackHeights.count(&_var), "");
|
||||||
int heightDiff = m_assembly.stackHeight() - m_context->variableStackHeights[&_var];
|
size_t heightDiff = static_cast<size_t>(m_assembly.stackHeight()) - m_context->variableStackHeights[&_var];
|
||||||
yulAssert(heightDiff > (_forSwap ? 1 : 0), "Negative stack difference for variable.");
|
yulAssert(heightDiff > (_forSwap ? 1 : 0), "Negative stack difference for variable.");
|
||||||
int limit = _forSwap ? 17 : 16;
|
size_t limit = _forSwap ? 17 : 16;
|
||||||
if (heightDiff > limit)
|
if (heightDiff > limit)
|
||||||
{
|
{
|
||||||
m_stackErrors.emplace_back(_varName, heightDiff - limit);
|
m_stackErrors.emplace_back(_varName, heightDiff - limit);
|
||||||
@ -723,4 +731,3 @@ void CodeTransform::expectDeposit(int _deposit, int _oldHeight) const
|
|||||||
{
|
{
|
||||||
yulAssert(m_assembly.stackHeight() == _oldHeight + _deposit, "Invalid stack deposit.");
|
yulAssert(m_assembly.stackHeight() == _oldHeight + _deposit, "Invalid stack deposit.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ struct StackTooDeepError: virtual YulException
|
|||||||
struct CodeTransformContext
|
struct CodeTransformContext
|
||||||
{
|
{
|
||||||
std::map<Scope::Function const*, AbstractAssembly::LabelID> functionEntryIDs;
|
std::map<Scope::Function const*, AbstractAssembly::LabelID> functionEntryIDs;
|
||||||
std::map<Scope::Variable const*, int> variableStackHeights;
|
std::map<Scope::Variable const*, size_t> variableStackHeights;
|
||||||
std::map<Scope::Variable const*, unsigned> variableReferences;
|
std::map<Scope::Variable const*, unsigned> variableReferences;
|
||||||
|
|
||||||
struct JumpInfo
|
struct JumpInfo
|
||||||
@ -200,7 +200,7 @@ private:
|
|||||||
/// Determines the stack height difference to the given variables. Throws
|
/// Determines the stack height difference to the given variables. Throws
|
||||||
/// if it is not yet in scope or the height difference is too large. Returns
|
/// if it is not yet in scope or the height difference is too large. Returns
|
||||||
/// the (positive) stack height difference otherwise.
|
/// the (positive) stack height difference otherwise.
|
||||||
int variableHeightDiff(Scope::Variable const& _var, YulString _name, bool _forSwap);
|
size_t variableHeightDiff(Scope::Variable const& _var, YulString _name, bool _forSwap);
|
||||||
|
|
||||||
void expectDeposit(int _deposit, int _oldHeight) const;
|
void expectDeposit(int _deposit, int _oldHeight) const;
|
||||||
|
|
||||||
|
@ -63,8 +63,8 @@ pair<YulString, BuiltinFunctionForEVM> createEVMFunction(
|
|||||||
evmasm::InstructionInfo info = evmasm::instructionInfo(_instruction);
|
evmasm::InstructionInfo info = evmasm::instructionInfo(_instruction);
|
||||||
BuiltinFunctionForEVM f;
|
BuiltinFunctionForEVM f;
|
||||||
f.name = YulString{_name};
|
f.name = YulString{_name};
|
||||||
f.parameters.resize(info.args);
|
f.parameters.resize(static_cast<size_t>(info.args));
|
||||||
f.returns.resize(info.ret);
|
f.returns.resize(static_cast<size_t>(info.ret));
|
||||||
f.sideEffects = EVMDialect::sideEffectsOfInstruction(_instruction);
|
f.sideEffects = EVMDialect::sideEffectsOfInstruction(_instruction);
|
||||||
f.controlFlowSideEffects.terminates = evmasm::SemanticInformation::terminatesControlFlow(_instruction);
|
f.controlFlowSideEffects.terminates = evmasm::SemanticInformation::terminatesControlFlow(_instruction);
|
||||||
f.controlFlowSideEffects.reverts = evmasm::SemanticInformation::reverts(_instruction);
|
f.controlFlowSideEffects.reverts = evmasm::SemanticInformation::reverts(_instruction);
|
||||||
|
@ -91,7 +91,11 @@ void GasMeterVisitor::operator()(Literal const& _lit)
|
|||||||
m_runGas += evmasm::GasMeter::runGas(evmasm::Instruction::PUSH1);
|
m_runGas += evmasm::GasMeter::runGas(evmasm::Instruction::PUSH1);
|
||||||
m_dataGas +=
|
m_dataGas +=
|
||||||
singleByteDataGas() +
|
singleByteDataGas() +
|
||||||
size_t(evmasm::GasMeter::dataGas(toCompactBigEndian(valueOfLiteral(_lit), 1), m_isCreation, m_dialect.evmVersion()));
|
static_cast<size_t>(evmasm::GasMeter::dataGas(
|
||||||
|
toCompactBigEndian(valueOfLiteral(_lit), 1),
|
||||||
|
m_isCreation,
|
||||||
|
m_dialect.evmVersion()
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
void GasMeterVisitor::operator()(Identifier const&)
|
void GasMeterVisitor::operator()(Identifier const&)
|
||||||
|
@ -22,9 +22,11 @@
|
|||||||
|
|
||||||
#include <libyul/Exceptions.h>
|
#include <libyul/Exceptions.h>
|
||||||
#include <libsolutil/CommonData.h>
|
#include <libsolutil/CommonData.h>
|
||||||
|
#include <libsolutil/Visitor.h>
|
||||||
|
|
||||||
#include <boost/range/adaptor/reversed.hpp>
|
#include <boost/range/adaptor/reversed.hpp>
|
||||||
#include <boost/range/adaptor/map.hpp>
|
#include <boost/range/adaptor/map.hpp>
|
||||||
|
#include <boost/range/adaptor/transformed.hpp>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace solidity;
|
using namespace solidity;
|
||||||
@ -82,6 +84,16 @@ bytes toBytes(ValueType _vt)
|
|||||||
return toBytes(uint8_t(_vt));
|
return toBytes(uint8_t(_vt));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ValueType toValueType(wasm::Type _type)
|
||||||
|
{
|
||||||
|
if (_type == wasm::Type::i32)
|
||||||
|
return ValueType::I32;
|
||||||
|
else if (_type == wasm::Type::i64)
|
||||||
|
return ValueType::I64;
|
||||||
|
else
|
||||||
|
yulAssert(false, "Invalid wasm variable type");
|
||||||
|
}
|
||||||
|
|
||||||
enum class Export: uint8_t
|
enum class Export: uint8_t
|
||||||
{
|
{
|
||||||
Function = 0x0,
|
Function = 0x0,
|
||||||
@ -131,6 +143,16 @@ bytes toBytes(Opcode _o)
|
|||||||
return toBytes(uint8_t(_o));
|
return toBytes(uint8_t(_o));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Opcode constOpcodeFor(ValueType _type)
|
||||||
|
{
|
||||||
|
if (_type == ValueType::I32)
|
||||||
|
return Opcode::I32Const;
|
||||||
|
else if (_type == ValueType::I64)
|
||||||
|
return Opcode::I64Const;
|
||||||
|
else
|
||||||
|
yulAssert(false, "Values of this type cannot be used with const opcode");
|
||||||
|
}
|
||||||
|
|
||||||
static map<string, uint8_t> const builtins = {
|
static map<string, uint8_t> const builtins = {
|
||||||
{"i32.load", 0x28},
|
{"i32.load", 0x28},
|
||||||
{"i64.load", 0x29},
|
{"i64.load", 0x29},
|
||||||
@ -249,6 +271,34 @@ bytes makeSection(Section _section, bytes _data)
|
|||||||
return toBytes(_section) + prefixSize(move(_data));
|
return toBytes(_section) + prefixSize(move(_data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This is a kind of run-length-encoding of local types.
|
||||||
|
vector<pair<size_t, ValueType>> groupLocalVariables(vector<VariableDeclaration> _localVariables)
|
||||||
|
{
|
||||||
|
vector<pair<size_t, ValueType>> localEntries;
|
||||||
|
|
||||||
|
size_t entrySize = 0;
|
||||||
|
ValueType entryType = ValueType::I32; // Any type would work here
|
||||||
|
for (VariableDeclaration const& localVariable: _localVariables)
|
||||||
|
{
|
||||||
|
ValueType variableType = toValueType(localVariable.type);
|
||||||
|
|
||||||
|
if (variableType != entryType)
|
||||||
|
{
|
||||||
|
if (entrySize > 0)
|
||||||
|
localEntries.emplace_back(entrySize, entryType);
|
||||||
|
|
||||||
|
entryType = variableType;
|
||||||
|
entrySize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
++entrySize;
|
||||||
|
}
|
||||||
|
if (entrySize > 0)
|
||||||
|
localEntries.emplace_back(entrySize, entryType);
|
||||||
|
|
||||||
|
return localEntries;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes BinaryTransform::run(Module const& _module)
|
bytes BinaryTransform::run(Module const& _module)
|
||||||
@ -297,7 +347,10 @@ bytes BinaryTransform::run(Module const& _module)
|
|||||||
|
|
||||||
bytes BinaryTransform::operator()(Literal const& _literal)
|
bytes BinaryTransform::operator()(Literal const& _literal)
|
||||||
{
|
{
|
||||||
return toBytes(Opcode::I64Const) + lebEncodeSigned(_literal.value);
|
return std::visit(GenericVisitor{
|
||||||
|
[&](uint32_t _value) -> bytes { return toBytes(Opcode::I32Const) + lebEncodeSigned(static_cast<int32_t>(_value)); },
|
||||||
|
[&](uint64_t _value) -> bytes { return toBytes(Opcode::I64Const) + lebEncodeSigned(static_cast<int64_t>(_value)); },
|
||||||
|
}, _literal.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes BinaryTransform::operator()(StringLiteral const&)
|
bytes BinaryTransform::operator()(StringLiteral const&)
|
||||||
@ -323,12 +376,12 @@ bytes BinaryTransform::operator()(BuiltinCall const& _call)
|
|||||||
if (_call.functionName == "dataoffset")
|
if (_call.functionName == "dataoffset")
|
||||||
{
|
{
|
||||||
string name = get<StringLiteral>(_call.arguments.at(0)).value;
|
string name = get<StringLiteral>(_call.arguments.at(0)).value;
|
||||||
return toBytes(Opcode::I64Const) + lebEncodeSigned(m_subModulePosAndSize.at(name).first);
|
return toBytes(Opcode::I64Const) + lebEncodeSigned(static_cast<int64_t>(m_subModulePosAndSize.at(name).first));
|
||||||
}
|
}
|
||||||
else if (_call.functionName == "datasize")
|
else if (_call.functionName == "datasize")
|
||||||
{
|
{
|
||||||
string name = get<StringLiteral>(_call.arguments.at(0)).value;
|
string name = get<StringLiteral>(_call.arguments.at(0)).value;
|
||||||
return toBytes(Opcode::I64Const) + lebEncodeSigned(m_subModulePosAndSize.at(name).second);
|
return toBytes(Opcode::I64Const) + lebEncodeSigned(static_cast<int64_t>(m_subModulePosAndSize.at(name).second));
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes args = visit(_call.arguments);
|
bytes args = visit(_call.arguments);
|
||||||
@ -443,21 +496,18 @@ bytes BinaryTransform::operator()(FunctionDefinition const& _function)
|
|||||||
{
|
{
|
||||||
bytes ret;
|
bytes ret;
|
||||||
|
|
||||||
// This is a kind of run-length-encoding of local types. Has to be adapted once
|
vector<pair<size_t, ValueType>> localEntries = groupLocalVariables(_function.locals);
|
||||||
// we have locals of different types.
|
ret += lebEncode(localEntries.size());
|
||||||
if (_function.locals.size() == 0)
|
for (pair<size_t, ValueType> const& entry: localEntries)
|
||||||
ret += lebEncode(0); // number of locals groups
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
ret += lebEncode(1); // number of locals groups
|
ret += lebEncode(entry.first);
|
||||||
ret += lebEncode(_function.locals.size());
|
ret += toBytes(entry.second);
|
||||||
ret += toBytes(ValueType::I64);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_locals.clear();
|
m_locals.clear();
|
||||||
size_t varIdx = 0;
|
size_t varIdx = 0;
|
||||||
for (size_t i = 0; i < _function.parameterNames.size(); ++i)
|
for (size_t i = 0; i < _function.parameters.size(); ++i)
|
||||||
m_locals[_function.parameterNames[i]] = varIdx++;
|
m_locals[_function.parameters[i].name] = varIdx++;
|
||||||
for (size_t i = 0; i < _function.locals.size(); ++i)
|
for (size_t i = 0; i < _function.locals.size(); ++i)
|
||||||
m_locals[_function.locals[i].variableName] = varIdx++;
|
m_locals[_function.locals[i].variableName] = varIdx++;
|
||||||
|
|
||||||
@ -475,38 +525,39 @@ BinaryTransform::Type BinaryTransform::typeOf(FunctionImport const& _import)
|
|||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
encodeTypes(_import.paramTypes),
|
encodeTypes(_import.paramTypes),
|
||||||
encodeTypes(_import.returnType ? vector<string>(1, *_import.returnType) : vector<string>())
|
encodeTypes(_import.returnType ? vector<wasm::Type>(1, *_import.returnType) : vector<wasm::Type>())
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
BinaryTransform::Type BinaryTransform::typeOf(FunctionDefinition const& _funDef)
|
BinaryTransform::Type BinaryTransform::typeOf(FunctionDefinition const& _funDef)
|
||||||
{
|
{
|
||||||
|
|
||||||
return {
|
return {
|
||||||
encodeTypes(vector<string>(_funDef.parameterNames.size(), "i64")),
|
encodeTypes(_funDef.parameters),
|
||||||
encodeTypes(vector<string>(_funDef.returns ? 1 : 0, "i64"))
|
encodeTypes(_funDef.returnType ? vector<wasm::Type>(1, *_funDef.returnType) : vector<wasm::Type>())
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t BinaryTransform::encodeType(string const& _typeName)
|
uint8_t BinaryTransform::encodeType(wasm::Type _type)
|
||||||
{
|
{
|
||||||
if (_typeName == "i32")
|
return uint8_t(toValueType(_type));
|
||||||
return uint8_t(ValueType::I32);
|
|
||||||
else if (_typeName == "i64")
|
|
||||||
return uint8_t(ValueType::I64);
|
|
||||||
else
|
|
||||||
yulAssert(false, "");
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<uint8_t> BinaryTransform::encodeTypes(vector<string> const& _typeNames)
|
vector<uint8_t> BinaryTransform::encodeTypes(vector<wasm::Type> const& _types)
|
||||||
{
|
{
|
||||||
vector<uint8_t> result;
|
vector<uint8_t> result;
|
||||||
for (auto const& t: _typeNames)
|
for (wasm::Type t: _types)
|
||||||
result.emplace_back(encodeType(t));
|
result.emplace_back(encodeType(t));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vector<uint8_t> BinaryTransform::encodeTypes(wasm::TypedNameList const& _typedNameList)
|
||||||
|
{
|
||||||
|
vector<uint8_t> result;
|
||||||
|
for (TypedName const& typedName: _typedNameList)
|
||||||
|
result.emplace_back(encodeType(typedName.type));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
map<BinaryTransform::Type, vector<string>> BinaryTransform::typeToFunctionMap(
|
map<BinaryTransform::Type, vector<string>> BinaryTransform::typeToFunctionMap(
|
||||||
vector<wasm::FunctionImport> const& _imports,
|
vector<wasm::FunctionImport> const& _imports,
|
||||||
vector<wasm::FunctionDefinition> const& _functions
|
vector<wasm::FunctionDefinition> const& _functions
|
||||||
@ -612,13 +663,16 @@ bytes BinaryTransform::memorySection()
|
|||||||
bytes BinaryTransform::globalSection(vector<wasm::GlobalVariableDeclaration> const& _globals)
|
bytes BinaryTransform::globalSection(vector<wasm::GlobalVariableDeclaration> const& _globals)
|
||||||
{
|
{
|
||||||
bytes result = lebEncode(_globals.size());
|
bytes result = lebEncode(_globals.size());
|
||||||
for (size_t i = 0; i < _globals.size(); ++i)
|
for (wasm::GlobalVariableDeclaration const& global: _globals)
|
||||||
|
{
|
||||||
|
ValueType globalType = toValueType(global.type);
|
||||||
result +=
|
result +=
|
||||||
toBytes(ValueType::I64) +
|
toBytes(globalType) +
|
||||||
lebEncode(static_cast<uint8_t>(Mutability::Var)) +
|
lebEncode(static_cast<uint8_t>(Mutability::Var)) +
|
||||||
toBytes(Opcode::I64Const) +
|
toBytes(constOpcodeFor(globalType)) +
|
||||||
lebEncodeSigned(0) +
|
lebEncodeSigned(0) +
|
||||||
toBytes(Opcode::End);
|
toBytes(Opcode::End);
|
||||||
|
}
|
||||||
|
|
||||||
return makeSection(Section::GLOBAL, move(result));
|
return makeSection(Section::GLOBAL, move(result));
|
||||||
}
|
}
|
||||||
|
@ -71,8 +71,9 @@ private:
|
|||||||
static Type typeOf(wasm::FunctionImport const& _import);
|
static Type typeOf(wasm::FunctionImport const& _import);
|
||||||
static Type typeOf(wasm::FunctionDefinition const& _funDef);
|
static Type typeOf(wasm::FunctionDefinition const& _funDef);
|
||||||
|
|
||||||
static uint8_t encodeType(std::string const& _typeName);
|
static uint8_t encodeType(wasm::Type _type);
|
||||||
static std::vector<uint8_t> encodeTypes(std::vector<std::string> const& _typeNames);
|
static std::vector<uint8_t> encodeTypes(std::vector<wasm::Type> const& _types);
|
||||||
|
static std::vector<uint8_t> encodeTypes(wasm::TypedNameList const& _typedNameList);
|
||||||
|
|
||||||
static std::map<Type, std::vector<std::string>> typeToFunctionMap(
|
static std::map<Type, std::vector<std::string>> typeToFunctionMap(
|
||||||
std::vector<wasm::FunctionImport> const& _imports,
|
std::vector<wasm::FunctionImport> const& _imports,
|
||||||
|
@ -20,7 +20,10 @@
|
|||||||
|
|
||||||
#include <libyul/backends/wasm/TextTransform.h>
|
#include <libyul/backends/wasm/TextTransform.h>
|
||||||
|
|
||||||
|
#include <libyul/Exceptions.h>
|
||||||
|
|
||||||
#include <libsolutil/StringUtils.h>
|
#include <libsolutil/StringUtils.h>
|
||||||
|
#include <libsolutil/Visitor.h>
|
||||||
|
|
||||||
#include <boost/algorithm/string/join.hpp>
|
#include <boost/algorithm/string/join.hpp>
|
||||||
#include <boost/algorithm/string/replace.hpp>
|
#include <boost/algorithm/string/replace.hpp>
|
||||||
@ -44,9 +47,9 @@ string TextTransform::run(wasm::Module const& _module)
|
|||||||
{
|
{
|
||||||
ret += " (import \"" + imp.module + "\" \"" + imp.externalName + "\" (func $" + imp.internalName;
|
ret += " (import \"" + imp.module + "\" \"" + imp.externalName + "\" (func $" + imp.internalName;
|
||||||
if (!imp.paramTypes.empty())
|
if (!imp.paramTypes.empty())
|
||||||
ret += " (param" + joinHumanReadablePrefixed(imp.paramTypes, " ", " ") + ")";
|
ret += " (param" + joinHumanReadablePrefixed(imp.paramTypes | boost::adaptors::transformed(encodeType), " ", " ") + ")";
|
||||||
if (imp.returnType)
|
if (imp.returnType)
|
||||||
ret += " (result " + *imp.returnType + ")";
|
ret += " (result " + encodeType(*imp.returnType) + ")";
|
||||||
ret += "))\n";
|
ret += "))\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,7 +59,7 @@ string TextTransform::run(wasm::Module const& _module)
|
|||||||
ret += " (export \"main\" (func $main))\n";
|
ret += " (export \"main\" (func $main))\n";
|
||||||
|
|
||||||
for (auto const& g: _module.globals)
|
for (auto const& g: _module.globals)
|
||||||
ret += " (global $" + g.variableName + " (mut i64) (i64.const 0))\n";
|
ret += " (global $" + g.variableName + " (mut " + encodeType(g.type) + ") (" + encodeType(g.type) + ".const 0))\n";
|
||||||
ret += "\n";
|
ret += "\n";
|
||||||
for (auto const& f: _module.functions)
|
for (auto const& f: _module.functions)
|
||||||
ret += transform(f) + "\n";
|
ret += transform(f) + "\n";
|
||||||
@ -65,7 +68,10 @@ string TextTransform::run(wasm::Module const& _module)
|
|||||||
|
|
||||||
string TextTransform::operator()(wasm::Literal const& _literal)
|
string TextTransform::operator()(wasm::Literal const& _literal)
|
||||||
{
|
{
|
||||||
return "(i64.const " + to_string(_literal.value) + ")";
|
return std::visit(GenericVisitor{
|
||||||
|
[&](uint32_t _value) -> string { return "(i32.const " + to_string(_value) + ")"; },
|
||||||
|
[&](uint64_t _value) -> string { return "(i64.const " + to_string(_value) + ")"; },
|
||||||
|
}, _literal.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
string TextTransform::operator()(wasm::StringLiteral const& _literal)
|
string TextTransform::operator()(wasm::StringLiteral const& _literal)
|
||||||
@ -162,12 +168,12 @@ string TextTransform::indented(string const& _in)
|
|||||||
string TextTransform::transform(wasm::FunctionDefinition const& _function)
|
string TextTransform::transform(wasm::FunctionDefinition const& _function)
|
||||||
{
|
{
|
||||||
string ret = "(func $" + _function.name + "\n";
|
string ret = "(func $" + _function.name + "\n";
|
||||||
for (auto const& param: _function.parameterNames)
|
for (auto const& param: _function.parameters)
|
||||||
ret += " (param $" + param + " i64)\n";
|
ret += " (param $" + param.name + " " + encodeType(param.type) + ")\n";
|
||||||
if (_function.returns)
|
if (_function.returnType.has_value())
|
||||||
ret += " (result i64)\n";
|
ret += " (result " + encodeType(_function.returnType.value()) + ")\n";
|
||||||
for (auto const& local: _function.locals)
|
for (auto const& local: _function.locals)
|
||||||
ret += " (local $" + local.variableName + " i64)\n";
|
ret += " (local $" + local.variableName + " " + encodeType(local.type) + ")\n";
|
||||||
ret += indented(joinTransformed(_function.body, '\n'));
|
ret += indented(joinTransformed(_function.body, '\n'));
|
||||||
if (ret.back() != '\n')
|
if (ret.back() != '\n')
|
||||||
ret += '\n';
|
ret += '\n';
|
||||||
@ -193,3 +199,13 @@ string TextTransform::joinTransformed(vector<wasm::Expression> const& _expressio
|
|||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string TextTransform::encodeType(wasm::Type _type)
|
||||||
|
{
|
||||||
|
if (_type == wasm::Type::i32)
|
||||||
|
return "i32";
|
||||||
|
else if (_type == wasm::Type::i64)
|
||||||
|
return "i64";
|
||||||
|
else
|
||||||
|
yulAssert(false, "Invalid wasm type");
|
||||||
|
}
|
||||||
|
@ -63,6 +63,8 @@ private:
|
|||||||
std::vector<wasm::Expression> const& _expressions,
|
std::vector<wasm::Expression> const& _expressions,
|
||||||
char _separator = ' '
|
char _separator = ' '
|
||||||
);
|
);
|
||||||
|
|
||||||
|
static std::string encodeType(wasm::Type _type);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,15 @@
|
|||||||
namespace solidity::yul::wasm
|
namespace solidity::yul::wasm
|
||||||
{
|
{
|
||||||
|
|
||||||
|
enum class Type
|
||||||
|
{
|
||||||
|
i32,
|
||||||
|
i64,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TypedName { std::string name; Type type; };
|
||||||
|
using TypedNameList = std::vector<TypedName>;
|
||||||
|
|
||||||
struct Literal;
|
struct Literal;
|
||||||
struct StringLiteral;
|
struct StringLiteral;
|
||||||
struct LocalVariable;
|
struct LocalVariable;
|
||||||
@ -50,7 +59,7 @@ using Expression = std::variant<
|
|||||||
Block, If, Loop, Branch, BranchIf, Return
|
Block, If, Loop, Branch, BranchIf, Return
|
||||||
>;
|
>;
|
||||||
|
|
||||||
struct Literal { uint64_t value; };
|
struct Literal { std::variant<uint32_t, uint64_t> value; };
|
||||||
struct StringLiteral { std::string value; };
|
struct StringLiteral { std::string value; };
|
||||||
struct LocalVariable { std::string name; };
|
struct LocalVariable { std::string name; };
|
||||||
struct GlobalVariable { std::string name; };
|
struct GlobalVariable { std::string name; };
|
||||||
@ -70,21 +79,21 @@ struct Branch { Label label; };
|
|||||||
struct Return {};
|
struct Return {};
|
||||||
struct BranchIf { Label label; std::unique_ptr<Expression> condition; };
|
struct BranchIf { Label label; std::unique_ptr<Expression> condition; };
|
||||||
|
|
||||||
struct VariableDeclaration { std::string variableName; };
|
struct VariableDeclaration { std::string variableName; Type type; };
|
||||||
struct GlobalVariableDeclaration { std::string variableName; };
|
struct GlobalVariableDeclaration { std::string variableName; Type type; };
|
||||||
struct FunctionImport {
|
struct FunctionImport {
|
||||||
std::string module;
|
std::string module;
|
||||||
std::string externalName;
|
std::string externalName;
|
||||||
std::string internalName;
|
std::string internalName;
|
||||||
std::vector<std::string> paramTypes;
|
std::vector<Type> paramTypes;
|
||||||
std::optional<std::string> returnType;
|
std::optional<Type> returnType;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FunctionDefinition
|
struct FunctionDefinition
|
||||||
{
|
{
|
||||||
std::string name;
|
std::string name;
|
||||||
std::vector<std::string> parameterNames;
|
std::vector<TypedName> parameters;
|
||||||
bool returns;
|
std::optional<Type> returnType;
|
||||||
std::vector<VariableDeclaration> locals;
|
std::vector<VariableDeclaration> locals;
|
||||||
std::vector<Expression> body;
|
std::vector<Expression> body;
|
||||||
};
|
};
|
||||||
|
@ -88,7 +88,7 @@ wasm::Expression WasmCodeTransform::operator()(VariableDeclaration const& _varDe
|
|||||||
for (auto const& var: _varDecl.variables)
|
for (auto const& var: _varDecl.variables)
|
||||||
{
|
{
|
||||||
variableNames.emplace_back(var.name.str());
|
variableNames.emplace_back(var.name.str());
|
||||||
m_localVariables.emplace_back(wasm::VariableDeclaration{variableNames.back()});
|
m_localVariables.emplace_back(wasm::VariableDeclaration{variableNames.back(), wasm::Type::i64});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_varDecl.value)
|
if (_varDecl.value)
|
||||||
@ -127,10 +127,10 @@ wasm::Expression WasmCodeTransform::operator()(FunctionCall const& _call)
|
|||||||
builtin->name.str().substr(4),
|
builtin->name.str().substr(4),
|
||||||
builtin->name.str(),
|
builtin->name.str(),
|
||||||
{},
|
{},
|
||||||
builtin->returns.empty() ? nullopt : make_optional<string>(builtin->returns.front().str())
|
builtin->returns.empty() ? nullopt : make_optional<wasm::Type>(translatedType(builtin->returns.front()))
|
||||||
};
|
};
|
||||||
for (auto const& param: builtin->parameters)
|
for (auto const& param: builtin->parameters)
|
||||||
imp.paramTypes.emplace_back(param.str());
|
imp.paramTypes.emplace_back(translatedType(param));
|
||||||
m_functionsToImport[builtin->name] = std::move(imp);
|
m_functionsToImport[builtin->name] = std::move(imp);
|
||||||
}
|
}
|
||||||
typeConversionNeeded = true;
|
typeConversionNeeded = true;
|
||||||
@ -184,7 +184,7 @@ wasm::Expression WasmCodeTransform::operator()(Literal const& _literal)
|
|||||||
{
|
{
|
||||||
u256 value = valueOfLiteral(_literal);
|
u256 value = valueOfLiteral(_literal);
|
||||||
yulAssert(value <= numeric_limits<uint64_t>::max(), "Literal too large: " + value.str());
|
yulAssert(value <= numeric_limits<uint64_t>::max(), "Literal too large: " + value.str());
|
||||||
return wasm::Literal{uint64_t(value)};
|
return wasm::Literal{static_cast<uint64_t>(value)};
|
||||||
}
|
}
|
||||||
|
|
||||||
wasm::Expression WasmCodeTransform::operator()(If const& _if)
|
wasm::Expression WasmCodeTransform::operator()(If const& _if)
|
||||||
@ -193,7 +193,7 @@ wasm::Expression WasmCodeTransform::operator()(If const& _if)
|
|||||||
|
|
||||||
vector<wasm::Expression> args;
|
vector<wasm::Expression> args;
|
||||||
args.emplace_back(visitReturnByValue(*_if.condition));
|
args.emplace_back(visitReturnByValue(*_if.condition));
|
||||||
args.emplace_back(wasm::Literal{0});
|
args.emplace_back(wasm::Literal{static_cast<uint64_t>(0)});
|
||||||
return wasm::If{
|
return wasm::If{
|
||||||
make_unique<wasm::Expression>(wasm::BuiltinCall{"i64.ne", std::move(args)}),
|
make_unique<wasm::Expression>(wasm::BuiltinCall{"i64.ne", std::move(args)}),
|
||||||
visit(_if.body.statements),
|
visit(_if.body.statements),
|
||||||
@ -205,7 +205,7 @@ wasm::Expression WasmCodeTransform::operator()(Switch const& _switch)
|
|||||||
{
|
{
|
||||||
wasm::Block block;
|
wasm::Block block;
|
||||||
string condition = m_nameDispenser.newName("condition"_yulstring).str();
|
string condition = m_nameDispenser.newName("condition"_yulstring).str();
|
||||||
m_localVariables.emplace_back(wasm::VariableDeclaration{condition});
|
m_localVariables.emplace_back(wasm::VariableDeclaration{condition, wasm::Type::i64});
|
||||||
block.statements.emplace_back(wasm::LocalAssignment{condition, visit(*_switch.expression)});
|
block.statements.emplace_back(wasm::LocalAssignment{condition, visit(*_switch.expression)});
|
||||||
|
|
||||||
vector<wasm::Expression>* currentBlock = &block.statements;
|
vector<wasm::Expression>* currentBlock = &block.statements;
|
||||||
@ -325,10 +325,11 @@ wasm::FunctionDefinition WasmCodeTransform::translateFunction(yul::FunctionDefin
|
|||||||
wasm::FunctionDefinition fun;
|
wasm::FunctionDefinition fun;
|
||||||
fun.name = _fun.name.str();
|
fun.name = _fun.name.str();
|
||||||
for (auto const& param: _fun.parameters)
|
for (auto const& param: _fun.parameters)
|
||||||
fun.parameterNames.emplace_back(param.name.str());
|
fun.parameters.push_back({param.name.str(), wasm::Type::i64});
|
||||||
for (auto const& retParam: _fun.returnVariables)
|
for (auto const& retParam: _fun.returnVariables)
|
||||||
fun.locals.emplace_back(wasm::VariableDeclaration{retParam.name.str()});
|
fun.locals.emplace_back(wasm::VariableDeclaration{retParam.name.str(), wasm::Type::i64});
|
||||||
fun.returns = !_fun.returnVariables.empty();
|
if (!_fun.returnVariables.empty())
|
||||||
|
fun.returnType = wasm::Type::i64;
|
||||||
|
|
||||||
yulAssert(m_localVariables.empty(), "");
|
yulAssert(m_localVariables.empty(), "");
|
||||||
yulAssert(m_functionBodyLabel.empty(), "");
|
yulAssert(m_functionBodyLabel.empty(), "");
|
||||||
@ -361,14 +362,14 @@ wasm::Expression WasmCodeTransform::injectTypeConversionIfNeeded(wasm::FunctionC
|
|||||||
{
|
{
|
||||||
wasm::FunctionImport const& import = m_functionsToImport.at(YulString{_call.functionName});
|
wasm::FunctionImport const& import = m_functionsToImport.at(YulString{_call.functionName});
|
||||||
for (size_t i = 0; i < _call.arguments.size(); ++i)
|
for (size_t i = 0; i < _call.arguments.size(); ++i)
|
||||||
if (import.paramTypes.at(i) == "i32")
|
if (import.paramTypes.at(i) == wasm::Type::i32)
|
||||||
_call.arguments[i] = wasm::BuiltinCall{"i32.wrap_i64", make_vector<wasm::Expression>(std::move(_call.arguments[i]))};
|
_call.arguments[i] = wasm::BuiltinCall{"i32.wrap_i64", make_vector<wasm::Expression>(std::move(_call.arguments[i]))};
|
||||||
else
|
else
|
||||||
yulAssert(import.paramTypes.at(i) == "i64", "Unknown type " + import.paramTypes.at(i));
|
yulAssert(import.paramTypes.at(i) == wasm::Type::i64, "Invalid Wasm type");
|
||||||
|
|
||||||
if (import.returnType && *import.returnType != "i64")
|
if (import.returnType && *import.returnType != wasm::Type::i64)
|
||||||
{
|
{
|
||||||
yulAssert(*import.returnType == "i32", "Invalid type " + *import.returnType);
|
yulAssert(*import.returnType == wasm::Type::i32, "Invalid Wasm type");
|
||||||
return wasm::BuiltinCall{"i64.extend_i32_u", make_vector<wasm::Expression>(std::move(_call))};
|
return wasm::BuiltinCall{"i64.extend_i32_u", make_vector<wasm::Expression>(std::move(_call))};
|
||||||
}
|
}
|
||||||
return {std::move(_call)};
|
return {std::move(_call)};
|
||||||
@ -400,6 +401,17 @@ void WasmCodeTransform::allocateGlobals(size_t _amount)
|
|||||||
{
|
{
|
||||||
while (m_globalVariables.size() < _amount)
|
while (m_globalVariables.size() < _amount)
|
||||||
m_globalVariables.emplace_back(wasm::GlobalVariableDeclaration{
|
m_globalVariables.emplace_back(wasm::GlobalVariableDeclaration{
|
||||||
m_nameDispenser.newName("global_"_yulstring).str()
|
m_nameDispenser.newName("global_"_yulstring).str(),
|
||||||
|
wasm::Type::i64
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wasm::Type WasmCodeTransform::translatedType(yul::Type _yulType)
|
||||||
|
{
|
||||||
|
if (_yulType == "i32"_yulstring)
|
||||||
|
return wasm::Type::i32;
|
||||||
|
else if (_yulType == "i64"_yulstring)
|
||||||
|
return wasm::Type::i64;
|
||||||
|
else
|
||||||
|
yulAssert(false, "This Yul type does not have a corresponding type in Wasm.");
|
||||||
|
}
|
||||||
|
@ -89,6 +89,8 @@ private:
|
|||||||
/// Makes sure that there are at least @a _amount global variables.
|
/// Makes sure that there are at least @a _amount global variables.
|
||||||
void allocateGlobals(size_t _amount);
|
void allocateGlobals(size_t _amount);
|
||||||
|
|
||||||
|
static wasm::Type translatedType(yul::Type _yulType);
|
||||||
|
|
||||||
Dialect const& m_dialect;
|
Dialect const& m_dialect;
|
||||||
NameDispenser m_nameDispenser;
|
NameDispenser m_nameDispenser;
|
||||||
|
|
||||||
|
@ -112,7 +112,7 @@ void WordSizeTransform::operator()(Block& _block)
|
|||||||
yulAssert(varDecl.variables.size() == 1, "");
|
yulAssert(varDecl.variables.size() == 1, "");
|
||||||
auto newLhs = generateU64IdentifierNames(varDecl.variables[0].name);
|
auto newLhs = generateU64IdentifierNames(varDecl.variables[0].name);
|
||||||
vector<Statement> ret;
|
vector<Statement> ret;
|
||||||
for (int i = 0; i < 3; i++)
|
for (size_t i = 0; i < 3; i++)
|
||||||
ret.emplace_back(VariableDeclaration{
|
ret.emplace_back(VariableDeclaration{
|
||||||
varDecl.location,
|
varDecl.location,
|
||||||
{TypedName{varDecl.location, newLhs[i], m_targetDialect.defaultType}},
|
{TypedName{varDecl.location, newLhs[i], m_targetDialect.defaultType}},
|
||||||
@ -143,7 +143,7 @@ void WordSizeTransform::operator()(Block& _block)
|
|||||||
auto newRhs = expandValue(*varDecl.value);
|
auto newRhs = expandValue(*varDecl.value);
|
||||||
auto newLhs = generateU64IdentifierNames(varDecl.variables[0].name);
|
auto newLhs = generateU64IdentifierNames(varDecl.variables[0].name);
|
||||||
vector<Statement> ret;
|
vector<Statement> ret;
|
||||||
for (int i = 0; i < 4; i++)
|
for (size_t i = 0; i < 4; i++)
|
||||||
ret.emplace_back(VariableDeclaration{
|
ret.emplace_back(VariableDeclaration{
|
||||||
varDecl.location,
|
varDecl.location,
|
||||||
{TypedName{varDecl.location, newLhs[i], m_targetDialect.defaultType}},
|
{TypedName{varDecl.location, newLhs[i], m_targetDialect.defaultType}},
|
||||||
@ -172,7 +172,7 @@ void WordSizeTransform::operator()(Block& _block)
|
|||||||
yulAssert(assignment.variableNames.size() == 1, "");
|
yulAssert(assignment.variableNames.size() == 1, "");
|
||||||
auto newLhs = generateU64IdentifierNames(assignment.variableNames[0].name);
|
auto newLhs = generateU64IdentifierNames(assignment.variableNames[0].name);
|
||||||
vector<Statement> ret;
|
vector<Statement> ret;
|
||||||
for (int i = 0; i < 3; i++)
|
for (size_t i = 0; i < 3; i++)
|
||||||
ret.emplace_back(Assignment{
|
ret.emplace_back(Assignment{
|
||||||
assignment.location,
|
assignment.location,
|
||||||
{Identifier{assignment.location, newLhs[i]}},
|
{Identifier{assignment.location, newLhs[i]}},
|
||||||
@ -203,7 +203,7 @@ void WordSizeTransform::operator()(Block& _block)
|
|||||||
auto newRhs = expandValue(*assignment.value);
|
auto newRhs = expandValue(*assignment.value);
|
||||||
YulString lhsName = assignment.variableNames[0].name;
|
YulString lhsName = assignment.variableNames[0].name;
|
||||||
vector<Statement> ret;
|
vector<Statement> ret;
|
||||||
for (int i = 0; i < 4; i++)
|
for (size_t i = 0; i < 4; i++)
|
||||||
ret.emplace_back(Assignment{
|
ret.emplace_back(Assignment{
|
||||||
assignment.location,
|
assignment.location,
|
||||||
{Identifier{assignment.location, m_variableMapping.at(lhsName)[i]}},
|
{Identifier{assignment.location, m_variableMapping.at(lhsName)[i]}},
|
||||||
@ -382,7 +382,7 @@ std::vector<Statement> WordSizeTransform::handleSwitch(Switch& _switch)
|
|||||||
array<YulString, 4> WordSizeTransform::generateU64IdentifierNames(YulString const& _s)
|
array<YulString, 4> WordSizeTransform::generateU64IdentifierNames(YulString const& _s)
|
||||||
{
|
{
|
||||||
yulAssert(m_variableMapping.find(_s) == m_variableMapping.end(), "");
|
yulAssert(m_variableMapping.find(_s) == m_variableMapping.end(), "");
|
||||||
for (int i = 0; i < 4; i++)
|
for (size_t i = 0; i < 4; i++)
|
||||||
m_variableMapping[_s][i] = m_nameDispenser.newName(YulString{_s.str() + "_" + to_string(i)});
|
m_variableMapping[_s][i] = m_nameDispenser.newName(YulString{_s.str() + "_" + to_string(i)});
|
||||||
return m_variableMapping[_s];
|
return m_variableMapping[_s];
|
||||||
}
|
}
|
||||||
@ -392,19 +392,20 @@ array<unique_ptr<Expression>, 4> WordSizeTransform::expandValue(Expression const
|
|||||||
array<unique_ptr<Expression>, 4> ret;
|
array<unique_ptr<Expression>, 4> ret;
|
||||||
if (holds_alternative<Identifier>(_e))
|
if (holds_alternative<Identifier>(_e))
|
||||||
{
|
{
|
||||||
Identifier const& id = std::get<Identifier>(_e);
|
auto const& id = std::get<Identifier>(_e);
|
||||||
for (int i = 0; i < 4; i++)
|
for (size_t i = 0; i < 4; i++)
|
||||||
ret[i] = make_unique<Expression>(Identifier{id.location, m_variableMapping.at(id.name)[i]});
|
ret[i] = make_unique<Expression>(Identifier{id.location, m_variableMapping.at(id.name)[i]});
|
||||||
}
|
}
|
||||||
else if (holds_alternative<Literal>(_e))
|
else if (holds_alternative<Literal>(_e))
|
||||||
{
|
{
|
||||||
Literal const& lit = std::get<Literal>(_e);
|
auto const& lit = std::get<Literal>(_e);
|
||||||
u256 val = valueOfLiteral(lit);
|
u256 val = valueOfLiteral(lit);
|
||||||
for (int i = 3; i >= 0; i--)
|
for (size_t exprIndex = 0; exprIndex < 4; ++exprIndex)
|
||||||
{
|
{
|
||||||
|
size_t exprIndexReverse = 3 - exprIndex;
|
||||||
u256 currentVal = val & std::numeric_limits<uint64_t>::max();
|
u256 currentVal = val & std::numeric_limits<uint64_t>::max();
|
||||||
val >>= 64;
|
val >>= 64;
|
||||||
ret[i] = make_unique<Expression>(
|
ret[exprIndexReverse] = make_unique<Expression>(
|
||||||
Literal{
|
Literal{
|
||||||
lit.location,
|
lit.location,
|
||||||
LiteralKind::Number,
|
LiteralKind::Number,
|
||||||
@ -426,4 +427,3 @@ vector<Expression> WordSizeTransform::expandValueToVector(Expression const& _e)
|
|||||||
ret.emplace_back(std::move(*val));
|
ret.emplace_back(std::move(*val));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,10 +51,10 @@ void DeadCodeEliminator::operator()(Block& _block)
|
|||||||
tie(controlFlowChange, index) = TerminationFinder{m_dialect}.firstUnconditionalControlFlowChange(_block.statements);
|
tie(controlFlowChange, index) = TerminationFinder{m_dialect}.firstUnconditionalControlFlowChange(_block.statements);
|
||||||
|
|
||||||
// Erase everything after the terminating statement that is not a function definition.
|
// Erase everything after the terminating statement that is not a function definition.
|
||||||
if (controlFlowChange != TerminationFinder::ControlFlow::FlowOut && index != size_t(-1))
|
if (controlFlowChange != TerminationFinder::ControlFlow::FlowOut && index != std::numeric_limits<size_t>::max())
|
||||||
_block.statements.erase(
|
_block.statements.erase(
|
||||||
remove_if(
|
remove_if(
|
||||||
_block.statements.begin() + index + 1,
|
_block.statements.begin() + static_cast<ptrdiff_t>(index) + 1,
|
||||||
_block.statements.end(),
|
_block.statements.end(),
|
||||||
[] (Statement const& _s) { return !holds_alternative<yul::FunctionDefinition>(_s); }
|
[] (Statement const& _s) { return !holds_alternative<yul::FunctionDefinition>(_s); }
|
||||||
),
|
),
|
||||||
@ -63,4 +63,3 @@ void DeadCodeEliminator::operator()(Block& _block)
|
|||||||
|
|
||||||
ASTModifier::operator()(_block);
|
ASTModifier::operator()(_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ void ExpressionJoiner::decrementLatestStatementPointer()
|
|||||||
void ExpressionJoiner::resetLatestStatementPointer()
|
void ExpressionJoiner::resetLatestStatementPointer()
|
||||||
{
|
{
|
||||||
m_currentBlock = nullptr;
|
m_currentBlock = nullptr;
|
||||||
m_latestStatementInBlock = size_t(-1);
|
m_latestStatementInBlock = numeric_limits<size_t>::max();
|
||||||
}
|
}
|
||||||
|
|
||||||
Statement* ExpressionJoiner::latestStatement()
|
Statement* ExpressionJoiner::latestStatement()
|
||||||
|
@ -180,7 +180,7 @@ pair<TerminationFinder::ControlFlow, size_t> TerminationFinder::firstUncondition
|
|||||||
if (controlFlow != ControlFlow::FlowOut)
|
if (controlFlow != ControlFlow::FlowOut)
|
||||||
return {controlFlow, i};
|
return {controlFlow, i};
|
||||||
}
|
}
|
||||||
return {ControlFlow::FlowOut, size_t(-1)};
|
return {ControlFlow::FlowOut, numeric_limits<size_t>::max()};
|
||||||
}
|
}
|
||||||
|
|
||||||
TerminationFinder::ControlFlow TerminationFinder::controlFlowKind(Statement const& _statement)
|
TerminationFinder::ControlFlow TerminationFinder::controlFlowKind(Statement const& _statement)
|
||||||
|
@ -178,14 +178,14 @@ bool StackCompressor::run(
|
|||||||
eliminateVariables(
|
eliminateVariables(
|
||||||
_dialect,
|
_dialect,
|
||||||
std::get<Block>(_object.code->statements.at(0)),
|
std::get<Block>(_object.code->statements.at(0)),
|
||||||
stackSurplus.at({}),
|
static_cast<size_t>(stackSurplus.at({})),
|
||||||
allowMSizeOptimzation
|
allowMSizeOptimzation
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 1; i < _object.code->statements.size(); ++i)
|
for (size_t i = 1; i < _object.code->statements.size(); ++i)
|
||||||
{
|
{
|
||||||
FunctionDefinition& fun = std::get<FunctionDefinition>(_object.code->statements[i]);
|
auto& fun = std::get<FunctionDefinition>(_object.code->statements[i]);
|
||||||
if (!stackSurplus.count(fun.name))
|
if (!stackSurplus.count(fun.name))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -193,7 +193,7 @@ bool StackCompressor::run(
|
|||||||
eliminateVariables(
|
eliminateVariables(
|
||||||
_dialect,
|
_dialect,
|
||||||
fun,
|
fun,
|
||||||
stackSurplus.at(fun.name),
|
static_cast<size_t>(stackSurplus.at(fun.name)),
|
||||||
allowMSizeOptimzation
|
allowMSizeOptimzation
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -34,5 +34,5 @@ else
|
|||||||
BUILD_DIR="$1"
|
BUILD_DIR="$1"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
docker run -v $(pwd):/root/project -w /root/project ethereum/solidity-buildpack-deps:emsdk-1.39.15-1 \
|
docker run -v $(pwd):/root/project -w /root/project ethereum/solidity-buildpack-deps:emsdk-1.39.15-2 \
|
||||||
./scripts/travis-emscripten/build_emscripten.sh $BUILD_DIR
|
./scripts/travis-emscripten/build_emscripten.sh $BUILD_DIR
|
||||||
|
@ -177,6 +177,7 @@ static string const g_strVersion = "version";
|
|||||||
static string const g_strIgnoreMissingFiles = "ignore-missing";
|
static string const g_strIgnoreMissingFiles = "ignore-missing";
|
||||||
static string const g_strColor = "color";
|
static string const g_strColor = "color";
|
||||||
static string const g_strNoColor = "no-color";
|
static string const g_strNoColor = "no-color";
|
||||||
|
static string const g_strErrorIds = "error-codes";
|
||||||
static string const g_strOldReporter = "old-reporter";
|
static string const g_strOldReporter = "old-reporter";
|
||||||
|
|
||||||
static string const g_argAbi = g_strAbi;
|
static string const g_argAbi = g_strAbi;
|
||||||
@ -222,6 +223,7 @@ static string const g_stdinFileName = g_stdinFileNameStr;
|
|||||||
static string const g_argIgnoreMissingFiles = g_strIgnoreMissingFiles;
|
static string const g_argIgnoreMissingFiles = g_strIgnoreMissingFiles;
|
||||||
static string const g_argColor = g_strColor;
|
static string const g_argColor = g_strColor;
|
||||||
static string const g_argNoColor = g_strNoColor;
|
static string const g_argNoColor = g_strNoColor;
|
||||||
|
static string const g_argErrorIds = g_strErrorIds;
|
||||||
static string const g_argOldReporter = g_strOldReporter;
|
static string const g_argOldReporter = g_strOldReporter;
|
||||||
|
|
||||||
/// Possible arguments to for --combined-json
|
/// Possible arguments to for --combined-json
|
||||||
@ -878,6 +880,10 @@ General Information)").c_str(),
|
|||||||
g_argNoColor.c_str(),
|
g_argNoColor.c_str(),
|
||||||
"Explicitly disable colored output, disabling terminal auto-detection."
|
"Explicitly disable colored output, disabling terminal auto-detection."
|
||||||
)
|
)
|
||||||
|
(
|
||||||
|
g_argErrorIds.c_str(),
|
||||||
|
"Output error codes."
|
||||||
|
)
|
||||||
(
|
(
|
||||||
g_argOldReporter.c_str(),
|
g_argOldReporter.c_str(),
|
||||||
"Enables old diagnostics reporter (legacy option, will be removed)."
|
"Enables old diagnostics reporter (legacy option, will be removed)."
|
||||||
@ -991,6 +997,8 @@ General Information)").c_str(),
|
|||||||
|
|
||||||
m_coloredOutput = !m_args.count(g_argNoColor) && (isatty(STDERR_FILENO) || m_args.count(g_argColor));
|
m_coloredOutput = !m_args.count(g_argNoColor) && (isatty(STDERR_FILENO) || m_args.count(g_argColor));
|
||||||
|
|
||||||
|
m_withErrorIds = m_args.count(g_argErrorIds);
|
||||||
|
|
||||||
if (m_args.count(g_argHelp) || (isatty(fileno(stdin)) && _argc == 1))
|
if (m_args.count(g_argHelp) || (isatty(fileno(stdin)) && _argc == 1))
|
||||||
{
|
{
|
||||||
sout() << desc;
|
sout() << desc;
|
||||||
@ -1296,7 +1304,7 @@ bool CommandLineInterface::processInput()
|
|||||||
if (m_args.count(g_argOldReporter))
|
if (m_args.count(g_argOldReporter))
|
||||||
formatter = make_unique<SourceReferenceFormatter>(serr(false));
|
formatter = make_unique<SourceReferenceFormatter>(serr(false));
|
||||||
else
|
else
|
||||||
formatter = make_unique<SourceReferenceFormatterHuman>(serr(false), m_coloredOutput);
|
formatter = make_unique<SourceReferenceFormatterHuman>(serr(false), m_coloredOutput, m_withErrorIds);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -1735,7 +1743,7 @@ bool CommandLineInterface::assemble(
|
|||||||
if (m_args.count(g_argOldReporter))
|
if (m_args.count(g_argOldReporter))
|
||||||
formatter = make_unique<SourceReferenceFormatter>(serr(false));
|
formatter = make_unique<SourceReferenceFormatter>(serr(false));
|
||||||
else
|
else
|
||||||
formatter = make_unique<SourceReferenceFormatterHuman>(serr(false), m_coloredOutput);
|
formatter = make_unique<SourceReferenceFormatterHuman>(serr(false), m_coloredOutput, m_withErrorIds);
|
||||||
|
|
||||||
for (auto const& error: stack.errors())
|
for (auto const& error: stack.errors())
|
||||||
{
|
{
|
||||||
|
@ -131,6 +131,8 @@ private:
|
|||||||
CompilerStack::MetadataHash m_metadataHash = CompilerStack::MetadataHash::IPFS;
|
CompilerStack::MetadataHash m_metadataHash = CompilerStack::MetadataHash::IPFS;
|
||||||
/// Whether or not to colorize diagnostics output.
|
/// Whether or not to colorize diagnostics output.
|
||||||
bool m_coloredOutput = true;
|
bool m_coloredOutput = true;
|
||||||
|
/// Whether or not to output error IDs.
|
||||||
|
bool m_withErrorIds = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -121,6 +121,7 @@ function test_solc_behaviour()
|
|||||||
rm "$stdout_path.bak"
|
rm "$stdout_path.bak"
|
||||||
else
|
else
|
||||||
sed -i.bak -e '/^Warning: This is a pre-release compiler version, please do not use it in production./d' "$stderr_path"
|
sed -i.bak -e '/^Warning: This is a pre-release compiler version, please do not use it in production./d' "$stderr_path"
|
||||||
|
sed -i.bak -e '/^Warning (3805): This is a pre-release compiler version, please do not use it in production./d' "$stderr_path"
|
||||||
sed -i.bak -e 's/\(^[ ]*auxdata: \)0x[0-9a-f]*$/\1AUXDATA REMOVED/' "$stdout_path"
|
sed -i.bak -e 's/\(^[ ]*auxdata: \)0x[0-9a-f]*$/\1AUXDATA REMOVED/' "$stdout_path"
|
||||||
sed -i.bak -e 's/ Consider adding "pragma .*$//' "$stderr_path"
|
sed -i.bak -e 's/ Consider adding "pragma .*$//' "$stderr_path"
|
||||||
# Remove trailing empty lines. Needs a line break to make OSX sed happy.
|
# Remove trailing empty lines. Needs a line break to make OSX sed happy.
|
||||||
|
1
test/cmdlineTests/error_codes/args
Normal file
1
test/cmdlineTests/error_codes/args
Normal file
@ -0,0 +1 @@
|
|||||||
|
--error-codes
|
26
test/cmdlineTests/error_codes/err
Normal file
26
test/cmdlineTests/error_codes/err
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
Error (4937): No visibility specified. Did you intend to add "public"?
|
||||||
|
--> error_codes/input.sol:4:5:
|
||||||
|
|
|
||||||
|
4 | function f() {
|
||||||
|
| ^ (Relevant source part starts here and spans across multiple lines).
|
||||||
|
|
||||||
|
Warning (3420): Source file does not specify required compiler version!
|
||||||
|
--> error_codes/input.sol
|
||||||
|
|
||||||
|
Error (4247): Expression has to be an lvalue.
|
||||||
|
--> error_codes/input.sol:5:9:
|
||||||
|
|
|
||||||
|
5 | 2=0;
|
||||||
|
| ^
|
||||||
|
|
||||||
|
Error (7407): Type int_const 0 is not implicitly convertible to expected type int_const 2.
|
||||||
|
--> error_codes/input.sol:5:11:
|
||||||
|
|
|
||||||
|
5 | 2=0;
|
||||||
|
| ^
|
||||||
|
|
||||||
|
Error (2614): Indexed expression has to be a type, mapping or array (is literal_string "")
|
||||||
|
--> error_codes/input.sol:6:9:
|
||||||
|
|
|
||||||
|
6 | ""[2];
|
||||||
|
| ^^
|
1
test/cmdlineTests/error_codes/exit
Normal file
1
test/cmdlineTests/error_codes/exit
Normal file
@ -0,0 +1 @@
|
|||||||
|
1
|
8
test/cmdlineTests/error_codes/input.sol
Normal file
8
test/cmdlineTests/error_codes/input.sol
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
function f() {
|
||||||
|
2=0;
|
||||||
|
""[2];
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
{"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}},"b.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version!
|
{"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}},"b.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version!
|
||||||
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version!
|
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","errorCode":"3420","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version!
|
||||||
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure
|
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","errorCode":"2018","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure
|
||||||
contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }
|
contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }
|
||||||
^------------------------------------------^
|
^------------------------------------------^
|
||||||
","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}}
|
","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{"contracts":{"a.sol":{"A2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version!
|
{"contracts":{"a.sol":{"A2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version!
|
||||||
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version!
|
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","errorCode":"3420","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version!
|
||||||
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure
|
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","errorCode":"2018","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure
|
||||||
contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }
|
contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }
|
||||||
^------------------------------------------^
|
^------------------------------------------^
|
||||||
","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}}
|
","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version!
|
{"errors":[{"component":"general","errorCode":"3420","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version!
|
||||||
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version!
|
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","errorCode":"3420","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version!
|
||||||
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure
|
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","errorCode":"2018","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure
|
||||||
contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }
|
contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }
|
||||||
^------------------------------------------^
|
^------------------------------------------^
|
||||||
","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}}
|
","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}},"A2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}},"b.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}},"B2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version!
|
{"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}},"A2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}},"b.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}},"B2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version!
|
||||||
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version!
|
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","errorCode":"3420","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version!
|
||||||
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure
|
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","errorCode":"2018","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure
|
||||||
contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }
|
contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }
|
||||||
^------------------------------------------^
|
^------------------------------------------^
|
||||||
","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}}
|
","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}}
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
{"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version!
|
{"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version!
|
||||||
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}}
|
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{"contracts":{"b.sol":{"B2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version!
|
{"contracts":{"b.sol":{"B2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version!
|
||||||
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure
|
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","errorCode":"2018","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure
|
||||||
contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }
|
contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }
|
||||||
^------------------------------------------^
|
^------------------------------------------^
|
||||||
","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}}
|
","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}}
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
{"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}},"A2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version!
|
{"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}},"A2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version!
|
||||||
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}}
|
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{"errors":[{"component":"general","formattedMessage":"A:2:58: ParserError: Expected type name
|
{"errors":[{"component":"general","errorCode":"3546","formattedMessage":"A:2:58: ParserError: Expected type name
|
||||||
pragma solidity >=0.0; contract Errort6 { using foo for ; /* missing type name */ }
|
pragma solidity >=0.0; contract Errort6 { using foo for ; /* missing type name */ }
|
||||||
^
|
^
|
||||||
","message":"Expected type name","severity":"error","sourceLocation":{"end":94,"file":"A","start":93},"type":"ParserError"},{"component":"general","formattedMessage":"A:2:84: Warning: Recovered in ContractDefinition at '}'.
|
","message":"Expected type name","severity":"error","sourceLocation":{"end":94,"file":"A","start":93},"type":"ParserError"},{"component":"general","errorCode":"3796","formattedMessage":"A:2:84: Warning: Recovered in ContractDefinition at '}'.
|
||||||
pragma solidity >=0.0; contract Errort6 { using foo for ; /* missing type name */ }
|
pragma solidity >=0.0; contract Errort6 { using foo for ; /* missing type name */ }
|
||||||
^
|
^
|
||||||
","message":"Recovered in ContractDefinition at '}'.","severity":"warning","sourceLocation":{"end":120,"file":"A","start":119},"type":"Warning"}],"sources":{"A":{"ast":{"absolutePath":"A","exportedSymbols":{"Errort6":[3]},"id":4,"license":"GPL-3.0","nodeType":"SourceUnit","nodes":[{"id":1,"literals":["solidity",">=","0.0"],"nodeType":"PragmaDirective","src":"36:22:0"},{"abstract":false,"baseContracts":[],"contractDependencies":[],"contractKind":"contract","documentation":null,"fullyImplemented":true,"id":3,"linearizedBaseContracts":[3],"name":"Errort6","nodeType":"ContractDefinition","nodes":[],"scope":4,"src":"59:35:0"}],"src":"36:84:0"},"id":0}}}
|
","message":"Recovered in ContractDefinition at '}'.","severity":"warning","sourceLocation":{"end":120,"file":"A","start":119},"type":"Warning"}],"sources":{"A":{"ast":{"absolutePath":"A","exportedSymbols":{"Errort6":[3]},"id":4,"license":"GPL-3.0","nodeType":"SourceUnit","nodes":[{"id":1,"literals":["solidity",">=","0.0"],"nodeType":"PragmaDirective","src":"36:22:0"},{"abstract":false,"baseContracts":[],"contractDependencies":[],"contractKind":"contract","documentation":null,"fullyImplemented":true,"id":3,"linearizedBaseContracts":[3],"name":"Errort6","nodeType":"ContractDefinition","nodes":[],"scope":4,"src":"59:35:0"}],"src":"36:84:0"},"id":0}}}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{"errors":[{"component":"general","formattedMessage":":2:24: DeclarationError: Declaration \"A\" not found in \"\" (referenced as \".\").
|
{"errors":[{"component":"general","errorCode":"2904","formattedMessage":":2:24: DeclarationError: Declaration \"A\" not found in \"\" (referenced as \".\").
|
||||||
pragma solidity >=0.0; import {A} from \".\";
|
pragma solidity >=0.0; import {A} from \".\";
|
||||||
^------------------^
|
^------------------^
|
||||||
","message":"Declaration \"A\" not found in \"\" (referenced as \".\").","severity":"error","type":"DeclarationError"}],"sources":{}}
|
","message":"Declaration \"A\" not found in \"\" (referenced as \".\").","severity":"error","type":"DeclarationError"}],"sources":{}}
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
{"contracts":{"a.sol":{"A":{"evm":{"deployedBytecode":{"immutableReferences":{"3":[{"length":32,"start":77}]},"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"36:96:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;74:56;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;108:7;126:1;119:8;;74:56;:::o"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version!
|
{"contracts":{"a.sol":{"A":{"evm":{"deployedBytecode":{"immutableReferences":{"3":[{"length":32,"start":77}]},"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"36:96:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;74:56;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;108:7;126:1;119:8;;74:56;:::o"}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version!
|
||||||
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"}],"sources":{"a.sol":{"id":0}}}
|
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"}],"sources":{"a.sol":{"id":0}}}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{"errors":[{"component":"general","formattedMessage":"A:2:112: DeclarationError: Base constructor arguments given twice.
|
{"errors":[{"component":"general","errorCode":"3364","formattedMessage":"A:2:112: DeclarationError: Base constructor arguments given twice.
|
||||||
pragma solidity >=0.0; contract A { constructor(uint) public {} } contract B is A(2) { } contract C is A(3) {} contract D is B, C {}
|
pragma solidity >=0.0; contract A { constructor(uint) public {} } contract B is A(2) { } contract C is A(3) {} contract D is B, C {}
|
||||||
^-------------------^
|
^-------------------^
|
||||||
A:2:81: First constructor call is here:
|
A:2:81: First constructor call is here:
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":3,"contract":"fileA:A","label":"s1","offset":0,"slot":"0","type":"t_bytes_storage"},{"astId":5,"contract":"fileA:A","label":"s2","offset":0,"slot":"1","type":"t_bytes_storage"}],"types":{"t_bytes_storage":{"encoding":"bytes","label":"bytes","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version!
|
{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":3,"contract":"fileA:A","label":"s1","offset":0,"slot":"0","type":"t_bytes_storage"},{"astId":5,"contract":"fileA:A","label":"s2","offset":0,"slot":"1","type":"t_bytes_storage"}],"types":{"t_bytes_storage":{"encoding":"bytes","label":"bytes","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version!
|
||||||
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}}
|
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}}
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":3,"contract":"fileA:A","label":"array1","offset":0,"slot":"0","type":"t_array(t_uint256)dyn_storage"},{"astId":6,"contract":"fileA:A","label":"array2","offset":0,"slot":"1","type":"t_array(t_bool)dyn_storage"}],"types":{"t_array(t_bool)dyn_storage":{"base":"t_bool","encoding":"dynamic_array","label":"bool[]","numberOfBytes":"32"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_bool":{"encoding":"inplace","label":"bool","numberOfBytes":"1"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version!
|
{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":3,"contract":"fileA:A","label":"array1","offset":0,"slot":"0","type":"t_array(t_uint256)dyn_storage"},{"astId":6,"contract":"fileA:A","label":"array2","offset":0,"slot":"1","type":"t_array(t_bool)dyn_storage"}],"types":{"t_array(t_bool)dyn_storage":{"base":"t_bool","encoding":"dynamic_array","label":"bool[]","numberOfBytes":"32"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_bool":{"encoding":"inplace","label":"bool","numberOfBytes":"1"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version!
|
||||||
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}}
|
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}}
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":14,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":16,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":18,"contract":"fileA:A","label":"s","offset":0,"slot":"2","type":"t_struct(S)12_storage"},{"astId":20,"contract":"fileA:A","label":"addr","offset":0,"slot":"6","type":"t_address"},{"astId":26,"contract":"fileA:A","label":"map","offset":0,"slot":"7","type":"t_mapping(t_uint256,t_mapping(t_address,t_bool))"},{"astId":29,"contract":"fileA:A","label":"array","offset":0,"slot":"8","type":"t_array(t_uint256)dyn_storage"},{"astId":31,"contract":"fileA:A","label":"s1","offset":0,"slot":"9","type":"t_string_storage"},{"astId":33,"contract":"fileA:A","label":"b1","offset":0,"slot":"10","type":"t_bytes_storage"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_bool":{"encoding":"inplace","label":"bool","numberOfBytes":"1"},"t_bytes_storage":{"encoding":"bytes","label":"bytes","numberOfBytes":"32"},"t_mapping(t_address,t_bool)":{"encoding":"mapping","key":"t_address","label":"mapping(address => bool)","numberOfBytes":"32","value":"t_bool"},"t_mapping(t_uint256,t_mapping(t_address,t_bool))":{"encoding":"mapping","key":"t_uint256","label":"mapping(uint256 => mapping(address => bool))","numberOfBytes":"32","value":"t_mapping(t_address,t_bool)"},"t_string_storage":{"encoding":"bytes","label":"string","numberOfBytes":"32"},"t_struct(S)12_storage":{"encoding":"inplace","label":"struct A.S","members":[{"astId":2,"contract":"fileA:A","label":"a","offset":0,"slot":"0","type":"t_uint128"},{"astId":4,"contract":"fileA:A","label":"b","offset":16,"slot":"0","type":"t_uint128"},{"astId":8,"contract":"fileA:A","label":"staticArray","offset":0,"slot":"1","type":"t_array(t_uint256)2_storage"},{"astId":11,"contract":"fileA:A","label":"dynArray","offset":0,"slot":"3","type":"t_array(t_uint256)dyn_storage"}],"numberOfBytes":"128"},"t_uint128":{"encoding":"inplace","label":"uint128","numberOfBytes":"16"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version!
|
{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":14,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":16,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":18,"contract":"fileA:A","label":"s","offset":0,"slot":"2","type":"t_struct(S)12_storage"},{"astId":20,"contract":"fileA:A","label":"addr","offset":0,"slot":"6","type":"t_address"},{"astId":26,"contract":"fileA:A","label":"map","offset":0,"slot":"7","type":"t_mapping(t_uint256,t_mapping(t_address,t_bool))"},{"astId":29,"contract":"fileA:A","label":"array","offset":0,"slot":"8","type":"t_array(t_uint256)dyn_storage"},{"astId":31,"contract":"fileA:A","label":"s1","offset":0,"slot":"9","type":"t_string_storage"},{"astId":33,"contract":"fileA:A","label":"b1","offset":0,"slot":"10","type":"t_bytes_storage"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_bool":{"encoding":"inplace","label":"bool","numberOfBytes":"1"},"t_bytes_storage":{"encoding":"bytes","label":"bytes","numberOfBytes":"32"},"t_mapping(t_address,t_bool)":{"encoding":"mapping","key":"t_address","label":"mapping(address => bool)","numberOfBytes":"32","value":"t_bool"},"t_mapping(t_uint256,t_mapping(t_address,t_bool))":{"encoding":"mapping","key":"t_uint256","label":"mapping(uint256 => mapping(address => bool))","numberOfBytes":"32","value":"t_mapping(t_address,t_bool)"},"t_string_storage":{"encoding":"bytes","label":"string","numberOfBytes":"32"},"t_struct(S)12_storage":{"encoding":"inplace","label":"struct A.S","members":[{"astId":2,"contract":"fileA:A","label":"a","offset":0,"slot":"0","type":"t_uint128"},{"astId":4,"contract":"fileA:A","label":"b","offset":16,"slot":"0","type":"t_uint128"},{"astId":8,"contract":"fileA:A","label":"staticArray","offset":0,"slot":"1","type":"t_array(t_uint256)2_storage"},{"astId":11,"contract":"fileA:A","label":"dynArray","offset":0,"slot":"3","type":"t_array(t_uint256)dyn_storage"}],"numberOfBytes":"128"},"t_uint128":{"encoding":"inplace","label":"uint128","numberOfBytes":"16"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version!
|
||||||
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}}
|
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}}
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":2,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":4,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":10,"contract":"fileA:A","label":"map","offset":0,"slot":"2","type":"t_mapping(t_uint256,t_mapping(t_address,t_bool))"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_bool":{"encoding":"inplace","label":"bool","numberOfBytes":"1"},"t_mapping(t_address,t_bool)":{"encoding":"mapping","key":"t_address","label":"mapping(address => bool)","numberOfBytes":"32","value":"t_bool"},"t_mapping(t_uint256,t_mapping(t_address,t_bool))":{"encoding":"mapping","key":"t_uint256","label":"mapping(uint256 => mapping(address => bool))","numberOfBytes":"32","value":"t_mapping(t_address,t_bool)"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version!
|
{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":2,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":4,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":10,"contract":"fileA:A","label":"map","offset":0,"slot":"2","type":"t_mapping(t_uint256,t_mapping(t_address,t_bool))"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_bool":{"encoding":"inplace","label":"bool","numberOfBytes":"1"},"t_mapping(t_address,t_bool)":{"encoding":"mapping","key":"t_address","label":"mapping(address => bool)","numberOfBytes":"32","value":"t_bool"},"t_mapping(t_uint256,t_mapping(t_address,t_bool))":{"encoding":"mapping","key":"t_uint256","label":"mapping(uint256 => mapping(address => bool))","numberOfBytes":"32","value":"t_mapping(t_address,t_bool)"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version!
|
||||||
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}}
|
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}}
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[],"types":null}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version!
|
{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[],"types":null}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version!
|
||||||
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}}
|
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}}
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[],"types":null}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version!
|
{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[],"types":null}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version!
|
||||||
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0},"fileB":{"id":1}}}
|
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0},"fileB":{"id":1}}}
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":3,"contract":"fileA:A","label":"s1","offset":0,"slot":"0","type":"t_string_storage"},{"astId":5,"contract":"fileA:A","label":"s2","offset":0,"slot":"1","type":"t_string_storage"}],"types":{"t_string_storage":{"encoding":"bytes","label":"string","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version!
|
{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":3,"contract":"fileA:A","label":"s1","offset":0,"slot":"0","type":"t_string_storage"},{"astId":5,"contract":"fileA:A","label":"s2","offset":0,"slot":"1","type":"t_string_storage"}],"types":{"t_string_storage":{"encoding":"bytes","label":"string","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version!
|
||||||
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}}
|
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}}
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":14,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":16,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":18,"contract":"fileA:A","label":"s","offset":0,"slot":"2","type":"t_struct(S)12_storage"},{"astId":20,"contract":"fileA:A","label":"addr","offset":0,"slot":"7","type":"t_address"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_struct(S)12_storage":{"encoding":"inplace","label":"struct A.S","members":[{"astId":2,"contract":"fileA:A","label":"a","offset":0,"slot":"0","type":"t_uint256"},{"astId":4,"contract":"fileA:A","label":"b","offset":0,"slot":"1","type":"t_uint256"},{"astId":8,"contract":"fileA:A","label":"staticArray","offset":0,"slot":"2","type":"t_array(t_uint256)2_storage"},{"astId":11,"contract":"fileA:A","label":"dynArray","offset":0,"slot":"4","type":"t_array(t_uint256)dyn_storage"}],"numberOfBytes":"160"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version!
|
{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":14,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":16,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":18,"contract":"fileA:A","label":"s","offset":0,"slot":"2","type":"t_struct(S)12_storage"},{"astId":20,"contract":"fileA:A","label":"addr","offset":0,"slot":"7","type":"t_address"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_struct(S)12_storage":{"encoding":"inplace","label":"struct A.S","members":[{"astId":2,"contract":"fileA:A","label":"a","offset":0,"slot":"0","type":"t_uint256"},{"astId":4,"contract":"fileA:A","label":"b","offset":0,"slot":"1","type":"t_uint256"},{"astId":8,"contract":"fileA:A","label":"staticArray","offset":0,"slot":"2","type":"t_array(t_uint256)2_storage"},{"astId":11,"contract":"fileA:A","label":"dynArray","offset":0,"slot":"4","type":"t_array(t_uint256)dyn_storage"}],"numberOfBytes":"160"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version!
|
||||||
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}}
|
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}}
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":14,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":16,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":18,"contract":"fileA:A","label":"s","offset":0,"slot":"2","type":"t_struct(S)12_storage"},{"astId":20,"contract":"fileA:A","label":"addr","offset":0,"slot":"6","type":"t_address"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_struct(S)12_storage":{"encoding":"inplace","label":"struct A.S","members":[{"astId":2,"contract":"fileA:A","label":"a","offset":0,"slot":"0","type":"t_uint128"},{"astId":4,"contract":"fileA:A","label":"b","offset":16,"slot":"0","type":"t_uint128"},{"astId":8,"contract":"fileA:A","label":"staticArray","offset":0,"slot":"1","type":"t_array(t_uint256)2_storage"},{"astId":11,"contract":"fileA:A","label":"dynArray","offset":0,"slot":"3","type":"t_array(t_uint256)dyn_storage"}],"numberOfBytes":"128"},"t_uint128":{"encoding":"inplace","label":"uint128","numberOfBytes":"16"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version!
|
{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":14,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":16,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":18,"contract":"fileA:A","label":"s","offset":0,"slot":"2","type":"t_struct(S)12_storage"},{"astId":20,"contract":"fileA:A","label":"addr","offset":0,"slot":"6","type":"t_address"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_struct(S)12_storage":{"encoding":"inplace","label":"struct A.S","members":[{"astId":2,"contract":"fileA:A","label":"a","offset":0,"slot":"0","type":"t_uint128"},{"astId":4,"contract":"fileA:A","label":"b","offset":16,"slot":"0","type":"t_uint128"},{"astId":8,"contract":"fileA:A","label":"staticArray","offset":0,"slot":"1","type":"t_array(t_uint256)2_storage"},{"astId":11,"contract":"fileA:A","label":"dynArray","offset":0,"slot":"3","type":"t_array(t_uint256)dyn_storage"}],"numberOfBytes":"128"},"t_uint128":{"encoding":"inplace","label":"uint128","numberOfBytes":"16"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version!
|
||||||
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}}
|
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}}
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":2,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":4,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":6,"contract":"fileA:A","label":"addr","offset":0,"slot":"2","type":"t_address"},{"astId":10,"contract":"fileA:A","label":"array","offset":0,"slot":"3","type":"t_array(t_uint256)2_storage"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version!
|
{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":2,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":4,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":6,"contract":"fileA:A","label":"addr","offset":0,"slot":"2","type":"t_address"},{"astId":10,"contract":"fileA:A","label":"array","offset":0,"slot":"3","type":"t_array(t_uint256)2_storage"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version!
|
||||||
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}}
|
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user