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:
|
||||
- nvm install 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:
|
||||
- SOLC_EMSCRIPTEN=On
|
||||
- SOLC_INSTALL_DEPS_TRAVIS=Off
|
||||
|
22
Changelog.md
22
Changelog.md
@ -20,18 +20,38 @@ Bugfixes:
|
||||
* NatSpec: Constructors and functions have consistent userdoc output.
|
||||
|
||||
|
||||
### 0.6.10 (unreleased)
|
||||
### 0.6.11 (unreleased)
|
||||
|
||||
|
||||
Language 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.
|
||||
|
||||
|
||||
Bugfixes:
|
||||
* SMTChecker: Fix internal error when encoding tuples of tuples.
|
||||
* 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)
|
||||
|
@ -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",
|
||||
"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"
|
||||
},
|
||||
"0.6.10": {
|
||||
"bugs": [],
|
||||
"released": "2020-06-11"
|
||||
},
|
||||
"0.6.2": {
|
||||
"bugs": [
|
||||
"MissingEscapingInFormatting",
|
||||
@ -1165,7 +1169,9 @@
|
||||
"released": "2020-05-14"
|
||||
},
|
||||
"0.6.9": {
|
||||
"bugs": [],
|
||||
"bugs": [
|
||||
"UsingForCalldata"
|
||||
],
|
||||
"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
|
||||
/// after doing basic validation on the address argument.
|
||||
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)"))) {
|
||||
address owner = abi.decode(_payload[4:], (address));
|
||||
require(owner != address(0), "Address of owner cannot be zero.");
|
||||
|
@ -374,8 +374,10 @@ Output Description
|
||||
"component": "general",
|
||||
// Mandatory ("error" or "warning")
|
||||
"severity": "error",
|
||||
// Optional: unique code for the cause of the error
|
||||
"errorCode": "3141",
|
||||
// Mandatory
|
||||
"message": "Invalid keyword"
|
||||
"message": "Invalid keyword",
|
||||
// Optional: the message formatted with source location
|
||||
"formattedMessage": "sourceFile.sol:100: Invalid keyword"
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ void AssemblyItem::setPushTagSubIdAndTag(size_t _subId, size_t _tag)
|
||||
setData(data);
|
||||
}
|
||||
|
||||
unsigned AssemblyItem::bytesRequired(unsigned _addressLength) const
|
||||
size_t AssemblyItem::bytesRequired(size_t _addressLength) const
|
||||
{
|
||||
switch (m_type)
|
||||
{
|
||||
@ -69,7 +69,7 @@ unsigned AssemblyItem::bytesRequired(unsigned _addressLength) const
|
||||
case PushString:
|
||||
return 1 + 32;
|
||||
case Push:
|
||||
return 1 + max<unsigned>(1, util::bytesRequired(data()));
|
||||
return 1 + max<size_t>(1, util::bytesRequired(data()));
|
||||
case PushSubSize:
|
||||
case PushProgramSize:
|
||||
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
|
||||
/// 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 returnValues() const;
|
||||
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 diff_type = string::difference_type;
|
||||
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;
|
||||
if (searchPosition == 0)
|
||||
lineStart = 0;
|
||||
|
@ -179,7 +179,7 @@ bool Scanner::scanHexByte(char& o_scannedByte)
|
||||
rollback(i);
|
||||
return false;
|
||||
}
|
||||
x = x * 16 + d;
|
||||
x = static_cast<char>(x * 16 + d);
|
||||
advance();
|
||||
}
|
||||
o_scannedByte = x;
|
||||
@ -197,7 +197,7 @@ std::optional<unsigned> Scanner::scanUnicode()
|
||||
rollback(i);
|
||||
return {};
|
||||
}
|
||||
x = x * 16 + static_cast<size_t>(d);
|
||||
x = x * 16 + static_cast<unsigned>(d);
|
||||
advance();
|
||||
}
|
||||
return x;
|
||||
|
@ -38,7 +38,15 @@ SourceReferenceExtractor::Message SourceReferenceExtractor::extract(util::Except
|
||||
for (auto const& info: secondaryLocation->infos)
|
||||
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)
|
||||
|
@ -16,16 +16,14 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <liblangutil/Exceptions.h>
|
||||
|
||||
#include <iosfwd>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
namespace solidity::util
|
||||
{
|
||||
struct Exception;
|
||||
}
|
||||
|
||||
namespace solidity::langutil
|
||||
{
|
||||
|
||||
@ -58,8 +56,6 @@ struct SourceReference
|
||||
}
|
||||
};
|
||||
|
||||
struct SourceLocation;
|
||||
|
||||
namespace SourceReferenceExtractor
|
||||
{
|
||||
struct Message
|
||||
@ -67,9 +63,11 @@ namespace SourceReferenceExtractor
|
||||
SourceReference primary;
|
||||
std::string category; // "Error", "Warning", ...
|
||||
std::vector<SourceReference> secondary;
|
||||
std::optional<ErrorId> errorId;
|
||||
};
|
||||
|
||||
Message extract(util::Exception const& _exception, std::string _category);
|
||||
Message extract(Error const& _error);
|
||||
SourceReference extract(SourceLocation const* _location, std::string message = "");
|
||||
}
|
||||
|
||||
|
@ -80,10 +80,7 @@ void SourceReferenceFormatter::printExceptionInformation(util::Exception const&
|
||||
|
||||
void SourceReferenceFormatter::printErrorInformation(Error const& _error)
|
||||
{
|
||||
printExceptionInformation(
|
||||
_error,
|
||||
(_error.type() == Error::Type::Warning) ? "Warning" : "Error"
|
||||
);
|
||||
printExceptionInformation(SourceReferenceExtractor::extract(_error));
|
||||
}
|
||||
|
||||
void SourceReferenceFormatter::printExceptionInformation(SourceReferenceExtractor::Message const& _msg)
|
||||
|
@ -151,6 +151,8 @@ void SourceReferenceFormatterHuman::printExceptionInformation(SourceReferenceExt
|
||||
{
|
||||
// exception header line
|
||||
errorColored() << _msg.category;
|
||||
if (m_withErrorIds && _msg.errorId.has_value())
|
||||
errorColored() << " (" << _msg.errorId.value().error << ")";
|
||||
messageColored() << ": " << _msg.primary.message << '\n';
|
||||
|
||||
printSourceLocation(_msg.primary);
|
||||
|
@ -29,22 +29,14 @@
|
||||
#include <sstream>
|
||||
#include <functional>
|
||||
|
||||
namespace solidity::util
|
||||
{
|
||||
struct Exception; // forward
|
||||
}
|
||||
|
||||
namespace solidity::langutil
|
||||
{
|
||||
|
||||
struct SourceLocation;
|
||||
struct SourceReference;
|
||||
|
||||
class SourceReferenceFormatterHuman: public SourceReferenceFormatter
|
||||
{
|
||||
public:
|
||||
SourceReferenceFormatterHuman(std::ostream& _stream, bool colored):
|
||||
SourceReferenceFormatter{_stream}, m_colored{colored}
|
||||
SourceReferenceFormatterHuman(std::ostream& _stream, bool _colored, bool _withErrorIds):
|
||||
SourceReferenceFormatter{_stream}, m_colored{_colored}, m_withErrorIds(_withErrorIds)
|
||||
{}
|
||||
|
||||
void printSourceLocation(SourceReference const& _ref) override;
|
||||
@ -54,12 +46,13 @@ public:
|
||||
static std::string formatExceptionInformation(
|
||||
util::Exception const& _exception,
|
||||
std::string const& _name,
|
||||
bool colored = false
|
||||
bool _colored = false,
|
||||
bool _withErrorIds = false
|
||||
)
|
||||
{
|
||||
std::ostringstream errorOutput;
|
||||
|
||||
SourceReferenceFormatterHuman formatter(errorOutput, colored);
|
||||
SourceReferenceFormatterHuman formatter(errorOutput, _colored, _withErrorIds);
|
||||
formatter.printExceptionInformation(_exception, _name);
|
||||
return errorOutput.str();
|
||||
}
|
||||
@ -75,6 +68,7 @@ private:
|
||||
|
||||
private:
|
||||
bool m_colored;
|
||||
bool m_withErrorIds;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ struct OverrideGraph
|
||||
std::map<OverrideProxy, int> nodes;
|
||||
std::map<int, OverrideProxy> nodeInv;
|
||||
std::map<int, std::set<int>> edges;
|
||||
int numNodes = 2;
|
||||
size_t numNodes = 2;
|
||||
void addEdge(int _a, int _b)
|
||||
{
|
||||
edges[_a].insert(_b);
|
||||
@ -82,7 +82,7 @@ private:
|
||||
auto it = nodes.find(_function);
|
||||
if (it != nodes.end())
|
||||
return it->second;
|
||||
int currentNode = numNodes++;
|
||||
int currentNode = static_cast<int>(numNodes++);
|
||||
nodes[_function] = currentNode;
|
||||
nodeInv[currentNode] = _function;
|
||||
if (_function.overrides())
|
||||
@ -116,21 +116,24 @@ private:
|
||||
std::vector<int> m_parent = std::vector<int>(m_graph.numNodes, -1);
|
||||
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_depths.at(_u) = m_low.at(_u) = _depth;
|
||||
for (int v: m_graph.edges.at(_u))
|
||||
if (!m_visited.at(v))
|
||||
m_depths.at(_u) = m_low.at(_u) = static_cast<int>(_depth);
|
||||
for (int const v: m_graph.edges.at(static_cast<int>(_u)))
|
||||
{
|
||||
m_parent[v] = _u;
|
||||
run(v, _depth + 1);
|
||||
if (m_low[v] >= m_depths[_u] && m_parent[_u] != -1)
|
||||
m_cutVertices.insert(m_graph.nodeInv.at(_u));
|
||||
m_low[_u] = min(m_low[_u], m_low[v]);
|
||||
auto const vInd = static_cast<size_t>(v);
|
||||
if (!m_visited.at(vInd))
|
||||
{
|
||||
m_parent[vInd] = static_cast<int>(_u);
|
||||
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])
|
||||
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
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -668,7 +668,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
{
|
||||
auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier);
|
||||
if (ref == _inlineAssembly.annotation().externalReferences.end())
|
||||
return size_t(-1);
|
||||
return numeric_limits<size_t>::max();
|
||||
Declaration const* declaration = ref->second.declaration;
|
||||
solAssert(!!declaration, "");
|
||||
bool requiresStorage = ref->second.isSlot || ref->second.isOffset;
|
||||
@ -678,7 +678,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
if (var->immutable())
|
||||
{
|
||||
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())
|
||||
{
|
||||
@ -687,17 +687,17 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
if (var && !var->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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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()))
|
||||
{
|
||||
@ -725,19 +725,19 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
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.");
|
||||
return size_t(-1);
|
||||
return numeric_limits<size_t>::max();
|
||||
}
|
||||
else if (_context == yul::IdentifierContext::LValue)
|
||||
{
|
||||
if (var->isStateVariable())
|
||||
{
|
||||
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)
|
||||
{
|
||||
m_errorReporter.typeError(9739_error, _identifier.location, "Only _slot can be assigned to.");
|
||||
return size_t(-1);
|
||||
return numeric_limits<size_t>::max();
|
||||
}
|
||||
else
|
||||
solAssert(ref->second.isSlot, "");
|
||||
@ -746,12 +746,12 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
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.");
|
||||
return size_t(-1);
|
||||
return numeric_limits<size_t>::max();
|
||||
}
|
||||
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.");
|
||||
return size_t(-1);
|
||||
return numeric_limits<size_t>::max();
|
||||
}
|
||||
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.");
|
||||
else
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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.");
|
||||
return size_t(-1);
|
||||
return numeric_limits<size_t>::max();
|
||||
}
|
||||
|
||||
if (_context == yul::IdentifierContext::RValue)
|
||||
@ -782,7 +782,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
if (dynamic_cast<FunctionDefinition const*>(declaration))
|
||||
{
|
||||
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))
|
||||
{
|
||||
@ -792,11 +792,11 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
if (!contract->isLibrary())
|
||||
{
|
||||
m_errorReporter.typeError(4977_error, _identifier.location, "Expected a library.");
|
||||
return size_t(-1);
|
||||
return numeric_limits<size_t>::max();
|
||||
}
|
||||
}
|
||||
else
|
||||
return size_t(-1);
|
||||
return numeric_limits<size_t>::max();
|
||||
}
|
||||
ref->second.valueSize = 1;
|
||||
return size_t(1);
|
||||
|
@ -38,7 +38,7 @@ using namespace solidity;
|
||||
using namespace solidity::frontend;
|
||||
|
||||
ASTNode::ASTNode(int64_t _id, SourceLocation _location):
|
||||
m_id(_id),
|
||||
m_id(static_cast<size_t>(_id)),
|
||||
m_location(std::move(_location))
|
||||
{
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ public:
|
||||
virtual ~ASTNode() {}
|
||||
|
||||
/// @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(ASTConstVisitor& _visitor) const = 0;
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity::langutil;
|
||||
@ -134,7 +135,7 @@ size_t ASTJsonConverter::sourceIndexFromLocation(SourceLocation const& _location
|
||||
if (_location.source && m_sourceIndices.count(_location.source->name()))
|
||||
return m_sourceIndices.at(_location.source->name());
|
||||
else
|
||||
return size_t(-1);
|
||||
return numeric_limits<size_t>::max();
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
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>
|
||||
|
@ -113,14 +113,22 @@ public:
|
||||
/// @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.
|
||||
/// 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))
|
||||
return withLocation(refType, _location, false);
|
||||
return withLocation(refType, _location, _isPointer);
|
||||
|
||||
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.
|
||||
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 (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,
|
||||
ufd->typeName()->annotation().type
|
||||
))
|
||||
ufd->typeName()->annotation().type,
|
||||
true
|
||||
)
|
||||
)
|
||||
continue;
|
||||
auto const& library = dynamic_cast<ContractDefinition const&>(
|
||||
*ufd->libraryName().annotation().referencedDeclaration
|
||||
@ -371,7 +379,8 @@ MemberList::MemberMap Type::boundFunctions(Type const& _type, ContractDefinition
|
||||
seenFunctions.insert(function);
|
||||
if (function->parameters().empty())
|
||||
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()))
|
||||
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 /= boost::multiprecision::pow(
|
||||
bigint(10),
|
||||
distance(radixPoint + 1, _value.end())
|
||||
static_cast<size_t>(distance(radixPoint + 1, _value.end()))
|
||||
);
|
||||
numerator = bigint(string(_value.begin(), radixPoint));
|
||||
value = numerator + denominator;
|
||||
@ -1093,7 +1102,7 @@ TypeResult RationalNumberType::binaryOperatorResult(Token _operator, Type const*
|
||||
if (_base == 1)
|
||||
return 1;
|
||||
else if (_base == -1)
|
||||
return 1 - 2 * int(_exponent & 1);
|
||||
return 1 - 2 * static_cast<int>(_exponent & 1);
|
||||
else
|
||||
return boost::multiprecision::pow(_base, _exponent);
|
||||
};
|
||||
@ -1199,7 +1208,7 @@ string RationalNumberType::bigintToReadableString(bigint const& _num)
|
||||
string str = _num.str();
|
||||
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);
|
||||
}
|
||||
return str;
|
||||
@ -1229,7 +1238,7 @@ u256 RationalNumberType::literalValue(Literal const*) const
|
||||
{
|
||||
auto fixed = fixedPointType();
|
||||
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();
|
||||
}
|
||||
|
||||
@ -1319,7 +1328,7 @@ StringLiteralType::StringLiteralType(string _value):
|
||||
BoolResult StringLiteralType::isImplicitlyConvertibleTo(Type const& _convertTo) const
|
||||
{
|
||||
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))
|
||||
return
|
||||
arrayType->isByteArray() &&
|
||||
@ -2485,6 +2494,21 @@ set<string> StructType::membersMissingInMemory() const
|
||||
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
|
||||
{
|
||||
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(), "");
|
||||
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;
|
||||
for (auto const& t: m_parameterTypes)
|
||||
{
|
||||
auto refType = dynamic_cast<ReferenceType const*>(t);
|
||||
if (refType && refType->location() == DataLocation::CallData)
|
||||
parameterTypes.push_back(TypeProvider::withLocation(refType, DataLocation::Memory, true));
|
||||
if (TypeProvider::isReferenceWithLocation(t, DataLocation::CallData))
|
||||
parameterTypes.push_back(
|
||||
TypeProvider::withLocationIfReference(DataLocation::Memory, t, true)
|
||||
);
|
||||
else
|
||||
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;
|
||||
if (_inLibrary)
|
||||
{
|
||||
solAssert(!!m_declaration, "Declaration has to be available.");
|
||||
if (!m_declaration->isPublic())
|
||||
kind = Kind::Internal; // will be inlined
|
||||
else
|
||||
solAssert(m_declaration->isPublic(), "");
|
||||
kind = Kind::DelegateCall;
|
||||
}
|
||||
|
||||
return TypeProvider::function(
|
||||
parameterTypes,
|
||||
m_returnParameterTypes,
|
||||
returnParameterTypes,
|
||||
m_parameterNames,
|
||||
m_returnParameterNames,
|
||||
kind,
|
||||
@ -3503,7 +3554,7 @@ FunctionTypePointer FunctionType::asExternallyCallableFunction(bool _inLibrary,
|
||||
m_gasSet,
|
||||
m_valueSet,
|
||||
m_saltSet,
|
||||
_bound
|
||||
m_bound
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -980,6 +980,8 @@ public:
|
||||
|
||||
void clearCache() const override;
|
||||
|
||||
protected:
|
||||
std::vector<std::tuple<std::string, TypePointer>> makeStackItems() const override;
|
||||
private:
|
||||
StructDefinition const& m_struct;
|
||||
// Caches for interfaceType(bool)
|
||||
@ -1302,13 +1304,16 @@ public:
|
||||
/// of the parameters to false.
|
||||
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
|
||||
/// 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.
|
||||
/// Also supports variants to be used for library or bound calls.
|
||||
/// @param _inLibrary if true, uses DelegateCall as location.
|
||||
/// @param _bound if true, the function type is set to be bound.
|
||||
FunctionTypePointer asExternallyCallableFunction(bool _inLibrary, bool _bound = false) const;
|
||||
FunctionTypePointer asExternallyCallableFunction(bool _inLibrary) const;
|
||||
|
||||
protected:
|
||||
std::vector<std::tuple<std::string, TypePointer>> makeStackItems() const override;
|
||||
|
@ -725,7 +725,7 @@ string ABIFunctions::abiEncodingFunctionCompactStorageArray(
|
||||
size_t itemsPerSlot = 32 / storageBytes;
|
||||
solAssert(itemsPerSlot > 0, "");
|
||||
// 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(
|
||||
R"(
|
||||
// <readableTypeNameFrom> -> <readableTypeNameTo>
|
||||
|
@ -56,7 +56,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
||||
bool directCopy = sourceIsStorage && sourceBaseType->isValueType() && *sourceBaseType == *targetBaseType;
|
||||
bool haveByteOffsetSource = !directCopy && sourceIsStorage && sourceBaseType->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
|
||||
// store target_ref
|
||||
|
@ -133,7 +133,7 @@ void CompilerContext::callLowLevelFunction(
|
||||
*this << lowLevelFunctionTag(_name, _inArgs, _outArgs, _generator);
|
||||
|
||||
appendJump(evmasm::AssemblyItem::JumpType::IntoFunction);
|
||||
adjustStackOffset(int(_outArgs) - 1 - _inArgs);
|
||||
adjustStackOffset(static_cast<int>(_outArgs) - 1 - static_cast<int>(_inArgs));
|
||||
*this << retTag.tag();
|
||||
}
|
||||
|
||||
@ -147,7 +147,7 @@ void CompilerContext::callYulFunction(
|
||||
auto const retTag = pushNewTag();
|
||||
CompilerUtils(*this).moveIntoStack(_inArgs);
|
||||
appendJumpTo(namedTag(_name));
|
||||
adjustStackOffset(int(_outArgs) - 1 - _inArgs);
|
||||
adjustStackOffset(static_cast<int>(_outArgs) - 1 - static_cast<int>(_inArgs));
|
||||
*this << retTag.tag();
|
||||
}
|
||||
|
||||
@ -181,7 +181,7 @@ void CompilerContext::appendMissingLowLevelFunctions()
|
||||
tie(name, inArgs, outArgs, generator) = m_lowLevelFunctionGenerationQueue.front();
|
||||
m_lowLevelFunctionGenerationQueue.pop();
|
||||
|
||||
setStackOffset(inArgs + 1);
|
||||
setStackOffset(static_cast<int>(inArgs) + 1);
|
||||
*this << m_lowLevelFunctions.at(name).tag();
|
||||
generator(*this);
|
||||
CompilerUtils(*this).moveToStackTop(outArgs);
|
||||
@ -298,12 +298,12 @@ unsigned CompilerContext::baseStackOffsetOfVariable(Declaration const& _declarat
|
||||
|
||||
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
|
||||
{
|
||||
return m_asm->deposit() - _offset - 1;
|
||||
return static_cast<unsigned>(m_asm->deposit()) - _offset - 1;
|
||||
}
|
||||
|
||||
pair<u256, unsigned> CompilerContext::storageLocationOfVariable(Declaration const& _declaration) const
|
||||
@ -371,7 +371,7 @@ void CompilerContext::appendInlineAssembly(
|
||||
OptimiserSettings const& _optimiserSettings
|
||||
)
|
||||
{
|
||||
int startStackHeight = stackHeight();
|
||||
unsigned startStackHeight = stackHeight();
|
||||
|
||||
set<yul::YulString> externallyUsedIdentifiers;
|
||||
for (auto const& fun: _externallyUsedFunctions)
|
||||
@ -387,9 +387,9 @@ void CompilerContext::appendInlineAssembly(
|
||||
) -> size_t
|
||||
{
|
||||
if (_insideFunction)
|
||||
return size_t(-1);
|
||||
return numeric_limits<size_t>::max();
|
||||
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 = [&](
|
||||
yul::Identifier const& _identifier,
|
||||
@ -399,8 +399,8 @@ void CompilerContext::appendInlineAssembly(
|
||||
{
|
||||
auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name.str());
|
||||
solAssert(it != _localVariables.end(), "");
|
||||
int stackDepth = _localVariables.end() - it;
|
||||
int stackDiff = _assembly.stackHeight() - startStackHeight + stackDepth;
|
||||
auto stackDepth = static_cast<size_t>(distance(it, _localVariables.end()));
|
||||
size_t stackDiff = static_cast<size_t>(_assembly.stackHeight()) - startStackHeight + stackDepth;
|
||||
if (_context == yul::IdentifierContext::LValue)
|
||||
stackDiff -= 1;
|
||||
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.
|
||||
CompilerContext *m_runtimeContext;
|
||||
/// 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.
|
||||
std::map<std::string, evmasm::AssemblyItem> m_lowLevelFunctions;
|
||||
/// Collector for yul functions.
|
||||
|
@ -1351,7 +1351,7 @@ void CompilerUtils::popAndJump(unsigned _toHeight, evmasm::AssemblyItem const& _
|
||||
unsigned amount = m_context.stackHeight() - _toHeight;
|
||||
popStackSlots(amount);
|
||||
m_context.appendJumpTo(_jumpTo);
|
||||
m_context.adjustStackOffset(amount);
|
||||
m_context.adjustStackOffset(static_cast<int>(amount));
|
||||
}
|
||||
|
||||
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;
|
||||
// add leading or trailing zeros by dividing/multiplying depending on alignment
|
||||
int shiftFactor = (32 - numBytes) * 8;
|
||||
unsigned shiftFactor = (32 - numBytes) * 8;
|
||||
rightShiftNumberOnStack(shiftFactor);
|
||||
if (leftAligned)
|
||||
{
|
||||
|
@ -185,7 +185,7 @@ size_t ContractCompiler::packIntoContractCreator(ContractDefinition const& _cont
|
||||
CompilerContext::LocationSetter locationSetter(m_context, _contract);
|
||||
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);
|
||||
auto const& immutables = contractType.immutableVariables();
|
||||
@ -221,7 +221,7 @@ size_t ContractCompiler::deployLibrary(ContractDefinition const& _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.pushSubroutineOffset(m_context.runtimeSub());
|
||||
// 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;
|
||||
evmasm::AssemblyItem lessTag{m_context.appendConditionalJump()};
|
||||
// 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);
|
||||
m_context << lessTag;
|
||||
// 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);
|
||||
}
|
||||
else
|
||||
@ -512,8 +512,8 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac
|
||||
m_context << returnTag;
|
||||
// Return tag and input parameters get consumed.
|
||||
m_context.adjustStackOffset(
|
||||
CompilerUtils(m_context).sizeOnStack(functionType->returnParameterTypes()) -
|
||||
CompilerUtils(m_context).sizeOnStack(functionType->parameterTypes()) -
|
||||
static_cast<int>(CompilerUtils::sizeOnStack(functionType->returnParameterTypes())) -
|
||||
static_cast<int>(CompilerUtils::sizeOnStack(functionType->parameterTypes())) -
|
||||
1
|
||||
);
|
||||
// Consumes the return parameters.
|
||||
@ -589,7 +589,7 @@ bool ContractCompiler::visit(FunctionDefinition const& _function)
|
||||
unsigned parametersSize = CompilerUtils::sizeOnStack(_function.parameters());
|
||||
if (!_function.isConstructor())
|
||||
// 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())
|
||||
{
|
||||
m_context.addVariable(*variable, parametersSize);
|
||||
@ -609,7 +609,7 @@ bool ContractCompiler::visit(FunctionDefinition const& _function)
|
||||
m_breakTags.clear();
|
||||
m_continueTags.clear();
|
||||
m_currentFunction = &_function;
|
||||
m_modifierDepth = -1;
|
||||
m_modifierDepth = numeric_limits<unsigned>::max();
|
||||
m_scopeStackHeight.clear();
|
||||
m_context.setModifierDepth(0);
|
||||
|
||||
@ -627,10 +627,10 @@ bool ContractCompiler::visit(FunctionDefinition const& _function)
|
||||
unsigned const c_returnValuesSize = CompilerUtils::sizeOnStack(_function.returnParameters());
|
||||
|
||||
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
|
||||
for (unsigned i = 0; i < c_returnValuesSize; ++i)
|
||||
stackLayout.push_back(i);
|
||||
for (size_t i = 0; i < c_returnValuesSize; ++i)
|
||||
stackLayout.push_back(static_cast<int>(i));
|
||||
|
||||
if (stackLayout.size() > 17)
|
||||
BOOST_THROW_EXCEPTION(
|
||||
@ -638,7 +638,7 @@ bool ContractCompiler::visit(FunctionDefinition const& _function)
|
||||
errinfo_sourceLocation(_function.location()) <<
|
||||
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)
|
||||
{
|
||||
m_context << Instruction::POP;
|
||||
@ -646,11 +646,11 @@ bool ContractCompiler::visit(FunctionDefinition const& _function)
|
||||
}
|
||||
else
|
||||
{
|
||||
m_context << swapInstruction(stackLayout.size() - stackLayout.back() - 1);
|
||||
swap(stackLayout[stackLayout.back()], stackLayout.back());
|
||||
m_context << swapInstruction(stackLayout.size() - static_cast<size_t>(stackLayout.back()) - 1);
|
||||
swap(stackLayout[static_cast<size_t>(stackLayout.back())], stackLayout.back());
|
||||
}
|
||||
for (int i = 0; i < int(stackLayout.size()); ++i)
|
||||
if (stackLayout[i] != i)
|
||||
for (size_t i = 0; i < stackLayout.size(); ++i)
|
||||
if (stackLayout[i] != static_cast<int>(i))
|
||||
solAssert(false, "Invalid stack layout on cleanup.");
|
||||
|
||||
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);
|
||||
if (ref == _inlineAssembly.annotation().externalReferences.end())
|
||||
return size_t(-1);
|
||||
return numeric_limits<size_t>::max();
|
||||
return ref->second.valueSize;
|
||||
};
|
||||
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());
|
||||
auto functionEntryLabel = m_context.functionEntryLabel(*functionDef).pushTag();
|
||||
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
|
||||
// stack slot in case we store it in storage.
|
||||
if (CompilerContext* rtc = m_context.runtimeContext())
|
||||
@ -705,7 +705,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
|
||||
_assembly.appendInstruction(Instruction::MUL);
|
||||
auto runtimeEntryLabel = rtc->functionEntryLabel(*functionDef).toSubAssemblyTag(m_context.runtimeSub());
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -772,7 +772,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
|
||||
}
|
||||
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)
|
||||
{
|
||||
solAssert(variable->type()->dataStoredIn(DataLocation::Storage), "");
|
||||
@ -816,7 +816,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
|
||||
}
|
||||
else
|
||||
solAssert(false, "Invalid declaration type.");
|
||||
solAssert(_assembly.stackHeight() - depositBefore == int(ref->second.valueSize), "");
|
||||
solAssert(_assembly.stackHeight() - depositBefore == static_cast<int>(ref->second.valueSize), "");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -828,7 +828,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
|
||||
"Can only assign to stack variables in inline assembly."
|
||||
);
|
||||
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)
|
||||
BOOST_THROW_EXCEPTION(
|
||||
CompilerError() <<
|
||||
@ -875,7 +875,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
|
||||
false,
|
||||
m_optimiserSettings.optimizeStackAllocation
|
||||
);
|
||||
m_context.setStackOffset(startStackHeight);
|
||||
m_context.setStackOffset(static_cast<int>(startStackHeight));
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -914,7 +914,7 @@ bool ContractCompiler::visit(TryStatement const& _tryStatement)
|
||||
solAssert(params[i] && exprTypes[i] && *params[i]->annotation().type == *exprTypes[i], "");
|
||||
}
|
||||
else
|
||||
CompilerUtils(m_context).popStackSlots(returnSize);
|
||||
CompilerUtils(m_context).popStackSlots(static_cast<size_t>(returnSize));
|
||||
|
||||
_tryStatement.clauses().front()->accept(*this);
|
||||
}
|
||||
@ -937,7 +937,7 @@ void ContractCompiler::handleCatch(vector<ASTPointer<TryCatchClause>> const& _ca
|
||||
else
|
||||
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 fallbackTag = m_context.newTag();
|
||||
|
@ -100,7 +100,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
|
||||
if (_varDecl.immutable())
|
||||
solAssert(paramTypes.empty(), "");
|
||||
|
||||
m_context.adjustStackOffset(1 + CompilerUtils::sizeOnStack(paramTypes));
|
||||
m_context.adjustStackOffset(static_cast<int>(1 + CompilerUtils::sizeOnStack(paramTypes)));
|
||||
|
||||
if (!_varDecl.immutable())
|
||||
{
|
||||
@ -242,7 +242,7 @@ bool ExpressionCompiler::visit(Conditional const& _condition)
|
||||
acceptAndConvert(_condition.falseExpression(), *_condition.annotation().type);
|
||||
evmasm::AssemblyItem endTag = m_context.appendJumpToNew();
|
||||
m_context << trueTag;
|
||||
int offset = _condition.annotation().type->sizeOnStack();
|
||||
int offset = static_cast<int>(_condition.annotation().type->sizeOnStack());
|
||||
m_context.adjustStackOffset(-offset);
|
||||
acceptAndConvert(_condition.trueExpression(), *_condition.annotation().type);
|
||||
m_context << endTag;
|
||||
@ -619,7 +619,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
|
||||
unsigned returnParametersSize = CompilerUtils::sizeOnStack(function.returnParameterTypes());
|
||||
// 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;
|
||||
}
|
||||
case FunctionType::Kind::BareCall:
|
||||
@ -705,7 +705,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
acceptAndConvert(*arguments.front(), *TypeProvider::uint256(), true);
|
||||
// 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.
|
||||
unsigned stackDepth = (function.gasSet() ? 1 : 0) + (function.valueSet() ? 1 : 0);
|
||||
unsigned stackDepth = (function.gasSet() ? 1u : 0u) + (function.valueSet() ? 1u : 0u);
|
||||
if (stackDepth > 0)
|
||||
m_context << swapInstruction(stackDepth);
|
||||
if (function.gasSet())
|
||||
@ -814,7 +814,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
case FunctionType::Kind::Log3:
|
||||
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)
|
||||
acceptAndConvert(*arguments[arg], *function.parameterTypes()[arg], true);
|
||||
arguments.front()->accept(*this);
|
||||
@ -1088,7 +1088,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
{
|
||||
utils().revertWithStringData(*arguments.at(1)->annotation().type);
|
||||
// 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
|
||||
m_context.appendRevert();
|
||||
@ -1271,9 +1271,9 @@ bool ExpressionCompiler::visit(FunctionCallOptions const& _functionCallOptions)
|
||||
acceptAndConvert(*_functionCallOptions.options()[i], *requiredType);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -2190,7 +2190,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
||||
// contract address
|
||||
|
||||
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 gasStackPos = m_context.currentToBaseStackOffset(gasValueSize);
|
||||
unsigned valueStackPos = m_context.currentToBaseStackOffset(1);
|
||||
@ -2361,7 +2361,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
||||
m_context << Instruction::CALL;
|
||||
|
||||
unsigned remainsSize =
|
||||
2 + // contract address, input_memory_end
|
||||
2u + // contract address, input_memory_end
|
||||
(_functionType.valueSet() ? 1 : 0) +
|
||||
(_functionType.gasSet() ? 1 : 0) +
|
||||
(!_functionType.isBareCall() ? 1 : 0);
|
||||
|
@ -1652,8 +1652,7 @@ string YulUtilFunctions::allocateAndInitializeMemoryStructFunction(StructType co
|
||||
return m_functionCollector.createFunction(functionName, [&]() {
|
||||
Whiskers templ(R"(
|
||||
function <functionName>() -> memPtr {
|
||||
let allocSize := <allocSize>()
|
||||
memPtr := <alloc>(allocSize)
|
||||
memPtr := <alloc>(<allocSize>)
|
||||
let offset := memPtr
|
||||
<#member>
|
||||
mstore(offset, <zeroValue>())
|
||||
|
@ -636,7 +636,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
});
|
||||
|
||||
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());
|
||||
@ -1092,7 +1092,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
case FunctionType::Kind::Log3:
|
||||
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, "");
|
||||
ABIFunctions abi(m_context.evmVersion(), m_context.revertStrings(), m_context.functionCollector());
|
||||
string indexedArgs;
|
||||
@ -1477,7 +1477,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
||||
pair<u256, unsigned> const& offsets = structType.storageOffsetsOfMember(member);
|
||||
string slot = m_context.newYulVariable();
|
||||
m_code << "let " << slot << " := " <<
|
||||
("add(" + expression.name() + ", " + offsets.first.str() + ")\n");
|
||||
("add(" + expression.part("slot").name() + ", " + offsets.first.str() + ")\n");
|
||||
setLValue(_memberAccess, IRLValue{
|
||||
type(_memberAccess),
|
||||
IRLValue::Storage{slot, offsets.second}
|
||||
@ -1497,7 +1497,25 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
||||
}
|
||||
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;
|
||||
}
|
||||
default:
|
||||
|
@ -104,7 +104,7 @@ void CHC::analyze(SourceUnit const& _source)
|
||||
for (auto const* assertion: assertions)
|
||||
{
|
||||
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());
|
||||
// This should be fine but it's a bug in the old compiler
|
||||
(void)model;
|
||||
@ -116,7 +116,7 @@ void CHC::analyze(SourceUnit const& _source)
|
||||
{
|
||||
solAssert(dynamic_cast<FunctionCall const*>(scope), "");
|
||||
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());
|
||||
// This should be fine but it's a bug in the old compiler
|
||||
(void)model;
|
||||
@ -533,7 +533,9 @@ void CHC::visitAssert(FunctionCall const& _funCall)
|
||||
connectBlocks(
|
||||
m_currentBlock,
|
||||
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);
|
||||
@ -601,7 +603,7 @@ void CHC::makeArrayPopVerificationTarget(FunctionCall const& _arrayPop)
|
||||
connectBlocks(
|
||||
m_currentBlock,
|
||||
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);
|
||||
@ -891,13 +893,13 @@ vector<smtutil::Expression> CHC::initialStateVariables()
|
||||
return stateVariablesAtIndex(0);
|
||||
}
|
||||
|
||||
vector<smtutil::Expression> CHC::stateVariablesAtIndex(int _index)
|
||||
vector<smtutil::Expression> CHC::stateVariablesAtIndex(unsigned _index)
|
||||
{
|
||||
solAssert(m_currentContract, "");
|
||||
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(
|
||||
stateVariablesIncludingInheritedAndPrivate(_contract),
|
||||
|
@ -149,8 +149,8 @@ private:
|
||||
/// @returns the symbolic values of the state variables at the beginning
|
||||
/// of the current transaction.
|
||||
std::vector<smtutil::Expression> initialStateVariables();
|
||||
std::vector<smtutil::Expression> stateVariablesAtIndex(int _index);
|
||||
std::vector<smtutil::Expression> stateVariablesAtIndex(int _index, ContractDefinition const& _contract);
|
||||
std::vector<smtutil::Expression> stateVariablesAtIndex(unsigned _index);
|
||||
std::vector<smtutil::Expression> stateVariablesAtIndex(unsigned _index, ContractDefinition const& _contract);
|
||||
/// @returns the current symbolic values of the current state variables.
|
||||
std::vector<smtutil::Expression> currentStateVariables();
|
||||
|
||||
|
@ -32,12 +32,23 @@ EncodingContext::EncodingContext():
|
||||
void EncodingContext::reset()
|
||||
{
|
||||
resetAllVariables();
|
||||
resetSlackId();
|
||||
m_expressions.clear();
|
||||
m_globalContext.clear();
|
||||
m_state.reset();
|
||||
m_assertions.clear();
|
||||
}
|
||||
|
||||
void EncodingContext::resetSlackId()
|
||||
{
|
||||
m_nextSlackId = 0;
|
||||
}
|
||||
|
||||
unsigned EncodingContext::newSlackId()
|
||||
{
|
||||
return m_nextSlackId++;
|
||||
}
|
||||
|
||||
void EncodingContext::clear()
|
||||
{
|
||||
m_variables.clear();
|
||||
|
@ -40,6 +40,10 @@ public:
|
||||
/// alive because of state variables and inlined function calls.
|
||||
/// To be used in the beginning of a root function visit.
|
||||
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.
|
||||
/// To be used before a model checking engine starts.
|
||||
void clear();
|
||||
@ -168,6 +172,9 @@ private:
|
||||
/// Whether to conjoin assertions in the assertion stack.
|
||||
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();
|
||||
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())
|
||||
function.body().accept(*this);
|
||||
}
|
||||
else
|
||||
{
|
||||
solAssert(m_modifierDepthStack.back() < int(function.modifiers().size()), "");
|
||||
ASTPointer<ModifierInvocation> const& modifierInvocation = function.modifiers()[m_modifierDepthStack.back()];
|
||||
solAssert(m_modifierDepthStack.back() < static_cast<int>(function.modifiers().size()), "");
|
||||
ASTPointer<ModifierInvocation> const& modifierInvocation =
|
||||
function.modifiers()[static_cast<size_t>(m_modifierDepthStack.back())];
|
||||
solAssert(modifierInvocation, "");
|
||||
auto refDecl = modifierInvocation->name()->annotation().referencedDeclaration;
|
||||
if (dynamic_cast<ContractDefinition const*>(refDecl))
|
||||
@ -1203,7 +1204,7 @@ pair<smtutil::Expression, smtutil::Expression> SMTEncoder::arithmeticOperation(
|
||||
smtutil::Expression const& _left,
|
||||
smtutil::Expression const& _right,
|
||||
TypePointer const& _commonType,
|
||||
Expression const&
|
||||
Expression const& _operation
|
||||
)
|
||||
{
|
||||
static set<Token> validOperators{
|
||||
@ -1226,39 +1227,66 @@ pair<smtutil::Expression, smtutil::Expression> SMTEncoder::arithmeticOperation(
|
||||
else
|
||||
intType = TypeProvider::uint256();
|
||||
|
||||
smtutil::Expression valueNoMod(
|
||||
_op == Token::Add ? _left + _right :
|
||||
_op == Token::Sub ? _left - _right :
|
||||
_op == Token::Div ? division(_left, _right, *intType) :
|
||||
_op == Token::Mul ? _left * _right :
|
||||
/*_op == Token::Mod*/ _left % _right
|
||||
);
|
||||
auto valueUnbounded = [&]() -> smtutil::Expression {
|
||||
switch (_op)
|
||||
{
|
||||
case Token::Add: return _left + _right;
|
||||
case Token::Sub: return _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)
|
||||
{
|
||||
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 symbMax = smt::maxValue(*intType);
|
||||
|
||||
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(
|
||||
valueNoMod > symbMax,
|
||||
valueNoMod % intValueRange,
|
||||
valueUnbounded > symbMax,
|
||||
wrap,
|
||||
smtutil::Expression::ite(
|
||||
valueNoMod < symbMin,
|
||||
valueNoMod % intValueRange,
|
||||
valueNoMod
|
||||
valueUnbounded < symbMin,
|
||||
wrap,
|
||||
valueUnbounded
|
||||
)
|
||||
);
|
||||
|
||||
if (intType->isSigned())
|
||||
value = smtutil::Expression::ite(
|
||||
value > symbMax,
|
||||
value - intValueRange,
|
||||
value
|
||||
);
|
||||
|
||||
return {value, valueNoMod};
|
||||
return {value, valueUnbounded};
|
||||
}
|
||||
|
||||
void SMTEncoder::compareOperation(BinaryOperation const& _op)
|
||||
@ -1679,8 +1707,8 @@ void SMTEncoder::mergeVariables(set<VariableDeclaration const*> const& _variable
|
||||
for (auto const* decl: sortedVars)
|
||||
{
|
||||
solAssert(_indicesEndTrue.count(decl) && _indicesEndFalse.count(decl), "");
|
||||
int trueIndex = _indicesEndTrue.at(decl);
|
||||
int falseIndex = _indicesEndFalse.at(decl);
|
||||
auto trueIndex = static_cast<unsigned>(_indicesEndTrue.at(decl));
|
||||
auto falseIndex = static_cast<unsigned>(_indicesEndFalse.at(decl));
|
||||
solAssert(trueIndex != falseIndex, "");
|
||||
m_context.addAssertion(m_context.newValue(*decl) == smtutil::Expression::ite(
|
||||
_condition,
|
||||
@ -1696,7 +1724,7 @@ smtutil::Expression SMTEncoder::currentValue(VariableDeclaration const& _decl)
|
||||
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), "");
|
||||
return m_context.variable(_decl)->valueAtIndex(_index);
|
||||
@ -1819,7 +1847,7 @@ SMTEncoder::VariableIndices SMTEncoder::copyVariableIndices()
|
||||
void SMTEncoder::resetVariableIndices(VariableIndices const& _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)
|
||||
|
@ -201,7 +201,7 @@ protected:
|
||||
smtutil::Expression currentValue(VariableDeclaration const& _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.
|
||||
smtutil::Expression valueAtIndex(VariableDeclaration const& _decl, int _index);
|
||||
smtutil::Expression valueAtIndex(VariableDeclaration const& _decl, unsigned _index);
|
||||
/// Returns the expression corresponding to the AST node.
|
||||
/// If _targetType is not null apply conversion.
|
||||
/// Throws if the expression does not exist.
|
||||
|
@ -66,12 +66,12 @@ string SymbolicVariable::currentName() const
|
||||
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);
|
||||
}
|
||||
|
||||
string SymbolicVariable::nameAtIndex(int _index) const
|
||||
string SymbolicVariable::nameAtIndex(unsigned _index) const
|
||||
{
|
||||
return uniqueSymbol(_index);
|
||||
}
|
||||
@ -170,12 +170,12 @@ smtutil::Expression SymbolicFunctionVariable::currentFunctionValue() const
|
||||
return m_declaration;
|
||||
}
|
||||
|
||||
smtutil::Expression SymbolicFunctionVariable::valueAtIndex(int _index) const
|
||||
smtutil::Expression SymbolicFunctionVariable::valueAtIndex(unsigned _index) const
|
||||
{
|
||||
return m_abstract.valueAtIndex(_index);
|
||||
}
|
||||
|
||||
smtutil::Expression SymbolicFunctionVariable::functionValueAtIndex(int _index) const
|
||||
smtutil::Expression SymbolicFunctionVariable::functionValueAtIndex(unsigned _index) const
|
||||
{
|
||||
return SymbolicVariable::valueAtIndex(_index);
|
||||
}
|
||||
@ -304,7 +304,7 @@ smtutil::Expression SymbolicArrayVariable::currentValue(frontend::TypePointer co
|
||||
return m_pair.currentValue();
|
||||
}
|
||||
|
||||
smtutil::Expression SymbolicArrayVariable::valueAtIndex(int _index) const
|
||||
smtutil::Expression SymbolicArrayVariable::valueAtIndex(unsigned _index) const
|
||||
{
|
||||
return m_pair.valueAtIndex(_index);
|
||||
}
|
||||
|
@ -54,8 +54,8 @@ public:
|
||||
|
||||
virtual smtutil::Expression currentValue(frontend::TypePointer const& _targetType = TypePointer{}) const;
|
||||
std::string currentName() const;
|
||||
virtual smtutil::Expression valueAtIndex(int _index) const;
|
||||
virtual std::string nameAtIndex(int _index) const;
|
||||
virtual smtutil::Expression valueAtIndex(unsigned _index) const;
|
||||
virtual std::string nameAtIndex(unsigned _index) const;
|
||||
virtual smtutil::Expression resetIndex();
|
||||
virtual smtutil::Expression setIndex(unsigned _index);
|
||||
virtual smtutil::Expression increaseIndex();
|
||||
@ -165,10 +165,10 @@ public:
|
||||
// Explicit request the function declaration.
|
||||
smtutil::Expression currentFunctionValue() const;
|
||||
|
||||
smtutil::Expression valueAtIndex(int _index) const override;
|
||||
smtutil::Expression valueAtIndex(unsigned _index) const override;
|
||||
|
||||
// Explicit request the function declaration.
|
||||
smtutil::Expression functionValueAtIndex(int _index) const;
|
||||
smtutil::Expression functionValueAtIndex(unsigned _index) const;
|
||||
|
||||
smtutil::Expression resetIndex() override;
|
||||
smtutil::Expression setIndex(unsigned _index) override;
|
||||
@ -251,7 +251,7 @@ public:
|
||||
SymbolicArrayVariable(SymbolicArrayVariable&&) = default;
|
||||
|
||||
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 setIndex(unsigned _index) override { SymbolicVariable::setIndex(_index); return m_pair.setIndex(_index); }
|
||||
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);
|
||||
}
|
||||
string path = bestMatchTarget;
|
||||
path.append(_path.begin() + longestPrefix, _path.end());
|
||||
path.append(_path.begin() + static_cast<string::difference_type>(longestPrefix), _path.end());
|
||||
return path;
|
||||
}
|
||||
|
||||
|
@ -54,8 +54,8 @@ GasEstimator::ASTGasConsumptionSelfAccumulated GasEstimator::structuralEstimatio
|
||||
{
|
||||
solAssert(!!block.startState, "");
|
||||
GasMeter meter(block.startState->copy(), m_evmVersion);
|
||||
auto const end = _items.begin() + block.end;
|
||||
for (auto iter = _items.begin() + block.begin; iter != end; ++iter)
|
||||
auto const end = _items.begin() + static_cast<ptrdiff_t>(block.end);
|
||||
for (auto iter = _items.begin() + static_cast<ptrdiff_t>(block.begin); iter != end; ++iter)
|
||||
particularCosts[iter->location()] += meter.estimateMax(*iter);
|
||||
}
|
||||
|
||||
|
@ -37,6 +37,9 @@ Json::Value Natspec::userDocumentation(ContractDefinition const& _contractDef)
|
||||
Json::Value doc;
|
||||
Json::Value methods(Json::objectValue);
|
||||
|
||||
doc["version"] = Json::Value(c_natspecVersion);
|
||||
doc["kind"] = Json::Value("user");
|
||||
|
||||
auto constructorDefinition(_contractDef.constructor());
|
||||
if (constructorDefinition)
|
||||
{
|
||||
@ -91,6 +94,9 @@ Json::Value Natspec::devDocumentation(ContractDefinition const& _contractDef)
|
||||
Json::Value doc;
|
||||
Json::Value methods(Json::objectValue);
|
||||
|
||||
doc["version"] = Json::Value(c_natspecVersion);
|
||||
doc["kind"] = Json::Value("dev");
|
||||
|
||||
auto author = extractDoc(_contractDef.annotation().docTags, "author");
|
||||
if (!author.empty())
|
||||
doc["author"] = author;
|
||||
|
@ -40,6 +40,8 @@ struct DocTag;
|
||||
class Natspec
|
||||
{
|
||||
public:
|
||||
static unsigned int constexpr c_natspecVersion = 1;
|
||||
|
||||
/// Get the User documentation of the contract
|
||||
/// @param _contractDef The contract definition
|
||||
/// @return A JSON representation of the contract's user documentation
|
||||
|
@ -111,7 +111,8 @@ Json::Value formatErrorWithException(
|
||||
bool const& _warning,
|
||||
string const& _type,
|
||||
string const& _component,
|
||||
string const& _message
|
||||
string const& _message,
|
||||
optional<ErrorId> _errorId = nullopt
|
||||
)
|
||||
{
|
||||
string message;
|
||||
@ -122,7 +123,7 @@ Json::Value formatErrorWithException(
|
||||
else
|
||||
message = _message;
|
||||
|
||||
return formatError(
|
||||
Json::Value error = formatError(
|
||||
_warning,
|
||||
_type,
|
||||
_component,
|
||||
@ -131,6 +132,11 @@ Json::Value formatErrorWithException(
|
||||
formatSourceLocation(boost::get_error_info<errinfo_sourceLocation>(_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)
|
||||
@ -857,7 +863,8 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
|
||||
err.type() == Error::Type::Warning,
|
||||
err.typeName(),
|
||||
"general",
|
||||
""
|
||||
"",
|
||||
err.errorId()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ Json::Value StorageLayout::generate(VariableDeclaration const& _var, u256 const&
|
||||
TypePointer varType = _var.type();
|
||||
|
||||
varEntry["label"] = _var.name();
|
||||
varEntry["astId"] = int(_var.id());
|
||||
varEntry["astId"] = static_cast<int>(_var.id());
|
||||
varEntry["contract"] = m_contract->fullyQualifiedName();
|
||||
varEntry["slot"] = _slot.str();
|
||||
varEntry["offset"] = _offset;
|
||||
|
@ -106,7 +106,7 @@ bytes solidity::util::fromHex(std::string const& _s, WhenError _throw)
|
||||
{
|
||||
int h = fromHex(_s[s++], _throw);
|
||||
if (h != -1)
|
||||
ret.push_back(h);
|
||||
ret.push_back(static_cast<uint8_t>(h));
|
||||
else
|
||||
return bytes();
|
||||
}
|
||||
@ -115,7 +115,7 @@ bytes solidity::util::fromHex(std::string const& _s, WhenError _throw)
|
||||
int h = fromHex(_s[i], _throw);
|
||||
int l = fromHex(_s[i + 1], _throw);
|
||||
if (h != -1 && l != -1)
|
||||
ret.push_back((uint8_t)(h * 16 + l));
|
||||
ret.push_back(static_cast<uint8_t>(h * 16 + l));
|
||||
else
|
||||
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()));
|
||||
|
||||
string ret = "0x";
|
||||
for (size_t i = 0; i < 40; ++i)
|
||||
for (unsigned i = 0; i < 40; ++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)
|
||||
ret += toupper(addressCharacter);
|
||||
ret += static_cast<char>(toupper(addressCharacter));
|
||||
else
|
||||
ret += tolower(addressCharacter);
|
||||
ret += static_cast<char>(tolower(addressCharacter));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -64,10 +64,44 @@ public:
|
||||
FixedHash(Arith const& _arith) { toBigEndian(_arith, m_data); }
|
||||
|
||||
/// 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.
|
||||
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.
|
||||
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 REPEAT24(e) REPEAT6(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; \
|
||||
REPEAT5(e; v += s;)
|
||||
REPEAT5(e; v = static_cast<type>(v + s);)
|
||||
|
||||
/*** Keccak-f[1600] ***/
|
||||
static inline void keccakf(void* state) {
|
||||
uint64_t* a = (uint64_t*)state;
|
||||
auto* a = static_cast<uint64_t*>(state);
|
||||
uint64_t b[5] = {0};
|
||||
|
||||
for (int i = 0; i < 24; i++)
|
||||
{
|
||||
uint8_t x, y;
|
||||
// Theta
|
||||
FOR5(x, 1,
|
||||
FOR5(uint8_t, x, 1,
|
||||
b[x] = 0;
|
||||
FOR5(y, 5,
|
||||
FOR5(uint8_t, y, 5,
|
||||
b[x] ^= a[x + y]; ))
|
||||
FOR5(x, 1,
|
||||
FOR5(y, 5,
|
||||
FOR5(uint8_t, x, 1,
|
||||
FOR5(uint8_t, y, 5,
|
||||
a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); ))
|
||||
// Rho and pi
|
||||
uint64_t t = a[1];
|
||||
@ -97,11 +97,12 @@ static inline void keccakf(void* state) {
|
||||
t = b[0];
|
||||
x++; )
|
||||
// Chi
|
||||
FOR5(y,
|
||||
FOR5(uint8_t,
|
||||
y,
|
||||
5,
|
||||
FOR5(x, 1,
|
||||
FOR5(uint8_t, x, 1,
|
||||
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]); ))
|
||||
// Iota
|
||||
a[0] ^= RC[i];
|
||||
|
@ -137,7 +137,7 @@ vector<YulString> AsmAnalyzer::operator()(Identifier const& _identifier)
|
||||
{
|
||||
bool insideFunction = m_currentScope->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;
|
||||
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();
|
||||
size_t variableSize = m_resolver(_variable, yul::IdentifierContext::LValue, insideFunction);
|
||||
if (variableSize != size_t(-1))
|
||||
if (variableSize != numeric_limits<size_t>::max())
|
||||
{
|
||||
found = true;
|
||||
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 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 closing = count_if(begin(_s), e, [](auto ch) { return ch == '}' || ch == ')'; });
|
||||
return opening - closing;
|
||||
|
@ -71,10 +71,10 @@ public:
|
||||
{
|
||||
// FNV hash - can be replaced by a better one, e.g. xxhash64
|
||||
std::uint64_t hash = emptyHash();
|
||||
for (auto c: v)
|
||||
for (char c: v)
|
||||
{
|
||||
hash *= 1099511628211u;
|
||||
hash ^= c;
|
||||
hash ^= static_cast<uint64_t>(c);
|
||||
}
|
||||
|
||||
return hash;
|
||||
|
@ -143,14 +143,14 @@ pair<shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> EthAssemblyAdapter::
|
||||
{
|
||||
shared_ptr<evmasm::Assembly> assembly{make_shared<evmasm::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)
|
||||
{
|
||||
auto it = m_dataHashBySubId.find(_sub);
|
||||
if (it == m_dataHashBySubId.end())
|
||||
m_assembly.pushSubroutineOffset(size_t(_sub));
|
||||
m_assembly.pushSubroutineOffset(_sub);
|
||||
else
|
||||
m_assembly << evmasm::AssemblyItem(evmasm::PushData, it->second);
|
||||
}
|
||||
@ -159,7 +159,7 @@ void EthAssemblyAdapter::appendDataSize(AbstractAssembly::SubID _sub)
|
||||
{
|
||||
auto it = m_dataHashBySubId.find(_sub);
|
||||
if (it == m_dataHashBySubId.end())
|
||||
m_assembly.pushSubroutineSize(size_t(_sub));
|
||||
m_assembly.pushSubroutineSize(static_cast<size_t>(_sub));
|
||||
else
|
||||
m_assembly << u256(m_assembly.data(h256(it->second)).size());
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ void EVMAssembly::appendLabelReference(LabelID _labelId)
|
||||
|
||||
EVMAssembly::LabelID EVMAssembly::newLabelId()
|
||||
{
|
||||
m_labelPositions[m_nextLabelId] = size_t(-1);
|
||||
m_labelPositions[m_nextLabelId] = numeric_limits<size_t>::max();
|
||||
return m_nextLabelId++;
|
||||
}
|
||||
|
||||
@ -165,7 +165,7 @@ evmasm::LinkerObject EVMAssembly::finalize()
|
||||
size_t referencePos = ref.first;
|
||||
yulAssert(m_labelPositions.count(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));
|
||||
}
|
||||
|
||||
@ -177,7 +177,7 @@ evmasm::LinkerObject EVMAssembly::finalize()
|
||||
void EVMAssembly::setLabelToCurrentPosition(LabelID _labelId)
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -175,28 +175,29 @@ void CodeTransform::operator()(VariableDeclaration const& _varDecl)
|
||||
{
|
||||
yulAssert(m_scope, "");
|
||||
|
||||
int const numVariables = _varDecl.variables.size();
|
||||
int heightAtStart = m_assembly.stackHeight();
|
||||
size_t const numVariables = _varDecl.variables.size();
|
||||
auto heightAtStart = static_cast<size_t>(m_assembly.stackHeight());
|
||||
if (_varDecl.value)
|
||||
{
|
||||
std::visit(*this, *_varDecl.value);
|
||||
expectDeposit(numVariables, heightAtStart);
|
||||
expectDeposit(static_cast<int>(numVariables), static_cast<int>(heightAtStart));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_assembly.setSourceLocation(_varDecl.location);
|
||||
int variablesLeft = numVariables;
|
||||
size_t variablesLeft = numVariables;
|
||||
while (variablesLeft--)
|
||||
m_assembly.appendConstant(u256(0));
|
||||
}
|
||||
|
||||
m_assembly.setSourceLocation(_varDecl.location);
|
||||
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));
|
||||
m_context->variableStackHeights[&var] = heightAtStart + varIndex;
|
||||
m_context->variableStackHeights[&var] = heightAtStart + varIndexReverse;
|
||||
if (!m_allowStackOpt)
|
||||
continue;
|
||||
|
||||
@ -214,10 +215,10 @@ void CodeTransform::operator()(VariableDeclaration const& _varDecl)
|
||||
atTopOfStack = false;
|
||||
else
|
||||
{
|
||||
int slot = *m_unusedStackSlots.begin();
|
||||
auto slot = static_cast<size_t>(*m_unusedStackSlots.begin());
|
||||
m_unusedStackSlots.erase(m_unusedStackSlots.begin());
|
||||
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::Instruction::POP);
|
||||
}
|
||||
@ -240,7 +241,7 @@ void CodeTransform::operator()(Assignment const& _assignment)
|
||||
{
|
||||
int height = m_assembly.stackHeight();
|
||||
std::visit(*this, *_assignment.value);
|
||||
expectDeposit(_assignment.variableNames.size(), height);
|
||||
expectDeposit(static_cast<int>(_assignment.variableNames.size()), height);
|
||||
|
||||
m_assembly.setSourceLocation(_assignment.location);
|
||||
generateMultiAssignment(_assignment.variableNames);
|
||||
@ -263,7 +264,7 @@ void CodeTransform::operator()(FunctionCall const& _call)
|
||||
else
|
||||
{
|
||||
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)
|
||||
{
|
||||
returnLabel = m_assembly.newLabelId();
|
||||
@ -281,10 +282,17 @@ void CodeTransform::operator()(FunctionCall const& _call)
|
||||
visitExpression(arg);
|
||||
m_assembly.setSourceLocation(_call.location);
|
||||
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
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -300,7 +308,7 @@ void CodeTransform::operator()(Identifier const& _identifier)
|
||||
{
|
||||
// TODO: opportunity for optimization: Do not DUP if this is the last reference
|
||||
// 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));
|
||||
else
|
||||
// Store something to balance the stack
|
||||
@ -407,7 +415,7 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
|
||||
int const stackHeightBefore = m_assembly.stackHeight();
|
||||
|
||||
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
|
||||
m_assembly.appendLabel(functionEntryID(_function.name, function));
|
||||
|
||||
@ -465,15 +473,15 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
|
||||
// modified parallel to the actual stack.
|
||||
vector<int> stackLayout;
|
||||
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
|
||||
|
||||
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)
|
||||
{
|
||||
StackTooDeepError error(_function.name, YulString{}, stackLayout.size() - 17);
|
||||
StackTooDeepError error(_function.name, YulString{}, static_cast<int>(stackLayout.size()) - 17);
|
||||
error << errinfo_comment(
|
||||
"The function " +
|
||||
_function.name.str() +
|
||||
@ -481,11 +489,11 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
|
||||
to_string(stackLayout.size() - 17) +
|
||||
" 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
|
||||
{
|
||||
while (!stackLayout.empty() && stackLayout.back() != int(stackLayout.size() - 1))
|
||||
while (!stackLayout.empty() && stackLayout.back() != static_cast<int>(stackLayout.size() - 1))
|
||||
if (stackLayout.back() < 0)
|
||||
{
|
||||
m_assembly.appendInstruction(evmasm::Instruction::POP);
|
||||
@ -493,17 +501,17 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
|
||||
}
|
||||
else
|
||||
{
|
||||
m_assembly.appendInstruction(evmasm::swapInstruction(stackLayout.size() - stackLayout.back() - 1));
|
||||
swap(stackLayout[stackLayout.back()], stackLayout.back());
|
||||
m_assembly.appendInstruction(evmasm::swapInstruction(stackLayout.size() - static_cast<size_t>(stackLayout.back()) - 1));
|
||||
swap(stackLayout[static_cast<size_t>(stackLayout.back())], stackLayout.back());
|
||||
}
|
||||
for (int i = 0; size_t(i) < stackLayout.size(); ++i)
|
||||
yulAssert(i == stackLayout[i], "Error reshuffling stack.");
|
||||
for (size_t i = 0; i < stackLayout.size(); ++i)
|
||||
yulAssert(i == static_cast<size_t>(stackLayout[i]), "Error reshuffling stack.");
|
||||
}
|
||||
}
|
||||
if (m_evm15)
|
||||
m_assembly.appendReturnsub(_function.returnVariables.size(), stackHeightBefore);
|
||||
m_assembly.appendReturnsub(static_cast<int>(_function.returnVariables.size()), stackHeightBefore);
|
||||
else
|
||||
m_assembly.appendJump(stackHeightBefore - _function.returnVariables.size());
|
||||
m_assembly.appendJump(stackHeightBefore - static_cast<int>(_function.returnVariables.size()));
|
||||
m_assembly.setStackHeight(stackHeightBefore);
|
||||
}
|
||||
|
||||
@ -683,7 +691,7 @@ void CodeTransform::generateAssignment(Identifier const& _variableName)
|
||||
if (auto var = m_scope->lookup(_variableName.name))
|
||||
{
|
||||
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::Instruction::POP);
|
||||
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), "");
|
||||
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.");
|
||||
int limit = _forSwap ? 17 : 16;
|
||||
size_t limit = _forSwap ? 17 : 16;
|
||||
if (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.");
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,7 @@ struct StackTooDeepError: virtual YulException
|
||||
struct CodeTransformContext
|
||||
{
|
||||
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;
|
||||
|
||||
struct JumpInfo
|
||||
@ -200,7 +200,7 @@ private:
|
||||
/// 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
|
||||
/// 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;
|
||||
|
||||
|
@ -63,8 +63,8 @@ pair<YulString, BuiltinFunctionForEVM> createEVMFunction(
|
||||
evmasm::InstructionInfo info = evmasm::instructionInfo(_instruction);
|
||||
BuiltinFunctionForEVM f;
|
||||
f.name = YulString{_name};
|
||||
f.parameters.resize(info.args);
|
||||
f.returns.resize(info.ret);
|
||||
f.parameters.resize(static_cast<size_t>(info.args));
|
||||
f.returns.resize(static_cast<size_t>(info.ret));
|
||||
f.sideEffects = EVMDialect::sideEffectsOfInstruction(_instruction);
|
||||
f.controlFlowSideEffects.terminates = evmasm::SemanticInformation::terminatesControlFlow(_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_dataGas +=
|
||||
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&)
|
||||
|
@ -22,9 +22,11 @@
|
||||
|
||||
#include <libyul/Exceptions.h>
|
||||
#include <libsolutil/CommonData.h>
|
||||
#include <libsolutil/Visitor.h>
|
||||
|
||||
#include <boost/range/adaptor/reversed.hpp>
|
||||
#include <boost/range/adaptor/map.hpp>
|
||||
#include <boost/range/adaptor/transformed.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity;
|
||||
@ -82,6 +84,16 @@ bytes toBytes(ValueType _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
|
||||
{
|
||||
Function = 0x0,
|
||||
@ -131,6 +143,16 @@ bytes toBytes(Opcode _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 = {
|
||||
{"i32.load", 0x28},
|
||||
{"i64.load", 0x29},
|
||||
@ -249,6 +271,34 @@ bytes makeSection(Section _section, bytes _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)
|
||||
@ -297,7 +347,10 @@ bytes BinaryTransform::run(Module const& _module)
|
||||
|
||||
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&)
|
||||
@ -323,12 +376,12 @@ bytes BinaryTransform::operator()(BuiltinCall const& _call)
|
||||
if (_call.functionName == "dataoffset")
|
||||
{
|
||||
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")
|
||||
{
|
||||
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);
|
||||
@ -443,21 +496,18 @@ bytes BinaryTransform::operator()(FunctionDefinition const& _function)
|
||||
{
|
||||
bytes ret;
|
||||
|
||||
// This is a kind of run-length-encoding of local types. Has to be adapted once
|
||||
// we have locals of different types.
|
||||
if (_function.locals.size() == 0)
|
||||
ret += lebEncode(0); // number of locals groups
|
||||
else
|
||||
vector<pair<size_t, ValueType>> localEntries = groupLocalVariables(_function.locals);
|
||||
ret += lebEncode(localEntries.size());
|
||||
for (pair<size_t, ValueType> const& entry: localEntries)
|
||||
{
|
||||
ret += lebEncode(1); // number of locals groups
|
||||
ret += lebEncode(_function.locals.size());
|
||||
ret += toBytes(ValueType::I64);
|
||||
ret += lebEncode(entry.first);
|
||||
ret += toBytes(entry.second);
|
||||
}
|
||||
|
||||
m_locals.clear();
|
||||
size_t varIdx = 0;
|
||||
for (size_t i = 0; i < _function.parameterNames.size(); ++i)
|
||||
m_locals[_function.parameterNames[i]] = varIdx++;
|
||||
for (size_t i = 0; i < _function.parameters.size(); ++i)
|
||||
m_locals[_function.parameters[i].name] = varIdx++;
|
||||
for (size_t i = 0; i < _function.locals.size(); ++i)
|
||||
m_locals[_function.locals[i].variableName] = varIdx++;
|
||||
|
||||
@ -475,38 +525,39 @@ BinaryTransform::Type BinaryTransform::typeOf(FunctionImport const& _import)
|
||||
{
|
||||
return {
|
||||
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)
|
||||
{
|
||||
|
||||
return {
|
||||
encodeTypes(vector<string>(_funDef.parameterNames.size(), "i64")),
|
||||
encodeTypes(vector<string>(_funDef.returns ? 1 : 0, "i64"))
|
||||
encodeTypes(_funDef.parameters),
|
||||
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(ValueType::I32);
|
||||
else if (_typeName == "i64")
|
||||
return uint8_t(ValueType::I64);
|
||||
else
|
||||
yulAssert(false, "");
|
||||
return 0;
|
||||
return uint8_t(toValueType(_type));
|
||||
}
|
||||
|
||||
vector<uint8_t> BinaryTransform::encodeTypes(vector<string> const& _typeNames)
|
||||
vector<uint8_t> BinaryTransform::encodeTypes(vector<wasm::Type> const& _types)
|
||||
{
|
||||
vector<uint8_t> result;
|
||||
for (auto const& t: _typeNames)
|
||||
for (wasm::Type t: _types)
|
||||
result.emplace_back(encodeType(t));
|
||||
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(
|
||||
vector<wasm::FunctionImport> const& _imports,
|
||||
vector<wasm::FunctionDefinition> const& _functions
|
||||
@ -612,13 +663,16 @@ bytes BinaryTransform::memorySection()
|
||||
bytes BinaryTransform::globalSection(vector<wasm::GlobalVariableDeclaration> const& _globals)
|
||||
{
|
||||
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 +=
|
||||
toBytes(ValueType::I64) +
|
||||
toBytes(globalType) +
|
||||
lebEncode(static_cast<uint8_t>(Mutability::Var)) +
|
||||
toBytes(Opcode::I64Const) +
|
||||
toBytes(constOpcodeFor(globalType)) +
|
||||
lebEncodeSigned(0) +
|
||||
toBytes(Opcode::End);
|
||||
}
|
||||
|
||||
return makeSection(Section::GLOBAL, move(result));
|
||||
}
|
||||
|
@ -71,8 +71,9 @@ private:
|
||||
static Type typeOf(wasm::FunctionImport const& _import);
|
||||
static Type typeOf(wasm::FunctionDefinition const& _funDef);
|
||||
|
||||
static uint8_t encodeType(std::string const& _typeName);
|
||||
static std::vector<uint8_t> encodeTypes(std::vector<std::string> const& _typeNames);
|
||||
static uint8_t encodeType(wasm::Type _type);
|
||||
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(
|
||||
std::vector<wasm::FunctionImport> const& _imports,
|
||||
|
@ -20,7 +20,10 @@
|
||||
|
||||
#include <libyul/backends/wasm/TextTransform.h>
|
||||
|
||||
#include <libyul/Exceptions.h>
|
||||
|
||||
#include <libsolutil/StringUtils.h>
|
||||
#include <libsolutil/Visitor.h>
|
||||
|
||||
#include <boost/algorithm/string/join.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;
|
||||
if (!imp.paramTypes.empty())
|
||||
ret += " (param" + joinHumanReadablePrefixed(imp.paramTypes, " ", " ") + ")";
|
||||
ret += " (param" + joinHumanReadablePrefixed(imp.paramTypes | boost::adaptors::transformed(encodeType), " ", " ") + ")";
|
||||
if (imp.returnType)
|
||||
ret += " (result " + *imp.returnType + ")";
|
||||
ret += " (result " + encodeType(*imp.returnType) + ")";
|
||||
ret += "))\n";
|
||||
}
|
||||
|
||||
@ -56,7 +59,7 @@ string TextTransform::run(wasm::Module const& _module)
|
||||
ret += " (export \"main\" (func $main))\n";
|
||||
|
||||
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";
|
||||
for (auto const& f: _module.functions)
|
||||
ret += transform(f) + "\n";
|
||||
@ -65,7 +68,10 @@ string TextTransform::run(wasm::Module const& _module)
|
||||
|
||||
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)
|
||||
@ -162,12 +168,12 @@ string TextTransform::indented(string const& _in)
|
||||
string TextTransform::transform(wasm::FunctionDefinition const& _function)
|
||||
{
|
||||
string ret = "(func $" + _function.name + "\n";
|
||||
for (auto const& param: _function.parameterNames)
|
||||
ret += " (param $" + param + " i64)\n";
|
||||
if (_function.returns)
|
||||
ret += " (result i64)\n";
|
||||
for (auto const& param: _function.parameters)
|
||||
ret += " (param $" + param.name + " " + encodeType(param.type) + ")\n";
|
||||
if (_function.returnType.has_value())
|
||||
ret += " (result " + encodeType(_function.returnType.value()) + ")\n";
|
||||
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'));
|
||||
if (ret.back() != '\n')
|
||||
ret += '\n';
|
||||
@ -193,3 +199,13 @@ string TextTransform::joinTransformed(vector<wasm::Expression> const& _expressio
|
||||
}
|
||||
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,
|
||||
char _separator = ' '
|
||||
);
|
||||
|
||||
static std::string encodeType(wasm::Type _type);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -30,6 +30,15 @@
|
||||
namespace solidity::yul::wasm
|
||||
{
|
||||
|
||||
enum class Type
|
||||
{
|
||||
i32,
|
||||
i64,
|
||||
};
|
||||
|
||||
struct TypedName { std::string name; Type type; };
|
||||
using TypedNameList = std::vector<TypedName>;
|
||||
|
||||
struct Literal;
|
||||
struct StringLiteral;
|
||||
struct LocalVariable;
|
||||
@ -50,7 +59,7 @@ using Expression = std::variant<
|
||||
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 LocalVariable { std::string name; };
|
||||
struct GlobalVariable { std::string name; };
|
||||
@ -70,21 +79,21 @@ struct Branch { Label label; };
|
||||
struct Return {};
|
||||
struct BranchIf { Label label; std::unique_ptr<Expression> condition; };
|
||||
|
||||
struct VariableDeclaration { std::string variableName; };
|
||||
struct GlobalVariableDeclaration { std::string variableName; };
|
||||
struct VariableDeclaration { std::string variableName; Type type; };
|
||||
struct GlobalVariableDeclaration { std::string variableName; Type type; };
|
||||
struct FunctionImport {
|
||||
std::string module;
|
||||
std::string externalName;
|
||||
std::string internalName;
|
||||
std::vector<std::string> paramTypes;
|
||||
std::optional<std::string> returnType;
|
||||
std::vector<Type> paramTypes;
|
||||
std::optional<Type> returnType;
|
||||
};
|
||||
|
||||
struct FunctionDefinition
|
||||
{
|
||||
std::string name;
|
||||
std::vector<std::string> parameterNames;
|
||||
bool returns;
|
||||
std::vector<TypedName> parameters;
|
||||
std::optional<Type> returnType;
|
||||
std::vector<VariableDeclaration> locals;
|
||||
std::vector<Expression> body;
|
||||
};
|
||||
|
@ -88,7 +88,7 @@ wasm::Expression WasmCodeTransform::operator()(VariableDeclaration const& _varDe
|
||||
for (auto const& var: _varDecl.variables)
|
||||
{
|
||||
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)
|
||||
@ -127,10 +127,10 @@ wasm::Expression WasmCodeTransform::operator()(FunctionCall const& _call)
|
||||
builtin->name.str().substr(4),
|
||||
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)
|
||||
imp.paramTypes.emplace_back(param.str());
|
||||
imp.paramTypes.emplace_back(translatedType(param));
|
||||
m_functionsToImport[builtin->name] = std::move(imp);
|
||||
}
|
||||
typeConversionNeeded = true;
|
||||
@ -184,7 +184,7 @@ wasm::Expression WasmCodeTransform::operator()(Literal const& _literal)
|
||||
{
|
||||
u256 value = valueOfLiteral(_literal);
|
||||
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)
|
||||
@ -193,7 +193,7 @@ wasm::Expression WasmCodeTransform::operator()(If const& _if)
|
||||
|
||||
vector<wasm::Expression> args;
|
||||
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{
|
||||
make_unique<wasm::Expression>(wasm::BuiltinCall{"i64.ne", std::move(args)}),
|
||||
visit(_if.body.statements),
|
||||
@ -205,7 +205,7 @@ wasm::Expression WasmCodeTransform::operator()(Switch const& _switch)
|
||||
{
|
||||
wasm::Block block;
|
||||
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)});
|
||||
|
||||
vector<wasm::Expression>* currentBlock = &block.statements;
|
||||
@ -325,10 +325,11 @@ wasm::FunctionDefinition WasmCodeTransform::translateFunction(yul::FunctionDefin
|
||||
wasm::FunctionDefinition fun;
|
||||
fun.name = _fun.name.str();
|
||||
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)
|
||||
fun.locals.emplace_back(wasm::VariableDeclaration{retParam.name.str()});
|
||||
fun.returns = !_fun.returnVariables.empty();
|
||||
fun.locals.emplace_back(wasm::VariableDeclaration{retParam.name.str(), wasm::Type::i64});
|
||||
if (!_fun.returnVariables.empty())
|
||||
fun.returnType = wasm::Type::i64;
|
||||
|
||||
yulAssert(m_localVariables.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});
|
||||
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]))};
|
||||
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 {std::move(_call)};
|
||||
@ -400,6 +401,17 @@ void WasmCodeTransform::allocateGlobals(size_t _amount)
|
||||
{
|
||||
while (m_globalVariables.size() < _amount)
|
||||
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.
|
||||
void allocateGlobals(size_t _amount);
|
||||
|
||||
static wasm::Type translatedType(yul::Type _yulType);
|
||||
|
||||
Dialect const& m_dialect;
|
||||
NameDispenser m_nameDispenser;
|
||||
|
||||
|
@ -112,7 +112,7 @@ void WordSizeTransform::operator()(Block& _block)
|
||||
yulAssert(varDecl.variables.size() == 1, "");
|
||||
auto newLhs = generateU64IdentifierNames(varDecl.variables[0].name);
|
||||
vector<Statement> ret;
|
||||
for (int i = 0; i < 3; i++)
|
||||
for (size_t i = 0; i < 3; i++)
|
||||
ret.emplace_back(VariableDeclaration{
|
||||
varDecl.location,
|
||||
{TypedName{varDecl.location, newLhs[i], m_targetDialect.defaultType}},
|
||||
@ -143,7 +143,7 @@ void WordSizeTransform::operator()(Block& _block)
|
||||
auto newRhs = expandValue(*varDecl.value);
|
||||
auto newLhs = generateU64IdentifierNames(varDecl.variables[0].name);
|
||||
vector<Statement> ret;
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (size_t i = 0; i < 4; i++)
|
||||
ret.emplace_back(VariableDeclaration{
|
||||
varDecl.location,
|
||||
{TypedName{varDecl.location, newLhs[i], m_targetDialect.defaultType}},
|
||||
@ -172,7 +172,7 @@ void WordSizeTransform::operator()(Block& _block)
|
||||
yulAssert(assignment.variableNames.size() == 1, "");
|
||||
auto newLhs = generateU64IdentifierNames(assignment.variableNames[0].name);
|
||||
vector<Statement> ret;
|
||||
for (int i = 0; i < 3; i++)
|
||||
for (size_t i = 0; i < 3; i++)
|
||||
ret.emplace_back(Assignment{
|
||||
assignment.location,
|
||||
{Identifier{assignment.location, newLhs[i]}},
|
||||
@ -203,7 +203,7 @@ void WordSizeTransform::operator()(Block& _block)
|
||||
auto newRhs = expandValue(*assignment.value);
|
||||
YulString lhsName = assignment.variableNames[0].name;
|
||||
vector<Statement> ret;
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (size_t i = 0; i < 4; i++)
|
||||
ret.emplace_back(Assignment{
|
||||
assignment.location,
|
||||
{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)
|
||||
{
|
||||
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)});
|
||||
return m_variableMapping[_s];
|
||||
}
|
||||
@ -392,19 +392,20 @@ array<unique_ptr<Expression>, 4> WordSizeTransform::expandValue(Expression const
|
||||
array<unique_ptr<Expression>, 4> ret;
|
||||
if (holds_alternative<Identifier>(_e))
|
||||
{
|
||||
Identifier const& id = std::get<Identifier>(_e);
|
||||
for (int i = 0; i < 4; i++)
|
||||
auto const& id = std::get<Identifier>(_e);
|
||||
for (size_t i = 0; i < 4; i++)
|
||||
ret[i] = make_unique<Expression>(Identifier{id.location, m_variableMapping.at(id.name)[i]});
|
||||
}
|
||||
else if (holds_alternative<Literal>(_e))
|
||||
{
|
||||
Literal const& lit = std::get<Literal>(_e);
|
||||
auto const& lit = std::get<Literal>(_e);
|
||||
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();
|
||||
val >>= 64;
|
||||
ret[i] = make_unique<Expression>(
|
||||
ret[exprIndexReverse] = make_unique<Expression>(
|
||||
Literal{
|
||||
lit.location,
|
||||
LiteralKind::Number,
|
||||
@ -426,4 +427,3 @@ vector<Expression> WordSizeTransform::expandValueToVector(Expression const& _e)
|
||||
ret.emplace_back(std::move(*val));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -51,10 +51,10 @@ void DeadCodeEliminator::operator()(Block& _block)
|
||||
tie(controlFlowChange, index) = TerminationFinder{m_dialect}.firstUnconditionalControlFlowChange(_block.statements);
|
||||
|
||||
// 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(
|
||||
remove_if(
|
||||
_block.statements.begin() + index + 1,
|
||||
_block.statements.begin() + static_cast<ptrdiff_t>(index) + 1,
|
||||
_block.statements.end(),
|
||||
[] (Statement const& _s) { return !holds_alternative<yul::FunctionDefinition>(_s); }
|
||||
),
|
||||
@ -63,4 +63,3 @@ void DeadCodeEliminator::operator()(Block& _block)
|
||||
|
||||
ASTModifier::operator()(_block);
|
||||
}
|
||||
|
||||
|
@ -119,7 +119,7 @@ void ExpressionJoiner::decrementLatestStatementPointer()
|
||||
void ExpressionJoiner::resetLatestStatementPointer()
|
||||
{
|
||||
m_currentBlock = nullptr;
|
||||
m_latestStatementInBlock = size_t(-1);
|
||||
m_latestStatementInBlock = numeric_limits<size_t>::max();
|
||||
}
|
||||
|
||||
Statement* ExpressionJoiner::latestStatement()
|
||||
|
@ -180,7 +180,7 @@ pair<TerminationFinder::ControlFlow, size_t> TerminationFinder::firstUncondition
|
||||
if (controlFlow != ControlFlow::FlowOut)
|
||||
return {controlFlow, i};
|
||||
}
|
||||
return {ControlFlow::FlowOut, size_t(-1)};
|
||||
return {ControlFlow::FlowOut, numeric_limits<size_t>::max()};
|
||||
}
|
||||
|
||||
TerminationFinder::ControlFlow TerminationFinder::controlFlowKind(Statement const& _statement)
|
||||
|
@ -178,14 +178,14 @@ bool StackCompressor::run(
|
||||
eliminateVariables(
|
||||
_dialect,
|
||||
std::get<Block>(_object.code->statements.at(0)),
|
||||
stackSurplus.at({}),
|
||||
static_cast<size_t>(stackSurplus.at({})),
|
||||
allowMSizeOptimzation
|
||||
);
|
||||
}
|
||||
|
||||
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))
|
||||
continue;
|
||||
|
||||
@ -193,7 +193,7 @@ bool StackCompressor::run(
|
||||
eliminateVariables(
|
||||
_dialect,
|
||||
fun,
|
||||
stackSurplus.at(fun.name),
|
||||
static_cast<size_t>(stackSurplus.at(fun.name)),
|
||||
allowMSizeOptimzation
|
||||
);
|
||||
}
|
||||
|
@ -34,5 +34,5 @@ else
|
||||
BUILD_DIR="$1"
|
||||
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
|
||||
|
@ -177,6 +177,7 @@ static string const g_strVersion = "version";
|
||||
static string const g_strIgnoreMissingFiles = "ignore-missing";
|
||||
static string const g_strColor = "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_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_argColor = g_strColor;
|
||||
static string const g_argNoColor = g_strNoColor;
|
||||
static string const g_argErrorIds = g_strErrorIds;
|
||||
static string const g_argOldReporter = g_strOldReporter;
|
||||
|
||||
/// Possible arguments to for --combined-json
|
||||
@ -878,6 +880,10 @@ General Information)").c_str(),
|
||||
g_argNoColor.c_str(),
|
||||
"Explicitly disable colored output, disabling terminal auto-detection."
|
||||
)
|
||||
(
|
||||
g_argErrorIds.c_str(),
|
||||
"Output error codes."
|
||||
)
|
||||
(
|
||||
g_argOldReporter.c_str(),
|
||||
"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_withErrorIds = m_args.count(g_argErrorIds);
|
||||
|
||||
if (m_args.count(g_argHelp) || (isatty(fileno(stdin)) && _argc == 1))
|
||||
{
|
||||
sout() << desc;
|
||||
@ -1296,7 +1304,7 @@ bool CommandLineInterface::processInput()
|
||||
if (m_args.count(g_argOldReporter))
|
||||
formatter = make_unique<SourceReferenceFormatter>(serr(false));
|
||||
else
|
||||
formatter = make_unique<SourceReferenceFormatterHuman>(serr(false), m_coloredOutput);
|
||||
formatter = make_unique<SourceReferenceFormatterHuman>(serr(false), m_coloredOutput, m_withErrorIds);
|
||||
|
||||
try
|
||||
{
|
||||
@ -1735,7 +1743,7 @@ bool CommandLineInterface::assemble(
|
||||
if (m_args.count(g_argOldReporter))
|
||||
formatter = make_unique<SourceReferenceFormatter>(serr(false));
|
||||
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())
|
||||
{
|
||||
|
@ -131,6 +131,8 @@ private:
|
||||
CompilerStack::MetadataHash m_metadataHash = CompilerStack::MetadataHash::IPFS;
|
||||
/// Whether or not to colorize diagnostics output.
|
||||
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"
|
||||
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 (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/ Consider adding "pragma .*$//' "$stderr_path"
|
||||
# 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!
|
||||
","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":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure
|
||||
{"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","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","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); } }
|
||||
^------------------------------------------^
|
||||
","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!
|
||||
","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":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure
|
||||
{"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","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","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); } }
|
||||
^------------------------------------------^
|
||||
","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!
|
||||
","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":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure
|
||||
{"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","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","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); } }
|
||||
^------------------------------------------^
|
||||
","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!
|
||||
","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":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure
|
||||
{"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","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","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); } }
|
||||
^------------------------------------------^
|
||||
","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}}}
|
||||
|
@ -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!
|
||||
","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
|
||||
{"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","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); } }
|
||||
^------------------------------------------^
|
||||
","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}}}
|
||||
|
@ -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 */ }
|
||||
^
|
||||
","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 */ }
|
||||
^
|
||||
","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 \".\";
|
||||
^------------------^
|
||||
","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}}}
|
||||
|
@ -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 {}
|
||||
^-------------------^
|
||||
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}}}
|
||||
|
@ -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}}}
|
||||
|
@ -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}}}
|
||||
|
@ -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}}}
|
||||
|
@ -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}}}
|
||||
|
@ -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}}}
|
||||
|
@ -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}}}
|
||||
|
@ -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}}}
|
||||
|
@ -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}}}
|
||||
|
@ -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}}}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user