Merge pull request #9186 from ethereum/develop

Merge develop into release for 0.6.10
This commit is contained in:
chriseth 2020-06-11 15:11:19 +02:00 committed by GitHub
commit 00c0fcaffd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
146 changed files with 1692 additions and 648 deletions

View File

@ -10,7 +10,7 @@ include(EthPolicy)
eth_policy() eth_policy()
# project name and version should be set after cmake_policy CMP0048 # project name and version should be set after cmake_policy CMP0048
set(PROJECT_VERSION "0.6.9") set(PROJECT_VERSION "0.6.10")
# OSX target needed in order to support std::visit # OSX target needed in order to support std::visit
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14") set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14")
project(solidity VERSION ${PROJECT_VERSION} LANGUAGES C CXX) project(solidity VERSION ${PROJECT_VERSION} LANGUAGES C CXX)

View File

@ -1,3 +1,22 @@
### 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) ### 0.6.9 (2020-06-04)
Language Features: Language Features:

View File

@ -6,9 +6,8 @@
- [ ] Readthedocs account, access to the Solidity project - [ ] Readthedocs account, access to the Solidity project
- [ ] Write access to https://github.com/ethereum/homebrew-ethereum - [ ] Write access to https://github.com/ethereum/homebrew-ethereum
### Pre-release ### Blog Post
- [ ] Ensure that a Github project exists for the release. - [ ] Create a post on https://github.com/ethereum/solidity-blog and explain some of the new features or concepts.
- [ ] Check that all issues and pull requests from the Github project to be released are merged to ``develop``.
### Changelog ### Changelog
- [ ] Sort the changelog entries alphabetically and correct any errors you notice. - [ ] Sort the changelog entries alphabetically and correct any errors you notice.
@ -33,8 +32,9 @@
- [ ] Wait for the ``~ethereum/ubuntu/ethereum-static`` PPA build to be finished and published for *all platforms*. SERIOUSLY: DO NOT PROCEED EARLIER!!! *After* the static builds are *published*, copy the static package to the ``~ethereum/ubuntu/ethereum`` PPA for the destination series ``Trusty`` and ``Xenial`` while selecting ``Copy existing binaries``. - [ ] Wait for the ``~ethereum/ubuntu/ethereum-static`` PPA build to be finished and published for *all platforms*. SERIOUSLY: DO NOT PROCEED EARLIER!!! *After* the static builds are *published*, copy the static package to the ``~ethereum/ubuntu/ethereum`` PPA for the destination series ``Trusty`` and ``Xenial`` while selecting ``Copy existing binaries``.
- [ ] Check that the Docker release was pushed to Docker Hub (this still seems to have problems, run ``./scripts/docker_deploy_manual.sh v0.x.x``). - [ ] Check that the Docker release was pushed to Docker Hub (this still seems to have problems, run ``./scripts/docker_deploy_manual.sh v0.x.x``).
### Homebrew ### Homebrew and MacOS
- [ ] Update the version and the hash (``sha256sum solidity_x.x.x.tar.gz``) in https://github.com/ethereum/homebrew-ethereum/blob/master/solidity.rb - [ ] Update the version and the hash (``sha256sum solidity_x.x.x.tar.gz``) in https://github.com/ethereum/homebrew-ethereum/blob/master/solidity.rb
- [ ] Take the binary from the ``b_osx`` run of the released commit in circle-ci and add it to the release page as ``solc-macos``.
### Documentation ### Documentation
- [ ] Build the new version on https://readthedocs.org/projects/solidity/ (select `latest` on the bottom of the page and click `BUILD`) - [ ] Build the new version on https://readthedocs.org/projects/solidity/ (select `latest` on the bottom of the page and click `BUILD`)

View File

@ -42,7 +42,8 @@ For most of the topics the compiler will provide suggestions.
storage arrays. storage arrays.
* The new keyword ``abstract`` can be used to mark contracts as abstract. It has to be used * The new keyword ``abstract`` can be used to mark contracts as abstract. It has to be used
if a contract does not implement all its functions. if a contract does not implement all its functions. Abstract contracts cannot be created using the ``new`` operator,
and it is not possible to generate bytecode for them during compilation.
* Libraries have to implement all their functions, not only the internal ones. * Libraries have to implement all their functions, not only the internal ones.

View File

@ -124,7 +124,11 @@ userDefinedTypeName
: identifier ( '.' identifier )* ; : identifier ( '.' identifier )* ;
mapping mapping
: 'mapping' '(' (elementaryTypeName | userDefinedTypeName) '=>' typeName ')' ; : 'mapping' '(' mappingKey '=>' typeName ')' ;
mappingKey
: elementaryTypeName
| userDefinedTypeName ;
functionTypeName functionTypeName
: 'function' parameterList modifierList returnParameters? ; : 'function' parameterList modifierList returnParameters? ;
@ -470,7 +474,7 @@ SingleQuotedStringCharacter
: ~['\r\n\\] | ('\\' .) ; : ~['\r\n\\] | ('\\' .) ;
VersionLiteral VersionLiteral
: [0-9]+ '.' [0-9]+ ('.' [0-9]+)? ; : [0-9]+ ( '.' [0-9]+ ('.' [0-9]+)? )? ;
WS WS
: [ \t\r\n\u000C]+ -> skip ; : [ \t\r\n\u000C]+ -> skip ;

View File

@ -24,7 +24,7 @@ Function Selector
================= =================
The first four bytes of the call data for a function call specifies the function to be called. It is the The first four bytes of the call data for a function call specifies the function to be called. It is the
first (left, high-order in big-endian) four bytes of the Keccak-256 (SHA-3) hash of the signature of first (left, high-order in big-endian) four bytes of the Keccak-256 hash of the signature of
the function. The signature is defined as the canonical expression of the basic prototype without data the function. The signature is defined as the canonical expression of the basic prototype without data
location specifier, i.e. location specifier, i.e.
the function name with the parenthesised list of parameter types. Parameter types are split by a single the function name with the parenthesised list of parameter types. Parameter types are split by a single

View File

@ -1,4 +1,12 @@
[ [
{
"name": "UsingForCalldata",
"summary": "Function calls to internal library functions with calldata parameters called via ``using for`` can result in invalid data being read.",
"description": "Function calls to internal library functions using the ``using for`` mechanism copied all calldata parameters to memory first and passed them on like that, regardless of whether it was an internal or an external call. Due to that, the called function would receive a memory pointer that is interpreted as a calldata pointer. Since dynamically sized arrays are passed using two stack slots for calldata, but only one for memory, this can lead to stack corruption. An affected library call will consider the JUMPDEST to which it is supposed to return as part of its arguments and will instead jump out to whatever was on the stack before the call.",
"introduced": "0.6.9",
"fixed": "0.6.10",
"severity": "very low"
},
{ {
"name": "MissingEscapingInFormatting", "name": "MissingEscapingInFormatting",
"summary": "String literals containing double backslash characters passed directly to external or encoding function calls can lead to a different string being used when ABIEncoderV2 is enabled.", "summary": "String literals containing double backslash characters passed directly to external or encoding function calls can lead to a different string being used when ABIEncoderV2 is enabled.",

View File

@ -1105,6 +1105,10 @@
], ],
"released": "2020-01-02" "released": "2020-01-02"
}, },
"0.6.10": {
"bugs": [],
"released": "2020-06-11"
},
"0.6.2": { "0.6.2": {
"bugs": [ "bugs": [
"MissingEscapingInFormatting", "MissingEscapingInFormatting",
@ -1165,7 +1169,9 @@
"released": "2020-05-14" "released": "2020-05-14"
}, },
"0.6.9": { "0.6.9": {
"bugs": [], "bugs": [
"UsingForCalldata"
],
"released": "2020-06-04" "released": "2020-06-04"
} }
} }

View File

@ -194,10 +194,10 @@ not known in the context of the class where it is used,
although its type is known. This is similar for ordinary although its type is known. This is similar for ordinary
virtual method lookup. virtual method lookup.
.. _function-overriding:
.. index:: ! overriding;function .. index:: ! overriding;function
.. _function-overriding:
Function Overriding Function Overriding
=================== ===================
@ -317,10 +317,10 @@ of the variable:
While public state variables can override external functions, they themselves cannot While public state variables can override external functions, they themselves cannot
be overridden. be overridden.
.. _modifier-overriding:
.. index:: ! overriding;modifier .. index:: ! overriding;modifier
.. _modifier-overriding:
Modifier Overriding Modifier Overriding
=================== ===================

View File

@ -430,7 +430,13 @@ Array slices are useful to ABI-decode secondary data passed in function paramete
/// Forward call to "setOwner(address)" that is implemented by client /// Forward call to "setOwner(address)" that is implemented by client
/// after doing basic validation on the address argument. /// after doing basic validation on the address argument.
function forward(bytes calldata _payload) external { function forward(bytes calldata _payload) external {
bytes4 sig = abi.decode(_payload[:4], (bytes4)); // Since ABI decoding requires padded data, we cannot
// use abi.decode(_payload[:4], (bytes4)).
bytes4 sig =
_payload[0] |
(bytes4(_payload[1]) >> 8) |
(bytes4(_payload[2]) >> 16) |
(bytes4(_payload[3]) >> 24);
if (sig == bytes4(keccak256("setOwner(address)"))) { if (sig == bytes4(keccak256("setOwner(address)"))) {
address owner = abi.decode(_payload[4:], (address)); address owner = abi.decode(_payload[4:], (address));
require(owner != address(0), "Address of owner cannot be zero."); require(owner != address(0), "Address of owner cannot be zero.");

View File

@ -374,8 +374,10 @@ Output Description
"component": "general", "component": "general",
// Mandatory ("error" or "warning") // Mandatory ("error" or "warning")
"severity": "error", "severity": "error",
// Optional: unique code for the cause of the error
"errorCode": "3141",
// Mandatory // Mandatory
"message": "Invalid keyword" "message": "Invalid keyword",
// Optional: the message formatted with source location // Optional: the message formatted with source location
"formattedMessage": "sourceFile.sol:100: Invalid keyword" "formattedMessage": "sourceFile.sol:100: Invalid keyword"
} }

View File

@ -38,7 +38,15 @@ SourceReferenceExtractor::Message SourceReferenceExtractor::extract(util::Except
for (auto const& info: secondaryLocation->infos) for (auto const& info: secondaryLocation->infos)
secondary.emplace_back(extract(&info.second, info.first)); secondary.emplace_back(extract(&info.second, info.first));
return Message{std::move(primary), _category, std::move(secondary)}; return Message{std::move(primary), _category, std::move(secondary), nullopt};
}
SourceReferenceExtractor::Message SourceReferenceExtractor::extract(Error const& _error)
{
string category = (_error.type() == Error::Type::Warning) ? "Warning" : "Error";
Message message = extract(_error, category);
message.errorId = _error.errorId();
return message;
} }
SourceReference SourceReferenceExtractor::extract(SourceLocation const* _location, std::string message) SourceReference SourceReferenceExtractor::extract(SourceLocation const* _location, std::string message)

View File

@ -16,16 +16,14 @@
*/ */
#pragma once #pragma once
#include <liblangutil/Exceptions.h>
#include <iosfwd> #include <iosfwd>
#include <optional>
#include <string> #include <string>
#include <tuple> #include <tuple>
#include <vector> #include <vector>
namespace solidity::util
{
struct Exception;
}
namespace solidity::langutil namespace solidity::langutil
{ {
@ -58,8 +56,6 @@ struct SourceReference
} }
}; };
struct SourceLocation;
namespace SourceReferenceExtractor namespace SourceReferenceExtractor
{ {
struct Message struct Message
@ -67,9 +63,11 @@ namespace SourceReferenceExtractor
SourceReference primary; SourceReference primary;
std::string category; // "Error", "Warning", ... std::string category; // "Error", "Warning", ...
std::vector<SourceReference> secondary; std::vector<SourceReference> secondary;
std::optional<ErrorId> errorId;
}; };
Message extract(util::Exception const& _exception, std::string _category); Message extract(util::Exception const& _exception, std::string _category);
Message extract(Error const& _error);
SourceReference extract(SourceLocation const* _location, std::string message = ""); SourceReference extract(SourceLocation const* _location, std::string message = "");
} }

View File

@ -80,10 +80,7 @@ void SourceReferenceFormatter::printExceptionInformation(util::Exception const&
void SourceReferenceFormatter::printErrorInformation(Error const& _error) void SourceReferenceFormatter::printErrorInformation(Error const& _error)
{ {
printExceptionInformation( printExceptionInformation(SourceReferenceExtractor::extract(_error));
_error,
(_error.type() == Error::Type::Warning) ? "Warning" : "Error"
);
} }
void SourceReferenceFormatter::printExceptionInformation(SourceReferenceExtractor::Message const& _msg) void SourceReferenceFormatter::printExceptionInformation(SourceReferenceExtractor::Message const& _msg)

View File

@ -151,6 +151,8 @@ void SourceReferenceFormatterHuman::printExceptionInformation(SourceReferenceExt
{ {
// exception header line // exception header line
errorColored() << _msg.category; errorColored() << _msg.category;
if (m_withErrorIds && _msg.errorId.has_value())
errorColored() << " (" << _msg.errorId.value().error << ")";
messageColored() << ": " << _msg.primary.message << '\n'; messageColored() << ": " << _msg.primary.message << '\n';
printSourceLocation(_msg.primary); printSourceLocation(_msg.primary);

View File

@ -29,22 +29,14 @@
#include <sstream> #include <sstream>
#include <functional> #include <functional>
namespace solidity::util
{
struct Exception; // forward
}
namespace solidity::langutil namespace solidity::langutil
{ {
struct SourceLocation;
struct SourceReference;
class SourceReferenceFormatterHuman: public SourceReferenceFormatter class SourceReferenceFormatterHuman: public SourceReferenceFormatter
{ {
public: public:
SourceReferenceFormatterHuman(std::ostream& _stream, bool colored): SourceReferenceFormatterHuman(std::ostream& _stream, bool _colored, bool _withErrorIds):
SourceReferenceFormatter{_stream}, m_colored{colored} SourceReferenceFormatter{_stream}, m_colored{_colored}, m_withErrorIds(_withErrorIds)
{} {}
void printSourceLocation(SourceReference const& _ref) override; void printSourceLocation(SourceReference const& _ref) override;
@ -54,12 +46,13 @@ public:
static std::string formatExceptionInformation( static std::string formatExceptionInformation(
util::Exception const& _exception, util::Exception const& _exception,
std::string const& _name, std::string const& _name,
bool colored = false bool _colored = false,
bool _withErrorIds = false
) )
{ {
std::ostringstream errorOutput; std::ostringstream errorOutput;
SourceReferenceFormatterHuman formatter(errorOutput, colored); SourceReferenceFormatterHuman formatter(errorOutput, _colored, _withErrorIds);
formatter.printExceptionInformation(_exception, _name); formatter.printExceptionInformation(_exception, _name);
return errorOutput.str(); return errorOutput.str();
} }
@ -75,6 +68,7 @@ private:
private: private:
bool m_colored; bool m_colored;
bool m_withErrorIds;
}; };
} }

View File

@ -68,7 +68,7 @@ struct OverrideGraph
std::map<OverrideProxy, int> nodes; std::map<OverrideProxy, int> nodes;
std::map<int, OverrideProxy> nodeInv; std::map<int, OverrideProxy> nodeInv;
std::map<int, std::set<int>> edges; std::map<int, std::set<int>> edges;
int numNodes = 2; size_t numNodes = 2;
void addEdge(int _a, int _b) void addEdge(int _a, int _b)
{ {
edges[_a].insert(_b); edges[_a].insert(_b);
@ -82,7 +82,7 @@ private:
auto it = nodes.find(_function); auto it = nodes.find(_function);
if (it != nodes.end()) if (it != nodes.end())
return it->second; return it->second;
int currentNode = numNodes++; int currentNode = static_cast<int>(numNodes++);
nodes[_function] = currentNode; nodes[_function] = currentNode;
nodeInv[currentNode] = _function; nodeInv[currentNode] = _function;
if (_function.overrides()) if (_function.overrides())
@ -116,21 +116,24 @@ private:
std::vector<int> m_parent = std::vector<int>(m_graph.numNodes, -1); std::vector<int> m_parent = std::vector<int>(m_graph.numNodes, -1);
std::set<OverrideProxy> m_cutVertices{}; std::set<OverrideProxy> m_cutVertices{};
void run(int _u = 0, int _depth = 0) void run(size_t _u = 0, size_t _depth = 0)
{ {
m_visited.at(_u) = true; m_visited.at(_u) = true;
m_depths.at(_u) = m_low.at(_u) = _depth; m_depths.at(_u) = m_low.at(_u) = static_cast<int>(_depth);
for (int v: m_graph.edges.at(_u)) for (int const v: m_graph.edges.at(static_cast<int>(_u)))
if (!m_visited.at(v)) {
auto const vInd = static_cast<size_t>(v);
if (!m_visited.at(vInd))
{ {
m_parent[v] = _u; m_parent[vInd] = static_cast<int>(_u);
run(v, _depth + 1); run(vInd, _depth + 1);
if (m_low[v] >= m_depths[_u] && m_parent[_u] != -1) if (m_low[vInd] >= m_depths[_u] && m_parent[_u] != -1)
m_cutVertices.insert(m_graph.nodeInv.at(_u)); m_cutVertices.insert(m_graph.nodeInv.at(static_cast<int>(_u)));
m_low[_u] = min(m_low[_u], m_low[v]); m_low[_u] = min(m_low[_u], m_low[vInd]);
} }
else if (v != m_parent[_u]) else if (v != m_parent[_u])
m_low[_u] = min(m_low[_u], m_depths[v]); m_low[_u] = min(m_low[_u], m_depths[vInd]);
}
} }
}; };
@ -213,7 +216,7 @@ bool OverrideProxy::CompareBySignature::operator()(OverrideProxy const& _a, Over
size_t OverrideProxy::id() const size_t OverrideProxy::id() const
{ {
return std::visit(GenericVisitor{ return std::visit(GenericVisitor{
[&](auto const* _item) -> size_t { return _item->id(); } [&](auto const* _item) -> size_t { return static_cast<size_t>(_item->id()); }
}, m_item); }, m_item);
} }

View File

@ -82,7 +82,7 @@ TypePointer const& TypeChecker::type(VariableDeclaration const& _variable) const
bool TypeChecker::visit(ContractDefinition const& _contract) bool TypeChecker::visit(ContractDefinition const& _contract)
{ {
m_scope = &_contract; m_currentContract = &_contract;
ASTNode::listAccept(_contract.baseContracts(), *this); ASTNode::listAccept(_contract.baseContracts(), *this);
@ -266,7 +266,7 @@ void TypeChecker::endVisit(InheritanceSpecifier const& _inheritance)
auto base = dynamic_cast<ContractDefinition const*>(&dereference(_inheritance.name())); auto base = dynamic_cast<ContractDefinition const*>(&dereference(_inheritance.name()));
solAssert(base, "Base contract not available."); solAssert(base, "Base contract not available.");
if (m_scope->isInterface() && !base->isInterface()) if (m_currentContract->isInterface() && !base->isInterface())
m_errorReporter.typeError(6536_error, _inheritance.location(), "Interfaces can only inherit from other interfaces."); m_errorReporter.typeError(6536_error, _inheritance.location(), "Interfaces can only inherit from other interfaces.");
if (base->isLibrary()) if (base->isLibrary())
@ -328,8 +328,6 @@ void TypeChecker::endVisit(ModifierDefinition const& _modifier)
bool TypeChecker::visit(FunctionDefinition const& _function) bool TypeChecker::visit(FunctionDefinition const& _function)
{ {
bool isLibraryFunction = _function.inContractKind() == ContractKind::Library;
if (_function.markedVirtual()) if (_function.markedVirtual())
{ {
if (_function.annotation().contract->isInterface()) if (_function.annotation().contract->isInterface())
@ -340,7 +338,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
if (_function.isPayable()) if (_function.isPayable())
{ {
if (isLibraryFunction) if (_function.libraryFunction())
m_errorReporter.typeError(7708_error, _function.location(), "Library functions cannot be payable."); m_errorReporter.typeError(7708_error, _function.location(), "Library functions cannot be payable.");
if (_function.isOrdinary() && !_function.isPartOfExternalInterface()) if (_function.isOrdinary() && !_function.isPartOfExternalInterface())
m_errorReporter.typeError(5587_error, _function.location(), "Internal functions cannot be payable."); m_errorReporter.typeError(5587_error, _function.location(), "Internal functions cannot be payable.");
@ -350,15 +348,13 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
{ {
if (var.referenceLocation() != VariableDeclaration::Location::Storage) if (var.referenceLocation() != VariableDeclaration::Location::Storage)
{ {
if (!isLibraryFunction && _function.isPublic()) if (!_function.libraryFunction() && _function.isPublic())
m_errorReporter.typeError(3442_error, var.location(), "Mapping types can only have a data location of \"storage\" and thus only be parameters or return variables for internal or library functions."); m_errorReporter.typeError(3442_error, var.location(), "Mapping types can only have a data location of \"storage\" and thus only be parameters or return variables for internal or library functions.");
else else
m_errorReporter.typeError(5380_error, var.location(), "Mapping types can only have a data location of \"storage\"." ); m_errorReporter.typeError(5380_error, var.location(), "Mapping types can only have a data location of \"storage\"." );
} }
else else
{ solAssert(_function.libraryFunction() || !_function.isPublic(), "Mapping types for parameters or return variables can only be used in internal or library functions.");
solAssert(isLibraryFunction || !_function.isPublic(), "Mapping types for parameters or return variables can only be used in internal or library functions.");
}
} }
else else
{ {
@ -366,7 +362,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
m_errorReporter.typeError(3312_error, var.location(), "Type is required to live outside storage."); m_errorReporter.typeError(3312_error, var.location(), "Type is required to live outside storage.");
if (_function.isPublic()) if (_function.isPublic())
{ {
auto iType = type(var)->interfaceType(isLibraryFunction); auto iType = type(var)->interfaceType(_function.libraryFunction());
if (!iType) if (!iType)
{ {
@ -378,7 +374,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
if ( if (
_function.isPublic() && _function.isPublic() &&
!_function.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2) && !_function.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2) &&
!typeSupportedByOldABIEncoder(*type(var), isLibraryFunction) !typeSupportedByOldABIEncoder(*type(var), _function.libraryFunction())
) )
m_errorReporter.typeError( m_errorReporter.typeError(
4957_error, 4957_error,
@ -417,7 +413,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
else else
modifiers.insert(decl); modifiers.insert(decl);
} }
if (m_scope->isInterface()) if (m_currentContract->isInterface())
{ {
if (_function.isImplemented()) if (_function.isImplemented())
m_errorReporter.typeError(4726_error, _function.location(), "Functions in interfaces cannot have an implementation."); m_errorReporter.typeError(4726_error, _function.location(), "Functions in interfaces cannot have an implementation.");
@ -428,14 +424,14 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
if (_function.isConstructor()) if (_function.isConstructor())
m_errorReporter.typeError(6482_error, _function.location(), "Constructor cannot be defined in interfaces."); m_errorReporter.typeError(6482_error, _function.location(), "Constructor cannot be defined in interfaces.");
} }
else if (m_scope->contractKind() == ContractKind::Library) else if (m_currentContract->contractKind() == ContractKind::Library)
if (_function.isConstructor()) if (_function.isConstructor())
m_errorReporter.typeError(7634_error, _function.location(), "Constructor cannot be defined in libraries."); m_errorReporter.typeError(7634_error, _function.location(), "Constructor cannot be defined in libraries.");
if (_function.isImplemented()) if (_function.isImplemented())
_function.body().accept(*this); _function.body().accept(*this);
else if (_function.isConstructor()) else if (_function.isConstructor())
m_errorReporter.typeError(5700_error, _function.location(), "Constructor must be implemented if declared."); m_errorReporter.typeError(5700_error, _function.location(), "Constructor must be implemented if declared.");
else if (isLibraryFunction) else if (_function.libraryFunction())
m_errorReporter.typeError(9231_error, _function.location(), "Library functions must be implemented if declared."); m_errorReporter.typeError(9231_error, _function.location(), "Library functions must be implemented if declared.");
else if (!_function.virtualSemantics()) else if (!_function.virtualSemantics())
m_errorReporter.typeError(5424_error, _function.location(), "Functions without implementation must be marked virtual."); m_errorReporter.typeError(5424_error, _function.location(), "Functions without implementation must be marked virtual.");
@ -670,7 +666,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
{ {
auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier); auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier);
if (ref == _inlineAssembly.annotation().externalReferences.end()) if (ref == _inlineAssembly.annotation().externalReferences.end())
return size_t(-1); return numeric_limits<size_t>::max();
Declaration const* declaration = ref->second.declaration; Declaration const* declaration = ref->second.declaration;
solAssert(!!declaration, ""); solAssert(!!declaration, "");
bool requiresStorage = ref->second.isSlot || ref->second.isOffset; bool requiresStorage = ref->second.isSlot || ref->second.isOffset;
@ -680,7 +676,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
if (var->immutable()) if (var->immutable())
{ {
m_errorReporter.typeError(3773_error, _identifier.location, "Assembly access to immutable variables is not supported."); m_errorReporter.typeError(3773_error, _identifier.location, "Assembly access to immutable variables is not supported.");
return size_t(-1); return numeric_limits<size_t>::max();
} }
if (var->isConstant()) if (var->isConstant())
{ {
@ -689,17 +685,17 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
if (var && !var->value()) if (var && !var->value())
{ {
m_errorReporter.typeError(3224_error, _identifier.location, "Constant has no value."); m_errorReporter.typeError(3224_error, _identifier.location, "Constant has no value.");
return size_t(-1); return numeric_limits<size_t>::max();
} }
else if (_context == yul::IdentifierContext::LValue) else if (_context == yul::IdentifierContext::LValue)
{ {
m_errorReporter.typeError(6252_error, _identifier.location, "Constant variables cannot be assigned to."); m_errorReporter.typeError(6252_error, _identifier.location, "Constant variables cannot be assigned to.");
return size_t(-1); return numeric_limits<size_t>::max();
} }
else if (requiresStorage) else if (requiresStorage)
{ {
m_errorReporter.typeError(6617_error, _identifier.location, "The suffixes _offset and _slot can only be used on non-constant storage variables."); m_errorReporter.typeError(6617_error, _identifier.location, "The suffixes _offset and _slot can only be used on non-constant storage variables.");
return size_t(-1); return numeric_limits<size_t>::max();
} }
else if (var && var->value() && !var->value()->annotation().type && !dynamic_cast<Literal const*>(var->value().get())) else if (var && var->value() && !var->value()->annotation().type && !dynamic_cast<Literal const*>(var->value().get()))
{ {
@ -727,19 +723,19 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
if (!var->isStateVariable() && !var->type()->dataStoredIn(DataLocation::Storage)) if (!var->isStateVariable() && !var->type()->dataStoredIn(DataLocation::Storage))
{ {
m_errorReporter.typeError(3622_error, _identifier.location, "The suffixes _offset and _slot can only be used on storage variables."); m_errorReporter.typeError(3622_error, _identifier.location, "The suffixes _offset and _slot can only be used on storage variables.");
return size_t(-1); return numeric_limits<size_t>::max();
} }
else if (_context == yul::IdentifierContext::LValue) else if (_context == yul::IdentifierContext::LValue)
{ {
if (var->isStateVariable()) if (var->isStateVariable())
{ {
m_errorReporter.typeError(4713_error, _identifier.location, "State variables cannot be assigned to - you have to use \"sstore()\"."); m_errorReporter.typeError(4713_error, _identifier.location, "State variables cannot be assigned to - you have to use \"sstore()\".");
return size_t(-1); return numeric_limits<size_t>::max();
} }
else if (ref->second.isOffset) else if (ref->second.isOffset)
{ {
m_errorReporter.typeError(9739_error, _identifier.location, "Only _slot can be assigned to."); m_errorReporter.typeError(9739_error, _identifier.location, "Only _slot can be assigned to.");
return size_t(-1); return numeric_limits<size_t>::max();
} }
else else
solAssert(ref->second.isSlot, ""); solAssert(ref->second.isSlot, "");
@ -748,12 +744,12 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
else if (!var->isConstant() && var->isStateVariable()) else if (!var->isConstant() && var->isStateVariable())
{ {
m_errorReporter.typeError(1408_error, _identifier.location, "Only local variables are supported. To access storage variables, use the _slot and _offset suffixes."); m_errorReporter.typeError(1408_error, _identifier.location, "Only local variables are supported. To access storage variables, use the _slot and _offset suffixes.");
return size_t(-1); return numeric_limits<size_t>::max();
} }
else if (var->type()->dataStoredIn(DataLocation::Storage)) else if (var->type()->dataStoredIn(DataLocation::Storage))
{ {
m_errorReporter.typeError(9068_error, _identifier.location, "You have to use the _slot or _offset suffix to access storage reference variables."); m_errorReporter.typeError(9068_error, _identifier.location, "You have to use the _slot or _offset suffix to access storage reference variables.");
return size_t(-1); return numeric_limits<size_t>::max();
} }
else if (var->type()->sizeOnStack() != 1) else if (var->type()->sizeOnStack() != 1)
{ {
@ -761,21 +757,21 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
m_errorReporter.typeError(2370_error, _identifier.location, "Call data elements cannot be accessed directly. Copy to a local variable first or use \"calldataload\" or \"calldatacopy\" with manually determined offsets and sizes."); m_errorReporter.typeError(2370_error, _identifier.location, "Call data elements cannot be accessed directly. Copy to a local variable first or use \"calldataload\" or \"calldatacopy\" with manually determined offsets and sizes.");
else else
m_errorReporter.typeError(9857_error, _identifier.location, "Only types that use one stack slot are supported."); m_errorReporter.typeError(9857_error, _identifier.location, "Only types that use one stack slot are supported.");
return size_t(-1); return numeric_limits<size_t>::max();
} }
} }
else if (requiresStorage) else if (requiresStorage)
{ {
m_errorReporter.typeError(7944_error, _identifier.location, "The suffixes _offset and _slot can only be used on storage variables."); m_errorReporter.typeError(7944_error, _identifier.location, "The suffixes _offset and _slot can only be used on storage variables.");
return size_t(-1); return numeric_limits<size_t>::max();
} }
else if (_context == yul::IdentifierContext::LValue) else if (_context == yul::IdentifierContext::LValue)
{ {
if (dynamic_cast<MagicVariableDeclaration const*>(declaration)) if (dynamic_cast<MagicVariableDeclaration const*>(declaration))
return size_t(-1); return numeric_limits<size_t>::max();
m_errorReporter.typeError(1990_error, _identifier.location, "Only local variables can be assigned to in inline assembly."); m_errorReporter.typeError(1990_error, _identifier.location, "Only local variables can be assigned to in inline assembly.");
return size_t(-1); return numeric_limits<size_t>::max();
} }
if (_context == yul::IdentifierContext::RValue) if (_context == yul::IdentifierContext::RValue)
@ -784,7 +780,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
if (dynamic_cast<FunctionDefinition const*>(declaration)) if (dynamic_cast<FunctionDefinition const*>(declaration))
{ {
m_errorReporter.declarationError(2025_error, _identifier.location, "Access to functions is not allowed in inline assembly."); m_errorReporter.declarationError(2025_error, _identifier.location, "Access to functions is not allowed in inline assembly.");
return size_t(-1); return numeric_limits<size_t>::max();
} }
else if (dynamic_cast<VariableDeclaration const*>(declaration)) else if (dynamic_cast<VariableDeclaration const*>(declaration))
{ {
@ -794,11 +790,11 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
if (!contract->isLibrary()) if (!contract->isLibrary())
{ {
m_errorReporter.typeError(4977_error, _identifier.location, "Expected a library."); m_errorReporter.typeError(4977_error, _identifier.location, "Expected a library.");
return size_t(-1); return numeric_limits<size_t>::max();
} }
} }
else else
return size_t(-1); return numeric_limits<size_t>::max();
} }
ref->second.valueSize = 1; ref->second.valueSize = 1;
return size_t(1); return size_t(1);
@ -1794,7 +1790,7 @@ void TypeChecker::typeCheckFunctionCall(
if (_functionType->kind() == FunctionType::Kind::Declaration) if (_functionType->kind() == FunctionType::Kind::Declaration)
{ {
if ( if (
m_scope->derivesFrom(*_functionType->declaration().annotation().contract) && m_currentContract->derivesFrom(*_functionType->declaration().annotation().contract) &&
!dynamic_cast<FunctionDefinition const&>(_functionType->declaration()).isImplemented() !dynamic_cast<FunctionDefinition const&>(_functionType->declaration()).isImplemented()
) )
m_errorReporter.typeError( m_errorReporter.typeError(
@ -1830,7 +1826,7 @@ void TypeChecker::typeCheckFallbackFunction(FunctionDefinition const& _function)
{ {
solAssert(_function.isFallback(), ""); solAssert(_function.isFallback(), "");
if (_function.inContractKind() == ContractKind::Library) if (_function.libraryFunction())
m_errorReporter.typeError(5982_error, _function.location(), "Libraries cannot have fallback functions."); m_errorReporter.typeError(5982_error, _function.location(), "Libraries cannot have fallback functions.");
if (_function.stateMutability() != StateMutability::NonPayable && _function.stateMutability() != StateMutability::Payable) if (_function.stateMutability() != StateMutability::NonPayable && _function.stateMutability() != StateMutability::Payable)
m_errorReporter.typeError( m_errorReporter.typeError(
@ -1857,7 +1853,7 @@ void TypeChecker::typeCheckReceiveFunction(FunctionDefinition const& _function)
{ {
solAssert(_function.isReceive(), ""); solAssert(_function.isReceive(), "");
if (_function.inContractKind() == ContractKind::Library) if (_function.libraryFunction())
m_errorReporter.typeError(4549_error, _function.location(), "Libraries cannot have receive ether functions."); m_errorReporter.typeError(4549_error, _function.location(), "Libraries cannot have receive ether functions.");
if (_function.stateMutability() != StateMutability::Payable) if (_function.stateMutability() != StateMutability::Payable)
@ -1916,7 +1912,7 @@ void TypeChecker::typeCheckABIEncodeFunctions(
bool const isPacked = _functionType->kind() == FunctionType::Kind::ABIEncodePacked; bool const isPacked = _functionType->kind() == FunctionType::Kind::ABIEncodePacked;
solAssert(_functionType->padArguments() != isPacked, "ABI function with unexpected padding"); solAssert(_functionType->padArguments() != isPacked, "ABI function with unexpected padding");
bool const abiEncoderV2 = m_scope->sourceUnit().annotation().experimentalFeatures.count( bool const abiEncoderV2 = m_currentContract->sourceUnit().annotation().experimentalFeatures.count(
ExperimentalFeature::ABIEncoderV2 ExperimentalFeature::ABIEncoderV2
); );
@ -2316,7 +2312,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
case FunctionType::Kind::ABIDecode: case FunctionType::Kind::ABIDecode:
{ {
bool const abiEncoderV2 = bool const abiEncoderV2 =
m_scope->sourceUnit().annotation().experimentalFeatures.count( m_currentContract->sourceUnit().annotation().experimentalFeatures.count(
ExperimentalFeature::ABIEncoderV2 ExperimentalFeature::ABIEncoderV2
); );
returnTypes = typeCheckABIDecodeAndRetrieveReturnType(_functionCall, abiEncoderV2); returnTypes = typeCheckABIDecodeAndRetrieveReturnType(_functionCall, abiEncoderV2);
@ -2512,13 +2508,13 @@ void TypeChecker::endVisit(NewExpression const& _newExpression)
if (contract->abstract()) if (contract->abstract())
m_errorReporter.typeError(4614_error, _newExpression.location(), "Cannot instantiate an abstract contract."); m_errorReporter.typeError(4614_error, _newExpression.location(), "Cannot instantiate an abstract contract.");
solAssert(!!m_scope, ""); solAssert(!!m_currentContract, "");
m_scope->annotation().contractDependencies.insert(contract); m_currentContract->annotation().contractDependencies.insert(contract);
solAssert( solAssert(
!contract->annotation().linearizedBaseContracts.empty(), !contract->annotation().linearizedBaseContracts.empty(),
"Linearized base contracts not yet available." "Linearized base contracts not yet available."
); );
if (contractDependenciesAreCyclic(*m_scope)) if (contractDependenciesAreCyclic(*m_currentContract))
m_errorReporter.typeError( m_errorReporter.typeError(
4579_error, 4579_error,
_newExpression.location(), _newExpression.location(),
@ -2565,7 +2561,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
// Retrieve the types of the arguments if this is used to call a function. // Retrieve the types of the arguments if this is used to call a function.
auto const& arguments = _memberAccess.annotation().arguments; auto const& arguments = _memberAccess.annotation().arguments;
MemberList::MemberMap possibleMembers = exprType->members(m_scope).membersByName(memberName); MemberList::MemberMap possibleMembers = exprType->members(m_currentContract).membersByName(memberName);
size_t const initialMemberCount = possibleMembers.size(); size_t const initialMemberCount = possibleMembers.size();
if (initialMemberCount > 1 && arguments) if (initialMemberCount > 1 && arguments)
{ {
@ -2591,7 +2587,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
DataLocation::Storage, DataLocation::Storage,
exprType exprType
); );
if (!storageType->members(m_scope).membersByName(memberName).empty()) if (!storageType->members(m_currentContract).membersByName(memberName).empty())
m_errorReporter.fatalTypeError( m_errorReporter.fatalTypeError(
4994_error, 4994_error,
_memberAccess.location(), _memberAccess.location(),
@ -2747,7 +2743,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
{ {
annotation.isPure = true; annotation.isPure = true;
ContractType const& accessedContractType = dynamic_cast<ContractType const&>(*magicType->typeArgument()); ContractType const& accessedContractType = dynamic_cast<ContractType const&>(*magicType->typeArgument());
m_scope->annotation().contractDependencies.insert(&accessedContractType.contractDefinition()); m_currentContract->annotation().contractDependencies.insert(&accessedContractType.contractDefinition());
if ( if (
memberName == "runtimeCode" && memberName == "runtimeCode" &&
@ -2759,7 +2755,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
"\"runtimeCode\" is not available for contracts containing immutable variables." "\"runtimeCode\" is not available for contracts containing immutable variables."
); );
if (contractDependenciesAreCyclic(*m_scope)) if (contractDependenciesAreCyclic(*m_currentContract))
m_errorReporter.typeError( m_errorReporter.typeError(
4224_error, 4224_error,
_memberAccess.location(), _memberAccess.location(),

View File

@ -165,7 +165,7 @@ private:
/// Runs type checks on @a _expression to infer its type and then checks that it is an LValue. /// Runs type checks on @a _expression to infer its type and then checks that it is an LValue.
void requireLValue(Expression const& _expression, bool _ordinaryAssignment); void requireLValue(Expression const& _expression, bool _ordinaryAssignment);
ContractDefinition const* m_scope = nullptr; ContractDefinition const* m_currentContract = nullptr;
langutil::EVMVersion m_evmVersion; langutil::EVMVersion m_evmVersion;

View File

@ -276,7 +276,7 @@ void ViewPureChecker::reportMutability(
{ {
// We do not warn for library functions because they cannot be payable anyway. // We do not warn for library functions because they cannot be payable anyway.
// Also internal functions should be allowed to use `msg.value`. // Also internal functions should be allowed to use `msg.value`.
if (m_currentFunction->isPublic() && m_currentFunction->inContractKind() != ContractKind::Library) if (m_currentFunction->isPublic() && !m_currentFunction->libraryFunction())
{ {
if (_nestedLocation) if (_nestedLocation)
m_errorReporter.typeError( m_errorReporter.typeError(

View File

@ -38,7 +38,7 @@ using namespace solidity;
using namespace solidity::frontend; using namespace solidity::frontend;
ASTNode::ASTNode(int64_t _id, SourceLocation _location): ASTNode::ASTNode(int64_t _id, SourceLocation _location):
m_id(_id), m_id(static_cast<size_t>(_id)),
m_location(std::move(_location)) m_location(std::move(_location))
{ {
} }
@ -287,11 +287,11 @@ TypeDeclarationAnnotation& EnumDefinition::annotation() const
return initAnnotation<TypeDeclarationAnnotation>(); return initAnnotation<TypeDeclarationAnnotation>();
} }
ContractKind FunctionDefinition::inContractKind() const bool FunctionDefinition::libraryFunction() const
{ {
auto contractDef = dynamic_cast<ContractDefinition const*>(scope()); if (auto const* contractDef = dynamic_cast<ContractDefinition const*>(scope()))
solAssert(contractDef, "Enclosing Scope of FunctionDefinition was not set."); return contractDef->isLibrary();
return contractDef->contractKind(); return false;
} }
FunctionTypePointer FunctionDefinition::functionType(bool _internal) const FunctionTypePointer FunctionDefinition::functionType(bool _internal) const

View File

@ -88,7 +88,7 @@ public:
virtual ~ASTNode() {} virtual ~ASTNode() {}
/// @returns an identifier of this AST node that is unique for a single compilation run. /// @returns an identifier of this AST node that is unique for a single compilation run.
int64_t id() const { return m_id; } int64_t id() const { return int64_t(m_id); }
virtual void accept(ASTVisitor& _visitor) = 0; virtual void accept(ASTVisitor& _visitor) = 0;
virtual void accept(ASTConstVisitor& _visitor) const = 0; virtual void accept(ASTConstVisitor& _visitor) const = 0;
@ -799,6 +799,7 @@ public:
void accept(ASTConstVisitor& _visitor) const override; void accept(ASTConstVisitor& _visitor) const override;
StateMutability stateMutability() const { return m_stateMutability; } StateMutability stateMutability() const { return m_stateMutability; }
bool libraryFunction() const;
bool isOrdinary() const { return m_kind == Token::Function; } bool isOrdinary() const { return m_kind == Token::Function; }
bool isConstructor() const { return m_kind == Token::Constructor; } bool isConstructor() const { return m_kind == Token::Constructor; }
bool isFallback() const { return m_kind == Token::Fallback; } bool isFallback() const { return m_kind == Token::Fallback; }
@ -825,8 +826,6 @@ public:
/// @returns the external identifier of this function (the hash of the signature) as a hex string. /// @returns the external identifier of this function (the hash of the signature) as a hex string.
std::string externalIdentifierHex() const; std::string externalIdentifierHex() const;
ContractKind inContractKind() const;
TypePointer type() const override; TypePointer type() const override;
TypePointer typeViaContractName() const override; TypePointer typeViaContractName() const override;

View File

@ -37,6 +37,7 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <algorithm> #include <algorithm>
#include <limits>
using namespace std; using namespace std;
using namespace solidity::langutil; using namespace solidity::langutil;
@ -134,7 +135,7 @@ size_t ASTJsonConverter::sourceIndexFromLocation(SourceLocation const& _location
if (_location.source && m_sourceIndices.count(_location.source->name())) if (_location.source && m_sourceIndices.count(_location.source->name()))
return m_sourceIndices.at(_location.source->name()); return m_sourceIndices.at(_location.source->name());
else else
return size_t(-1); return numeric_limits<size_t>::max();
} }
string ASTJsonConverter::sourceLocationToString(SourceLocation const& _location) const string ASTJsonConverter::sourceLocationToString(SourceLocation const& _location) const

View File

@ -92,7 +92,7 @@ SourceLocation const ASTJsonImporter::createSourceLocation(Json::Value const& _n
{ {
astAssert(member(_node, "src").isString(), "'src' must be a string"); astAssert(member(_node, "src").isString(), "'src' must be a string");
return solidity::langutil::parseSourceLocation(_node["src"].asString(), m_currentSourceName, int(m_sourceLocations.size())); return solidity::langutil::parseSourceLocation(_node["src"].asString(), m_currentSourceName, m_sourceLocations.size());
} }
template<class T> template<class T>

View File

@ -112,14 +112,22 @@ public:
/// @returns a copy of @a _type having the same location as this (and is not a pointer type) /// @returns a copy of @a _type having the same location as this (and is not a pointer type)
/// if _type is a reference type and an unmodified copy of _type otherwise. /// if _type is a reference type and an unmodified copy of _type otherwise.
/// This function is mostly useful to modify inner types appropriately. /// This function is mostly useful to modify inner types appropriately.
static Type const* withLocationIfReference(DataLocation _location, Type const* _type) static Type const* withLocationIfReference(DataLocation _location, Type const* _type, bool _isPointer = false)
{ {
if (auto refType = dynamic_cast<ReferenceType const*>(_type)) if (auto refType = dynamic_cast<ReferenceType const*>(_type))
return withLocation(refType, _location, false); return withLocation(refType, _location, _isPointer);
return _type; return _type;
} }
static bool isReferenceWithLocation(Type const* _type, DataLocation _location)
{
if (auto const* refType = dynamic_cast<ReferenceType const*>(_type))
if (refType->location() == _location)
return true;
return false;
}
/// @returns the internally-facing or externally-facing type of a function or the type of a function declaration. /// @returns the internally-facing or externally-facing type of a function or the type of a function declaration.
static FunctionType const* function(FunctionDefinition const& _function, FunctionType::Kind _kind = FunctionType::Kind::Declaration); static FunctionType const* function(FunctionDefinition const& _function, FunctionType::Kind _kind = FunctionType::Kind::Declaration);

View File

@ -356,10 +356,18 @@ MemberList::MemberMap Type::boundFunctions(Type const& _type, ContractDefinition
for (ContractDefinition const* contract: _scope.annotation().linearizedBaseContracts) for (ContractDefinition const* contract: _scope.annotation().linearizedBaseContracts)
for (UsingForDirective const* ufd: contract->usingForDirectives()) for (UsingForDirective const* ufd: contract->usingForDirectives())
{ {
if (ufd->typeName() && _type != *TypeProvider::withLocationIfReference( // Convert both types to pointers for comparison to see if the `using for`
typeLocation, // directive applies.
ufd->typeName()->annotation().type // 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,
true
)
)
continue; continue;
auto const& library = dynamic_cast<ContractDefinition const&>( auto const& library = dynamic_cast<ContractDefinition const&>(
*ufd->libraryName().annotation().referencedDeclaration *ufd->libraryName().annotation().referencedDeclaration
@ -371,7 +379,8 @@ MemberList::MemberMap Type::boundFunctions(Type const& _type, ContractDefinition
seenFunctions.insert(function); seenFunctions.insert(function);
if (function->parameters().empty()) if (function->parameters().empty())
continue; continue;
FunctionTypePointer fun = FunctionType(*function, FunctionType::Kind::External).asExternallyCallableFunction(true, true); FunctionTypePointer fun =
dynamic_cast<FunctionType const&>(*function->typeViaContractName()).asBoundFunction();
if (_type.isImplicitlyConvertibleTo(*fun->selfType())) if (_type.isImplicitlyConvertibleTo(*fun->selfType()))
members.emplace_back(function->name(), fun, function); members.emplace_back(function->name(), fun, function);
} }
@ -773,7 +782,7 @@ tuple<bool, rational> RationalNumberType::parseRational(string const& _value)
denominator = bigint(string(fractionalBegin, _value.end())); denominator = bigint(string(fractionalBegin, _value.end()));
denominator /= boost::multiprecision::pow( denominator /= boost::multiprecision::pow(
bigint(10), bigint(10),
distance(radixPoint + 1, _value.end()) static_cast<size_t>(distance(radixPoint + 1, _value.end()))
); );
numerator = bigint(string(_value.begin(), radixPoint)); numerator = bigint(string(_value.begin(), radixPoint));
value = numerator + denominator; value = numerator + denominator;
@ -1065,7 +1074,7 @@ TypeResult RationalNumberType::binaryOperatorResult(Token _operator, Type const*
if (_base == 1) if (_base == 1)
return 1; return 1;
else if (_base == -1) else if (_base == -1)
return 1 - 2 * int(_exponent & 1); return 1 - 2 * static_cast<int>(_exponent & 1);
else else
return boost::multiprecision::pow(_base, _exponent); return boost::multiprecision::pow(_base, _exponent);
}; };
@ -1171,7 +1180,7 @@ string RationalNumberType::bigintToReadableString(bigint const& _num)
string str = _num.str(); string str = _num.str();
if (str.size() > 32) if (str.size() > 32)
{ {
int omitted = str.size() - 8; size_t omitted = str.size() - 8;
str = str.substr(0, 4) + "...(" + to_string(omitted) + " digits omitted)..." + str.substr(str.size() - 4, 4); str = str.substr(0, 4) + "...(" + to_string(omitted) + " digits omitted)..." + str.substr(str.size() - 4, 4);
} }
return str; return str;
@ -1201,7 +1210,7 @@ u256 RationalNumberType::literalValue(Literal const*) const
{ {
auto fixed = fixedPointType(); auto fixed = fixedPointType();
solAssert(fixed, "Rational number cannot be represented as fixed point type."); solAssert(fixed, "Rational number cannot be represented as fixed point type.");
int fractionalDigits = fixed->fractionalDigits(); unsigned fractionalDigits = fixed->fractionalDigits();
shiftedValue = m_value.numerator() * boost::multiprecision::pow(bigint(10), fractionalDigits) / m_value.denominator(); shiftedValue = m_value.numerator() * boost::multiprecision::pow(bigint(10), fractionalDigits) / m_value.denominator();
} }
@ -1291,7 +1300,7 @@ StringLiteralType::StringLiteralType(string _value):
BoolResult StringLiteralType::isImplicitlyConvertibleTo(Type const& _convertTo) const BoolResult StringLiteralType::isImplicitlyConvertibleTo(Type const& _convertTo) const
{ {
if (auto fixedBytes = dynamic_cast<FixedBytesType const*>(&_convertTo)) if (auto fixedBytes = dynamic_cast<FixedBytesType const*>(&_convertTo))
return size_t(fixedBytes->numBytes()) >= m_value.size(); return static_cast<size_t>(fixedBytes->numBytes()) >= m_value.size();
else if (auto arrayType = dynamic_cast<ArrayType const*>(&_convertTo)) else if (auto arrayType = dynamic_cast<ArrayType const*>(&_convertTo))
return return
arrayType->isByteArray() && arrayType->isByteArray() &&
@ -2457,6 +2466,21 @@ set<string> StructType::membersMissingInMemory() const
return missing; return missing;
} }
vector<tuple<string, TypePointer>> StructType::makeStackItems() const
{
switch (m_location)
{
case DataLocation::CallData:
return {std::make_tuple("offset", TypeProvider::uint256())};
case DataLocation::Memory:
return {std::make_tuple("mpos", TypeProvider::uint256())};
case DataLocation::Storage:
return {std::make_tuple("slot", TypeProvider::uint256())};
}
solAssert(false, "");
}
TypePointer EnumType::encodingType() const TypePointer EnumType::encodingType() const
{ {
return TypeProvider::uint(8 * storageBytes()); return TypeProvider::uint(8 * storageBytes());
@ -3438,34 +3462,61 @@ TypePointer FunctionType::copyAndSetCallOptions(bool _setGas, bool _setValue, bo
); );
} }
FunctionTypePointer FunctionType::asExternallyCallableFunction(bool _inLibrary, bool _bound) const FunctionTypePointer FunctionType::asBoundFunction() const
{ {
if (_bound) solAssert(!m_parameterTypes.empty(), "");
solAssert(!m_parameterTypes.empty(), ""); FunctionDefinition const* fun = dynamic_cast<FunctionDefinition const*>(m_declaration);
solAssert(fun && fun->libraryFunction(), "");
solAssert(!m_gasSet, "");
solAssert(!m_valueSet, "");
solAssert(!m_saltSet, "");
return TypeProvider::function(
m_parameterTypes,
m_returnParameterTypes,
m_parameterNames,
m_returnParameterNames,
m_kind,
m_arbitraryParameters,
m_stateMutability,
m_declaration,
m_gasSet,
m_valueSet,
m_saltSet,
true
);
}
FunctionTypePointer FunctionType::asExternallyCallableFunction(bool _inLibrary) const
{
TypePointers parameterTypes; TypePointers parameterTypes;
for (auto const& t: m_parameterTypes) for (auto const& t: m_parameterTypes)
{ if (TypeProvider::isReferenceWithLocation(t, DataLocation::CallData))
auto refType = dynamic_cast<ReferenceType const*>(t); parameterTypes.push_back(
if (refType && refType->location() == DataLocation::CallData) TypeProvider::withLocationIfReference(DataLocation::Memory, t, true)
parameterTypes.push_back(TypeProvider::withLocation(refType, DataLocation::Memory, true)); );
else else
parameterTypes.push_back(t); parameterTypes.push_back(t);
}
TypePointers returnParameterTypes;
for (auto const& returnParamType: m_returnParameterTypes)
if (TypeProvider::isReferenceWithLocation(returnParamType, DataLocation::CallData))
returnParameterTypes.push_back(
TypeProvider::withLocationIfReference(DataLocation::Memory, returnParamType, true)
);
else
returnParameterTypes.push_back(returnParamType);
Kind kind = m_kind; Kind kind = m_kind;
if (_inLibrary) if (_inLibrary)
{ {
solAssert(!!m_declaration, "Declaration has to be available."); solAssert(!!m_declaration, "Declaration has to be available.");
if (!m_declaration->isPublic()) solAssert(m_declaration->isPublic(), "");
kind = Kind::Internal; // will be inlined kind = Kind::DelegateCall;
else
kind = Kind::DelegateCall;
} }
return TypeProvider::function( return TypeProvider::function(
parameterTypes, parameterTypes,
m_returnParameterTypes, returnParameterTypes,
m_parameterNames, m_parameterNames,
m_returnParameterNames, m_returnParameterNames,
kind, kind,
@ -3475,7 +3526,7 @@ FunctionTypePointer FunctionType::asExternallyCallableFunction(bool _inLibrary,
m_gasSet, m_gasSet,
m_valueSet, m_valueSet,
m_saltSet, m_saltSet,
_bound m_bound
); );
} }

View File

@ -980,6 +980,8 @@ public:
void clearCache() const override; void clearCache() const override;
protected:
std::vector<std::tuple<std::string, TypePointer>> makeStackItems() const override;
private: private:
StructDefinition const& m_struct; StructDefinition const& m_struct;
// Caches for interfaceType(bool) // Caches for interfaceType(bool)
@ -1302,13 +1304,16 @@ public:
/// of the parameters to false. /// of the parameters to false.
TypePointer copyAndSetCallOptions(bool _setGas, bool _setValue, bool _setSalt) const; TypePointer copyAndSetCallOptions(bool _setGas, bool _setValue, bool _setSalt) const;
/// @returns a copy of this function type with the `bound` flag set to true.
/// Should only be called on library functions.
FunctionTypePointer asBoundFunction() const;
/// @returns a copy of this function type where the location of reference types is changed /// @returns a copy of this function type where the location of reference types is changed
/// from CallData to Memory. This is the type that would be used when the function is /// from CallData to Memory. This is the type that would be used when the function is
/// called externally, as opposed to the parameter types that are available inside the function body. /// called externally, as opposed to the parameter types that are available inside the function body.
/// Also supports variants to be used for library or bound calls. /// Also supports variants to be used for library or bound calls.
/// @param _inLibrary if true, uses DelegateCall as location. /// @param _inLibrary if true, uses DelegateCall as location.
/// @param _bound if true, the function type is set to be bound. FunctionTypePointer asExternallyCallableFunction(bool _inLibrary) const;
FunctionTypePointer asExternallyCallableFunction(bool _inLibrary, bool _bound = false) const;
protected: protected:
std::vector<std::tuple<std::string, TypePointer>> makeStackItems() const override; std::vector<std::tuple<std::string, TypePointer>> makeStackItems() const override;

View File

@ -725,7 +725,7 @@ string ABIFunctions::abiEncodingFunctionCompactStorageArray(
size_t itemsPerSlot = 32 / storageBytes; size_t itemsPerSlot = 32 / storageBytes;
solAssert(itemsPerSlot > 0, ""); solAssert(itemsPerSlot > 0, "");
// The number of elements we need to handle manually after the loop. // The number of elements we need to handle manually after the loop.
size_t spill = size_t(_from.length() % itemsPerSlot); size_t spill = static_cast<size_t>(_from.length() % itemsPerSlot);
Whiskers templ( Whiskers templ(
R"( R"(
// <readableTypeNameFrom> -> <readableTypeNameTo> // <readableTypeNameFrom> -> <readableTypeNameTo>

View File

@ -56,7 +56,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
bool directCopy = sourceIsStorage && sourceBaseType->isValueType() && *sourceBaseType == *targetBaseType; bool directCopy = sourceIsStorage && sourceBaseType->isValueType() && *sourceBaseType == *targetBaseType;
bool haveByteOffsetSource = !directCopy && sourceIsStorage && sourceBaseType->storageBytes() <= 16; bool haveByteOffsetSource = !directCopy && sourceIsStorage && sourceBaseType->storageBytes() <= 16;
bool haveByteOffsetTarget = !directCopy && targetBaseType->storageBytes() <= 16; bool haveByteOffsetTarget = !directCopy && targetBaseType->storageBytes() <= 16;
unsigned byteOffsetSize = (haveByteOffsetSource ? 1 : 0) + (haveByteOffsetTarget ? 1 : 0); unsigned byteOffsetSize = (haveByteOffsetSource ? 1u : 0u) + (haveByteOffsetTarget ? 1u : 0u);
// stack: source_ref [source_length] target_ref // stack: source_ref [source_length] target_ref
// store target_ref // store target_ref

View File

@ -133,7 +133,7 @@ void CompilerContext::callLowLevelFunction(
*this << lowLevelFunctionTag(_name, _inArgs, _outArgs, _generator); *this << lowLevelFunctionTag(_name, _inArgs, _outArgs, _generator);
appendJump(evmasm::AssemblyItem::JumpType::IntoFunction); appendJump(evmasm::AssemblyItem::JumpType::IntoFunction);
adjustStackOffset(int(_outArgs) - 1 - _inArgs); adjustStackOffset(static_cast<int>(_outArgs) - 1 - static_cast<int>(_inArgs));
*this << retTag.tag(); *this << retTag.tag();
} }
@ -147,7 +147,7 @@ void CompilerContext::callYulFunction(
auto const retTag = pushNewTag(); auto const retTag = pushNewTag();
CompilerUtils(*this).moveIntoStack(_inArgs); CompilerUtils(*this).moveIntoStack(_inArgs);
appendJumpTo(namedTag(_name)); appendJumpTo(namedTag(_name));
adjustStackOffset(int(_outArgs) - 1 - _inArgs); adjustStackOffset(static_cast<int>(_outArgs) - 1 - static_cast<int>(_inArgs));
*this << retTag.tag(); *this << retTag.tag();
} }
@ -181,7 +181,7 @@ void CompilerContext::appendMissingLowLevelFunctions()
tie(name, inArgs, outArgs, generator) = m_lowLevelFunctionGenerationQueue.front(); tie(name, inArgs, outArgs, generator) = m_lowLevelFunctionGenerationQueue.front();
m_lowLevelFunctionGenerationQueue.pop(); m_lowLevelFunctionGenerationQueue.pop();
setStackOffset(inArgs + 1); setStackOffset(static_cast<int>(inArgs) + 1);
*this << m_lowLevelFunctions.at(name).tag(); *this << m_lowLevelFunctions.at(name).tag();
generator(*this); generator(*this);
CompilerUtils(*this).moveToStackTop(outArgs); CompilerUtils(*this).moveToStackTop(outArgs);
@ -298,12 +298,12 @@ unsigned CompilerContext::baseStackOffsetOfVariable(Declaration const& _declarat
unsigned CompilerContext::baseToCurrentStackOffset(unsigned _baseOffset) const unsigned CompilerContext::baseToCurrentStackOffset(unsigned _baseOffset) const
{ {
return m_asm->deposit() - _baseOffset - 1; return static_cast<unsigned>(m_asm->deposit()) - _baseOffset - 1;
} }
unsigned CompilerContext::currentToBaseStackOffset(unsigned _offset) const unsigned CompilerContext::currentToBaseStackOffset(unsigned _offset) const
{ {
return m_asm->deposit() - _offset - 1; return static_cast<unsigned>(m_asm->deposit()) - _offset - 1;
} }
pair<u256, unsigned> CompilerContext::storageLocationOfVariable(Declaration const& _declaration) const pair<u256, unsigned> CompilerContext::storageLocationOfVariable(Declaration const& _declaration) const
@ -371,7 +371,7 @@ void CompilerContext::appendInlineAssembly(
OptimiserSettings const& _optimiserSettings OptimiserSettings const& _optimiserSettings
) )
{ {
int startStackHeight = stackHeight(); unsigned startStackHeight = stackHeight();
set<yul::YulString> externallyUsedIdentifiers; set<yul::YulString> externallyUsedIdentifiers;
for (auto const& fun: _externallyUsedFunctions) for (auto const& fun: _externallyUsedFunctions)
@ -387,9 +387,9 @@ void CompilerContext::appendInlineAssembly(
) -> size_t ) -> size_t
{ {
if (_insideFunction) if (_insideFunction)
return size_t(-1); return numeric_limits<size_t>::max();
auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name.str()); auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name.str());
return it == _localVariables.end() ? size_t(-1) : 1; return it == _localVariables.end() ? numeric_limits<size_t>::max() : 1;
}; };
identifierAccess.generateCode = [&]( identifierAccess.generateCode = [&](
yul::Identifier const& _identifier, yul::Identifier const& _identifier,
@ -399,8 +399,8 @@ void CompilerContext::appendInlineAssembly(
{ {
auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name.str()); auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name.str());
solAssert(it != _localVariables.end(), ""); solAssert(it != _localVariables.end(), "");
int stackDepth = _localVariables.end() - it; auto stackDepth = static_cast<size_t>(distance(it, _localVariables.end()));
int stackDiff = _assembly.stackHeight() - startStackHeight + stackDepth; size_t stackDiff = static_cast<size_t>(_assembly.stackHeight()) - startStackHeight + stackDepth;
if (_context == yul::IdentifierContext::LValue) if (_context == yul::IdentifierContext::LValue)
stackDiff -= 1; stackDiff -= 1;
if (stackDiff < 1 || stackDiff > 16) if (stackDiff < 1 || stackDiff > 16)

View File

@ -377,7 +377,7 @@ private:
/// The runtime context if in Creation mode, this is used for generating tags that would be stored into the storage and then used at runtime. /// The runtime context if in Creation mode, this is used for generating tags that would be stored into the storage and then used at runtime.
CompilerContext *m_runtimeContext; CompilerContext *m_runtimeContext;
/// The index of the runtime subroutine. /// The index of the runtime subroutine.
size_t m_runtimeSub = -1; size_t m_runtimeSub = std::numeric_limits<size_t>::max();
/// An index of low-level function labels by name. /// An index of low-level function labels by name.
std::map<std::string, evmasm::AssemblyItem> m_lowLevelFunctions; std::map<std::string, evmasm::AssemblyItem> m_lowLevelFunctions;
/// Collector for yul functions. /// Collector for yul functions.

View File

@ -1351,7 +1351,7 @@ void CompilerUtils::popAndJump(unsigned _toHeight, evmasm::AssemblyItem const& _
unsigned amount = m_context.stackHeight() - _toHeight; unsigned amount = m_context.stackHeight() - _toHeight;
popStackSlots(amount); popStackSlots(amount);
m_context.appendJumpTo(_jumpTo); m_context.appendJumpTo(_jumpTo);
m_context.adjustStackOffset(amount); m_context.adjustStackOffset(static_cast<int>(amount));
} }
unsigned CompilerUtils::sizeOnStack(vector<Type const*> const& _variableTypes) unsigned CompilerUtils::sizeOnStack(vector<Type const*> const& _variableTypes)
@ -1436,7 +1436,7 @@ unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCallda
{ {
bool leftAligned = _type.category() == Type::Category::FixedBytes; bool leftAligned = _type.category() == Type::Category::FixedBytes;
// add leading or trailing zeros by dividing/multiplying depending on alignment // add leading or trailing zeros by dividing/multiplying depending on alignment
int shiftFactor = (32 - numBytes) * 8; unsigned shiftFactor = (32 - numBytes) * 8;
rightShiftNumberOnStack(shiftFactor); rightShiftNumberOnStack(shiftFactor);
if (leftAligned) if (leftAligned)
{ {

View File

@ -185,7 +185,7 @@ size_t ContractCompiler::packIntoContractCreator(ContractDefinition const& _cont
CompilerContext::LocationSetter locationSetter(m_context, _contract); CompilerContext::LocationSetter locationSetter(m_context, _contract);
m_context << deployRoutine; m_context << deployRoutine;
solAssert(m_context.runtimeSub() != size_t(-1), "Runtime sub not registered"); solAssert(m_context.runtimeSub() != numeric_limits<size_t>::max(), "Runtime sub not registered");
ContractType contractType(_contract); ContractType contractType(_contract);
auto const& immutables = contractType.immutableVariables(); auto const& immutables = contractType.immutableVariables();
@ -221,7 +221,7 @@ size_t ContractCompiler::deployLibrary(ContractDefinition const& _contract)
CompilerContext::LocationSetter locationSetter(m_context, _contract); CompilerContext::LocationSetter locationSetter(m_context, _contract);
solAssert(m_context.runtimeSub() != size_t(-1), "Runtime sub not registered"); solAssert(m_context.runtimeSub() != numeric_limits<size_t>::max(), "Runtime sub not registered");
m_context.pushSubroutineSize(m_context.runtimeSub()); m_context.pushSubroutineSize(m_context.runtimeSub());
m_context.pushSubroutineOffset(m_context.runtimeSub()); m_context.pushSubroutineOffset(m_context.runtimeSub());
// This code replaces the address added by appendDeployTimeAddress(). // This code replaces the address added by appendDeployTimeAddress().
@ -349,11 +349,11 @@ void ContractCompiler::appendInternalSelector(
m_context << dupInstruction(1) << u256(FixedHash<4>::Arith(pivot)) << Instruction::GT; m_context << dupInstruction(1) << u256(FixedHash<4>::Arith(pivot)) << Instruction::GT;
evmasm::AssemblyItem lessTag{m_context.appendConditionalJump()}; evmasm::AssemblyItem lessTag{m_context.appendConditionalJump()};
// Here, we have funid >= pivot // Here, we have funid >= pivot
vector<FixedHash<4>> larger{_ids.begin() + pivotIndex, _ids.end()}; vector<FixedHash<4>> larger{_ids.begin() + static_cast<ptrdiff_t>(pivotIndex), _ids.end()};
appendInternalSelector(_entryPoints, larger, _notFoundTag, _runs); appendInternalSelector(_entryPoints, larger, _notFoundTag, _runs);
m_context << lessTag; m_context << lessTag;
// Here, we have funid < pivot // Here, we have funid < pivot
vector<FixedHash<4>> smaller{_ids.begin(), _ids.begin() + pivotIndex}; vector<FixedHash<4>> smaller{_ids.begin(), _ids.begin() + static_cast<ptrdiff_t>(pivotIndex)};
appendInternalSelector(_entryPoints, smaller, _notFoundTag, _runs); appendInternalSelector(_entryPoints, smaller, _notFoundTag, _runs);
} }
else else
@ -512,8 +512,8 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac
m_context << returnTag; m_context << returnTag;
// Return tag and input parameters get consumed. // Return tag and input parameters get consumed.
m_context.adjustStackOffset( m_context.adjustStackOffset(
CompilerUtils(m_context).sizeOnStack(functionType->returnParameterTypes()) - static_cast<int>(CompilerUtils::sizeOnStack(functionType->returnParameterTypes())) -
CompilerUtils(m_context).sizeOnStack(functionType->parameterTypes()) - static_cast<int>(CompilerUtils::sizeOnStack(functionType->parameterTypes())) -
1 1
); );
// Consumes the return parameters. // Consumes the return parameters.
@ -589,7 +589,7 @@ bool ContractCompiler::visit(FunctionDefinition const& _function)
unsigned parametersSize = CompilerUtils::sizeOnStack(_function.parameters()); unsigned parametersSize = CompilerUtils::sizeOnStack(_function.parameters());
if (!_function.isConstructor()) if (!_function.isConstructor())
// adding 1 for return address. // adding 1 for return address.
m_context.adjustStackOffset(parametersSize + 1); m_context.adjustStackOffset(static_cast<int>(parametersSize) + 1);
for (ASTPointer<VariableDeclaration> const& variable: _function.parameters()) for (ASTPointer<VariableDeclaration> const& variable: _function.parameters())
{ {
m_context.addVariable(*variable, parametersSize); m_context.addVariable(*variable, parametersSize);
@ -609,7 +609,7 @@ bool ContractCompiler::visit(FunctionDefinition const& _function)
m_breakTags.clear(); m_breakTags.clear();
m_continueTags.clear(); m_continueTags.clear();
m_currentFunction = &_function; m_currentFunction = &_function;
m_modifierDepth = -1; m_modifierDepth = numeric_limits<unsigned>::max();
m_scopeStackHeight.clear(); m_scopeStackHeight.clear();
m_context.setModifierDepth(0); m_context.setModifierDepth(0);
@ -627,10 +627,10 @@ bool ContractCompiler::visit(FunctionDefinition const& _function)
unsigned const c_returnValuesSize = CompilerUtils::sizeOnStack(_function.returnParameters()); unsigned const c_returnValuesSize = CompilerUtils::sizeOnStack(_function.returnParameters());
vector<int> stackLayout; vector<int> stackLayout;
stackLayout.push_back(c_returnValuesSize); // target of return address stackLayout.push_back(static_cast<int>(c_returnValuesSize)); // target of return address
stackLayout += vector<int>(c_argumentsSize, -1); // discard all arguments stackLayout += vector<int>(c_argumentsSize, -1); // discard all arguments
for (unsigned i = 0; i < c_returnValuesSize; ++i) for (size_t i = 0; i < c_returnValuesSize; ++i)
stackLayout.push_back(i); stackLayout.push_back(static_cast<int>(i));
if (stackLayout.size() > 17) if (stackLayout.size() > 17)
BOOST_THROW_EXCEPTION( BOOST_THROW_EXCEPTION(
@ -638,7 +638,7 @@ bool ContractCompiler::visit(FunctionDefinition const& _function)
errinfo_sourceLocation(_function.location()) << errinfo_sourceLocation(_function.location()) <<
errinfo_comment("Stack too deep, try removing local variables.") errinfo_comment("Stack too deep, try removing local variables.")
); );
while (stackLayout.back() != int(stackLayout.size() - 1)) while (stackLayout.back() != static_cast<int>(stackLayout.size() - 1))
if (stackLayout.back() < 0) if (stackLayout.back() < 0)
{ {
m_context << Instruction::POP; m_context << Instruction::POP;
@ -646,11 +646,11 @@ bool ContractCompiler::visit(FunctionDefinition const& _function)
} }
else else
{ {
m_context << swapInstruction(stackLayout.size() - stackLayout.back() - 1); m_context << swapInstruction(stackLayout.size() - static_cast<size_t>(stackLayout.back()) - 1);
swap(stackLayout[stackLayout.back()], stackLayout.back()); swap(stackLayout[static_cast<size_t>(stackLayout.back())], stackLayout.back());
} }
for (int i = 0; i < int(stackLayout.size()); ++i) for (size_t i = 0; i < stackLayout.size(); ++i)
if (stackLayout[i] != i) if (stackLayout[i] != static_cast<int>(i))
solAssert(false, "Invalid stack layout on cleanup."); solAssert(false, "Invalid stack layout on cleanup.");
for (ASTPointer<VariableDeclaration> const& variable: _function.parameters() + _function.returnParameters()) for (ASTPointer<VariableDeclaration> const& variable: _function.parameters() + _function.returnParameters())
@ -677,7 +677,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
{ {
auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier); auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier);
if (ref == _inlineAssembly.annotation().externalReferences.end()) if (ref == _inlineAssembly.annotation().externalReferences.end())
return size_t(-1); return numeric_limits<size_t>::max();
return ref->second.valueSize; return ref->second.valueSize;
}; };
identifierAccess.generateCode = [&](yul::Identifier const& _identifier, yul::IdentifierContext _context, yul::AbstractAssembly& _assembly) identifierAccess.generateCode = [&](yul::Identifier const& _identifier, yul::IdentifierContext _context, yul::AbstractAssembly& _assembly)
@ -696,7 +696,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
functionDef = &functionDef->resolveVirtual(m_context.mostDerivedContract()); functionDef = &functionDef->resolveVirtual(m_context.mostDerivedContract());
auto functionEntryLabel = m_context.functionEntryLabel(*functionDef).pushTag(); auto functionEntryLabel = m_context.functionEntryLabel(*functionDef).pushTag();
solAssert(functionEntryLabel.data() <= std::numeric_limits<size_t>::max(), ""); solAssert(functionEntryLabel.data() <= std::numeric_limits<size_t>::max(), "");
_assembly.appendLabelReference(size_t(functionEntryLabel.data())); _assembly.appendLabelReference(static_cast<size_t>(functionEntryLabel.data()));
// If there is a runtime context, we have to merge both labels into the same // If there is a runtime context, we have to merge both labels into the same
// stack slot in case we store it in storage. // stack slot in case we store it in storage.
if (CompilerContext* rtc = m_context.runtimeContext()) if (CompilerContext* rtc = m_context.runtimeContext())
@ -705,7 +705,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
_assembly.appendInstruction(Instruction::MUL); _assembly.appendInstruction(Instruction::MUL);
auto runtimeEntryLabel = rtc->functionEntryLabel(*functionDef).toSubAssemblyTag(m_context.runtimeSub()); auto runtimeEntryLabel = rtc->functionEntryLabel(*functionDef).toSubAssemblyTag(m_context.runtimeSub());
solAssert(runtimeEntryLabel.data() <= std::numeric_limits<size_t>::max(), ""); solAssert(runtimeEntryLabel.data() <= std::numeric_limits<size_t>::max(), "");
_assembly.appendLabelReference(size_t(runtimeEntryLabel.data())); _assembly.appendLabelReference(static_cast<size_t>(runtimeEntryLabel.data()));
_assembly.appendInstruction(Instruction::OR); _assembly.appendInstruction(Instruction::OR);
} }
} }
@ -772,7 +772,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
} }
else if (m_context.isLocalVariable(decl)) else if (m_context.isLocalVariable(decl))
{ {
int stackDiff = _assembly.stackHeight() - m_context.baseStackOffsetOfVariable(*variable); unsigned stackDiff = static_cast<unsigned>(_assembly.stackHeight()) - m_context.baseStackOffsetOfVariable(*variable);
if (ref->second.isSlot || ref->second.isOffset) if (ref->second.isSlot || ref->second.isOffset)
{ {
solAssert(variable->type()->dataStoredIn(DataLocation::Storage), ""); solAssert(variable->type()->dataStoredIn(DataLocation::Storage), "");
@ -816,7 +816,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
} }
else else
solAssert(false, "Invalid declaration type."); solAssert(false, "Invalid declaration type.");
solAssert(_assembly.stackHeight() - depositBefore == int(ref->second.valueSize), ""); solAssert(_assembly.stackHeight() - depositBefore == static_cast<int>(ref->second.valueSize), "");
} }
else else
{ {
@ -828,7 +828,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
"Can only assign to stack variables in inline assembly." "Can only assign to stack variables in inline assembly."
); );
solAssert(variable->type()->sizeOnStack() == 1, ""); solAssert(variable->type()->sizeOnStack() == 1, "");
int stackDiff = _assembly.stackHeight() - m_context.baseStackOffsetOfVariable(*variable) - 1; unsigned stackDiff = static_cast<unsigned>(_assembly.stackHeight()) - m_context.baseStackOffsetOfVariable(*variable) - 1;
if (stackDiff > 16 || stackDiff < 1) if (stackDiff > 16 || stackDiff < 1)
BOOST_THROW_EXCEPTION( BOOST_THROW_EXCEPTION(
CompilerError() << CompilerError() <<
@ -875,7 +875,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
false, false,
m_optimiserSettings.optimizeStackAllocation m_optimiserSettings.optimizeStackAllocation
); );
m_context.setStackOffset(startStackHeight); m_context.setStackOffset(static_cast<int>(startStackHeight));
return false; return false;
} }
@ -914,7 +914,7 @@ bool ContractCompiler::visit(TryStatement const& _tryStatement)
solAssert(params[i] && exprTypes[i] && *params[i]->annotation().type == *exprTypes[i], ""); solAssert(params[i] && exprTypes[i] && *params[i]->annotation().type == *exprTypes[i], "");
} }
else else
CompilerUtils(m_context).popStackSlots(returnSize); CompilerUtils(m_context).popStackSlots(static_cast<size_t>(returnSize));
_tryStatement.clauses().front()->accept(*this); _tryStatement.clauses().front()->accept(*this);
} }
@ -937,7 +937,7 @@ void ContractCompiler::handleCatch(vector<ASTPointer<TryCatchClause>> const& _ca
else else
solAssert(false, ""); solAssert(false, "");
solAssert(_catchClauses.size() == size_t(1 + (structured ? 1 : 0) + (fallback ? 1 : 0)), ""); solAssert(_catchClauses.size() == 1ul + (structured ? 1 : 0) + (fallback ? 1 : 0), "");
evmasm::AssemblyItem endTag = m_context.newTag(); evmasm::AssemblyItem endTag = m_context.newTag();
evmasm::AssemblyItem fallbackTag = m_context.newTag(); evmasm::AssemblyItem fallbackTag = m_context.newTag();

View File

@ -100,7 +100,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
if (_varDecl.immutable()) if (_varDecl.immutable())
solAssert(paramTypes.empty(), ""); solAssert(paramTypes.empty(), "");
m_context.adjustStackOffset(1 + CompilerUtils::sizeOnStack(paramTypes)); m_context.adjustStackOffset(static_cast<int>(1 + CompilerUtils::sizeOnStack(paramTypes)));
if (!_varDecl.immutable()) if (!_varDecl.immutable())
{ {
@ -242,7 +242,7 @@ bool ExpressionCompiler::visit(Conditional const& _condition)
acceptAndConvert(_condition.falseExpression(), *_condition.annotation().type); acceptAndConvert(_condition.falseExpression(), *_condition.annotation().type);
evmasm::AssemblyItem endTag = m_context.appendJumpToNew(); evmasm::AssemblyItem endTag = m_context.appendJumpToNew();
m_context << trueTag; m_context << trueTag;
int offset = _condition.annotation().type->sizeOnStack(); int offset = static_cast<int>(_condition.annotation().type->sizeOnStack());
m_context.adjustStackOffset(-offset); m_context.adjustStackOffset(-offset);
acceptAndConvert(_condition.trueExpression(), *_condition.annotation().type); acceptAndConvert(_condition.trueExpression(), *_condition.annotation().type);
m_context << endTag; m_context << endTag;
@ -619,7 +619,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
unsigned returnParametersSize = CompilerUtils::sizeOnStack(function.returnParameterTypes()); unsigned returnParametersSize = CompilerUtils::sizeOnStack(function.returnParameterTypes());
// callee adds return parameters, but removes arguments and return label // callee adds return parameters, but removes arguments and return label
m_context.adjustStackOffset(returnParametersSize - parameterSize - 1); m_context.adjustStackOffset(static_cast<int>(returnParametersSize - parameterSize) - 1);
break; break;
} }
case FunctionType::Kind::BareCall: case FunctionType::Kind::BareCall:
@ -705,7 +705,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
acceptAndConvert(*arguments.front(), *TypeProvider::uint256(), true); acceptAndConvert(*arguments.front(), *TypeProvider::uint256(), true);
// Note that function is not the original function, but the ".gas" function. // Note that function is not the original function, but the ".gas" function.
// Its values of gasSet and valueSet is equal to the original function's though. // Its values of gasSet and valueSet is equal to the original function's though.
unsigned stackDepth = (function.gasSet() ? 1 : 0) + (function.valueSet() ? 1 : 0); unsigned stackDepth = (function.gasSet() ? 1u : 0u) + (function.valueSet() ? 1u : 0u);
if (stackDepth > 0) if (stackDepth > 0)
m_context << swapInstruction(stackDepth); m_context << swapInstruction(stackDepth);
if (function.gasSet()) if (function.gasSet())
@ -814,7 +814,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
case FunctionType::Kind::Log3: case FunctionType::Kind::Log3:
case FunctionType::Kind::Log4: case FunctionType::Kind::Log4:
{ {
unsigned logNumber = int(function.kind()) - int(FunctionType::Kind::Log0); unsigned logNumber = static_cast<unsigned>(function.kind()) - static_cast<unsigned>(FunctionType::Kind::Log0);
for (unsigned arg = logNumber; arg > 0; --arg) for (unsigned arg = logNumber; arg > 0; --arg)
acceptAndConvert(*arguments[arg], *function.parameterTypes()[arg], true); acceptAndConvert(*arguments[arg], *function.parameterTypes()[arg], true);
arguments.front()->accept(*this); arguments.front()->accept(*this);
@ -1088,7 +1088,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
{ {
utils().revertWithStringData(*arguments.at(1)->annotation().type); utils().revertWithStringData(*arguments.at(1)->annotation().type);
// Here, the argument is consumed, but in the other branch, it is still there. // Here, the argument is consumed, but in the other branch, it is still there.
m_context.adjustStackOffset(arguments.at(1)->annotation().type->sizeOnStack()); m_context.adjustStackOffset(static_cast<int>(arguments.at(1)->annotation().type->sizeOnStack()));
} }
else else
m_context.appendRevert(); m_context.appendRevert();
@ -1271,9 +1271,9 @@ bool ExpressionCompiler::visit(FunctionCallOptions const& _functionCallOptions)
acceptAndConvert(*_functionCallOptions.options()[i], *requiredType); acceptAndConvert(*_functionCallOptions.options()[i], *requiredType);
solAssert(!contains(presentOptions, newOption), ""); solAssert(!contains(presentOptions, newOption), "");
size_t insertPos = presentOptions.end() - lower_bound(presentOptions.begin(), presentOptions.end(), newOption); ptrdiff_t insertPos = presentOptions.end() - lower_bound(presentOptions.begin(), presentOptions.end(), newOption);
utils().moveIntoStack(insertPos, 1); utils().moveIntoStack(static_cast<size_t>(insertPos), 1);
presentOptions.insert(presentOptions.end() - insertPos, newOption); presentOptions.insert(presentOptions.end() - insertPos, newOption);
} }
@ -2190,7 +2190,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
// contract address // contract address
unsigned selfSize = _functionType.bound() ? _functionType.selfType()->sizeOnStack() : 0; unsigned selfSize = _functionType.bound() ? _functionType.selfType()->sizeOnStack() : 0;
unsigned gasValueSize = (_functionType.gasSet() ? 1 : 0) + (_functionType.valueSet() ? 1 : 0); unsigned gasValueSize = (_functionType.gasSet() ? 1u : 0u) + (_functionType.valueSet() ? 1u : 0u);
unsigned contractStackPos = m_context.currentToBaseStackOffset(1 + gasValueSize + selfSize + (_functionType.isBareCall() ? 0 : 1)); unsigned contractStackPos = m_context.currentToBaseStackOffset(1 + gasValueSize + selfSize + (_functionType.isBareCall() ? 0 : 1));
unsigned gasStackPos = m_context.currentToBaseStackOffset(gasValueSize); unsigned gasStackPos = m_context.currentToBaseStackOffset(gasValueSize);
unsigned valueStackPos = m_context.currentToBaseStackOffset(1); unsigned valueStackPos = m_context.currentToBaseStackOffset(1);
@ -2361,7 +2361,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
m_context << Instruction::CALL; m_context << Instruction::CALL;
unsigned remainsSize = unsigned remainsSize =
2 + // contract address, input_memory_end 2u + // contract address, input_memory_end
(_functionType.valueSet() ? 1 : 0) + (_functionType.valueSet() ? 1 : 0) +
(_functionType.gasSet() ? 1 : 0) + (_functionType.gasSet() ? 1 : 0) +
(!_functionType.isBareCall() ? 1 : 0); (!_functionType.isBareCall() ? 1 : 0);

View File

@ -1652,8 +1652,7 @@ string YulUtilFunctions::allocateAndInitializeMemoryStructFunction(StructType co
return m_functionCollector.createFunction(functionName, [&]() { return m_functionCollector.createFunction(functionName, [&]() {
Whiskers templ(R"( Whiskers templ(R"(
function <functionName>() -> memPtr { function <functionName>() -> memPtr {
let allocSize := <allocSize>() memPtr := <alloc>(<allocSize>)
memPtr := <alloc>(allocSize)
let offset := memPtr let offset := memPtr
<#member> <#member>
mstore(offset, <zeroValue>()) mstore(offset, <zeroValue>())

View File

@ -636,7 +636,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
}); });
solAssert(it != callArgumentNames.cend(), ""); solAssert(it != callArgumentNames.cend(), "");
arguments.push_back(callArguments[std::distance(callArgumentNames.begin(), it)]); arguments.push_back(callArguments[static_cast<size_t>(std::distance(callArgumentNames.begin(), it))]);
} }
auto memberAccess = dynamic_cast<MemberAccess const*>(&_functionCall.expression()); auto memberAccess = dynamic_cast<MemberAccess const*>(&_functionCall.expression());
@ -1092,7 +1092,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
case FunctionType::Kind::Log3: case FunctionType::Kind::Log3:
case FunctionType::Kind::Log4: case FunctionType::Kind::Log4:
{ {
unsigned logNumber = int(functionType->kind()) - int(FunctionType::Kind::Log0); unsigned logNumber = static_cast<unsigned>(functionType->kind()) - static_cast<unsigned>(FunctionType::Kind::Log0);
solAssert(arguments.size() == logNumber + 1, ""); solAssert(arguments.size() == logNumber + 1, "");
ABIFunctions abi(m_context.evmVersion(), m_context.revertStrings(), m_context.functionCollector()); ABIFunctions abi(m_context.evmVersion(), m_context.revertStrings(), m_context.functionCollector());
string indexedArgs; string indexedArgs;
@ -1477,7 +1477,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
pair<u256, unsigned> const& offsets = structType.storageOffsetsOfMember(member); pair<u256, unsigned> const& offsets = structType.storageOffsetsOfMember(member);
string slot = m_context.newYulVariable(); string slot = m_context.newYulVariable();
m_code << "let " << slot << " := " << m_code << "let " << slot << " := " <<
("add(" + expression.name() + ", " + offsets.first.str() + ")\n"); ("add(" + expression.part("slot").name() + ", " + offsets.first.str() + ")\n");
setLValue(_memberAccess, IRLValue{ setLValue(_memberAccess, IRLValue{
type(_memberAccess), type(_memberAccess),
IRLValue::Storage{slot, offsets.second} IRLValue::Storage{slot, offsets.second}
@ -1497,7 +1497,25 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
} }
case DataLocation::CallData: case DataLocation::CallData:
{ {
solUnimplementedAssert(false, ""); string baseRef = expression.part("offset").name();
string offset = m_context.newYulVariable();
m_code << "let " << offset << " := " << "add(" << baseRef << ", " << to_string(structType.calldataOffsetOfMember(member)) << ")\n";
if (_memberAccess.annotation().type->isDynamicallyEncoded())
define(_memberAccess) <<
m_utils.accessCalldataTailFunction(*_memberAccess.annotation().type) <<
"(" <<
baseRef <<
", " <<
offset <<
")" <<
std::endl;
else
define(_memberAccess) <<
m_utils.readFromCalldata(*_memberAccess.annotation().type) <<
"(" <<
offset <<
")" <<
std::endl;
break; break;
} }
default: default:
@ -1730,7 +1748,7 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess)
setLValue(_indexAccess, IRLValue{ setLValue(_indexAccess, IRLValue{
*arrayType.baseType(), *arrayType.baseType(),
IRLValue::Memory{memAddress} IRLValue::Memory{memAddress, arrayType.isByteArray()}
}); });
break; break;
} }
@ -1763,7 +1781,23 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess)
} }
} }
else if (baseType.category() == Type::Category::FixedBytes) else if (baseType.category() == Type::Category::FixedBytes)
solUnimplementedAssert(false, ""); {
auto const& fixedBytesType = dynamic_cast<FixedBytesType const&>(baseType);
solAssert(_indexAccess.indexExpression(), "Index expression expected.");
IRVariable index{m_context.newYulVariable(), *TypeProvider::uint256()};
define(index, *_indexAccess.indexExpression());
m_code << Whiskers(R"(
if iszero(lt(<index>, <length>)) { invalid() }
let <result> := <shl248>(byte(<index>, <array>))
)")
("index", index.name())
("length", to_string(fixedBytesType.numBytes()))
("array", IRVariable(_indexAccess.baseExpression()).name())
("shl248", m_utils.shiftLeftFunction(256 - 8))
("result", IRVariable(_indexAccess).name())
.render();
}
else if (baseType.category() == Type::Category::TypeType) else if (baseType.category() == Type::Category::TypeType)
{ {
solAssert(baseType.sizeOnStack() == 0, ""); solAssert(baseType.sizeOnStack() == 0, "");

View File

@ -604,7 +604,11 @@ void BMC::checkUnderflow(BMCVerificationTarget& _target, smtutil::Expression con
_target.type == VerificationTarget::Type::UnderOverflow, _target.type == VerificationTarget::Type::UnderOverflow,
"" ""
); );
auto intType = dynamic_cast<IntegerType const*>(_target.expression->annotation().type); IntegerType const* intType = nullptr;
if (auto const* type = dynamic_cast<IntegerType const*>(_target.expression->annotation().type))
intType = type;
else
intType = TypeProvider::uint256();
solAssert(intType, ""); solAssert(intType, "");
checkCondition( checkCondition(
_target.constraints && _constraints && _target.value < smt::minValue(*intType), _target.constraints && _constraints && _target.value < smt::minValue(*intType),
@ -626,7 +630,12 @@ void BMC::checkOverflow(BMCVerificationTarget& _target, smtutil::Expression cons
_target.type == VerificationTarget::Type::UnderOverflow, _target.type == VerificationTarget::Type::UnderOverflow,
"" ""
); );
auto intType = dynamic_cast<IntegerType const*>(_target.expression->annotation().type); IntegerType const* intType = nullptr;
if (auto const* type = dynamic_cast<IntegerType const*>(_target.expression->annotation().type))
intType = type;
else
intType = TypeProvider::uint256();
solAssert(intType, ""); solAssert(intType, "");
checkCondition( checkCondition(
_target.constraints && _constraints && _target.value > smt::maxValue(*intType), _target.constraints && _constraints && _target.value > smt::maxValue(*intType),

View File

@ -104,7 +104,7 @@ void CHC::analyze(SourceUnit const& _source)
for (auto const* assertion: assertions) for (auto const* assertion: assertions)
{ {
createErrorBlock(); createErrorBlock();
connectBlocks(target.value, error(), target.constraints && (target.errorId == assertion->id())); connectBlocks(target.value, error(), target.constraints && (target.errorId == static_cast<size_t>(assertion->id())));
auto [result, model] = query(error(), assertion->location()); auto [result, model] = query(error(), assertion->location());
// This should be fine but it's a bug in the old compiler // This should be fine but it's a bug in the old compiler
(void)model; (void)model;
@ -116,7 +116,7 @@ void CHC::analyze(SourceUnit const& _source)
{ {
solAssert(dynamic_cast<FunctionCall const*>(scope), ""); solAssert(dynamic_cast<FunctionCall const*>(scope), "");
createErrorBlock(); createErrorBlock();
connectBlocks(target.value, error(), target.constraints && (target.errorId == scope->id())); connectBlocks(target.value, error(), target.constraints && (target.errorId == static_cast<size_t>(scope->id())));
auto [result, model] = query(error(), scope->location()); auto [result, model] = query(error(), scope->location());
// This should be fine but it's a bug in the old compiler // This should be fine but it's a bug in the old compiler
(void)model; (void)model;
@ -533,7 +533,9 @@ void CHC::visitAssert(FunctionCall const& _funCall)
connectBlocks( connectBlocks(
m_currentBlock, m_currentBlock,
m_currentFunction->isConstructor() ? summary(*m_currentContract) : summary(*m_currentFunction), m_currentFunction->isConstructor() ? summary(*m_currentContract) : summary(*m_currentFunction),
currentPathConditions() && !m_context.expression(*args.front())->currentValue() && (m_error.currentValue() == _funCall.id()) currentPathConditions() && !m_context.expression(*args.front())->currentValue() && (
m_error.currentValue() == static_cast<size_t>(_funCall.id())
)
); );
m_context.addAssertion(m_error.currentValue() == previousError); m_context.addAssertion(m_error.currentValue() == previousError);
@ -601,7 +603,7 @@ void CHC::makeArrayPopVerificationTarget(FunctionCall const& _arrayPop)
connectBlocks( connectBlocks(
m_currentBlock, m_currentBlock,
m_currentFunction->isConstructor() ? summary(*m_currentContract) : summary(*m_currentFunction), m_currentFunction->isConstructor() ? summary(*m_currentContract) : summary(*m_currentFunction),
currentPathConditions() && symbArray->length() <= 0 && m_error.currentValue() == _arrayPop.id() currentPathConditions() && symbArray->length() <= 0 && m_error.currentValue() == static_cast<size_t>(_arrayPop.id())
); );
m_context.addAssertion(m_error.currentValue() == previousError); m_context.addAssertion(m_error.currentValue() == previousError);
@ -891,13 +893,13 @@ vector<smtutil::Expression> CHC::initialStateVariables()
return stateVariablesAtIndex(0); return stateVariablesAtIndex(0);
} }
vector<smtutil::Expression> CHC::stateVariablesAtIndex(int _index) vector<smtutil::Expression> CHC::stateVariablesAtIndex(unsigned _index)
{ {
solAssert(m_currentContract, ""); solAssert(m_currentContract, "");
return applyMap(m_stateVariables, [&](auto _var) { return valueAtIndex(*_var, _index); }); return applyMap(m_stateVariables, [&](auto _var) { return valueAtIndex(*_var, _index); });
} }
vector<smtutil::Expression> CHC::stateVariablesAtIndex(int _index, ContractDefinition const& _contract) vector<smtutil::Expression> CHC::stateVariablesAtIndex(unsigned _index, ContractDefinition const& _contract)
{ {
return applyMap( return applyMap(
stateVariablesIncludingInheritedAndPrivate(_contract), stateVariablesIncludingInheritedAndPrivate(_contract),

View File

@ -149,8 +149,8 @@ private:
/// @returns the symbolic values of the state variables at the beginning /// @returns the symbolic values of the state variables at the beginning
/// of the current transaction. /// of the current transaction.
std::vector<smtutil::Expression> initialStateVariables(); std::vector<smtutil::Expression> initialStateVariables();
std::vector<smtutil::Expression> stateVariablesAtIndex(int _index); std::vector<smtutil::Expression> stateVariablesAtIndex(unsigned _index);
std::vector<smtutil::Expression> stateVariablesAtIndex(int _index, ContractDefinition const& _contract); std::vector<smtutil::Expression> stateVariablesAtIndex(unsigned _index, ContractDefinition const& _contract);
/// @returns the current symbolic values of the current state variables. /// @returns the current symbolic values of the current state variables.
std::vector<smtutil::Expression> currentStateVariables(); std::vector<smtutil::Expression> currentStateVariables();

View File

@ -154,15 +154,16 @@ void SMTEncoder::visitFunctionOrModifier()
++m_modifierDepthStack.back(); ++m_modifierDepthStack.back();
FunctionDefinition const& function = dynamic_cast<FunctionDefinition const&>(*m_callStack.back().first); FunctionDefinition const& function = dynamic_cast<FunctionDefinition const&>(*m_callStack.back().first);
if (m_modifierDepthStack.back() == int(function.modifiers().size())) if (m_modifierDepthStack.back() == static_cast<int>(function.modifiers().size()))
{ {
if (function.isImplemented()) if (function.isImplemented())
function.body().accept(*this); function.body().accept(*this);
} }
else else
{ {
solAssert(m_modifierDepthStack.back() < int(function.modifiers().size()), ""); solAssert(m_modifierDepthStack.back() < static_cast<int>(function.modifiers().size()), "");
ASTPointer<ModifierInvocation> const& modifierInvocation = function.modifiers()[m_modifierDepthStack.back()]; ASTPointer<ModifierInvocation> const& modifierInvocation =
function.modifiers()[static_cast<size_t>(m_modifierDepthStack.back())];
solAssert(modifierInvocation, ""); solAssert(modifierInvocation, "");
auto refDecl = modifierInvocation->name()->annotation().referencedDeclaration; auto refDecl = modifierInvocation->name()->annotation().referencedDeclaration;
if (dynamic_cast<ContractDefinition const*>(refDecl)) if (dynamic_cast<ContractDefinition const*>(refDecl))
@ -385,44 +386,22 @@ void SMTEncoder::endVisit(Assignment const& _assignment)
} }
else else
{ {
auto const& type = _assignment.annotation().type; if (dynamic_cast<TupleType const*>(_assignment.rightHandSide().annotation().type))
vector<smtutil::Expression> rightArguments; tupleAssignment(_assignment.leftHandSide(), _assignment.rightHandSide());
if (auto const* tupleTypeRight = dynamic_cast<TupleType const*>(_assignment.rightHandSide().annotation().type))
{
auto symbTupleLeft = dynamic_pointer_cast<smt::SymbolicTupleVariable>(m_context.expression(_assignment.leftHandSide()));
solAssert(symbTupleLeft, "");
auto symbTupleRight = dynamic_pointer_cast<smt::SymbolicTupleVariable>(m_context.expression(_assignment.rightHandSide()));
solAssert(symbTupleRight, "");
auto const& leftComponents = symbTupleLeft->components();
auto const& rightComponents = symbTupleRight->components();
solAssert(leftComponents.size() == rightComponents.size(), "");
auto tupleTypeLeft = dynamic_cast<TupleType const*>(_assignment.leftHandSide().annotation().type);
solAssert(tupleTypeLeft, "");
solAssert(tupleTypeLeft->components().size() == leftComponents.size(), "");
auto const& typesLeft = tupleTypeLeft->components();
solAssert(tupleTypeRight->components().size() == rightComponents.size(), "");
auto const& typesRight = tupleTypeRight->components();
for (unsigned i = 0; i < rightComponents.size(); ++i)
rightArguments.push_back(symbTupleRight->component(i, typesRight.at(i), typesLeft.at(i)));
}
else else
{ {
auto const& type = _assignment.annotation().type;
auto rightHandSide = compoundOps.count(op) ? auto rightHandSide = compoundOps.count(op) ?
compoundAssignment(_assignment) : compoundAssignment(_assignment) :
expr(_assignment.rightHandSide(), type); expr(_assignment.rightHandSide(), type);
defineExpr(_assignment, rightHandSide); defineExpr(_assignment, rightHandSide);
rightArguments.push_back(expr(_assignment, type)); assignment(
_assignment.leftHandSide(),
expr(_assignment, type),
type,
_assignment.location()
);
} }
assignment(
_assignment.leftHandSide(),
rightArguments,
type,
_assignment.location()
);
} }
} }
@ -1023,38 +1002,7 @@ void SMTEncoder::arrayIndexAssignment(Expression const& _expr, smtutil::Expressi
solAssert(varDecl, ""); solAssert(varDecl, "");
if (varDecl->hasReferenceOrMappingType()) if (varDecl->hasReferenceOrMappingType())
m_context.resetVariables([&](VariableDeclaration const& _var) { resetReferences(*varDecl);
if (_var == *varDecl)
return false;
// If both are state variables no need to clear knowledge.
if (_var.isStateVariable() && varDecl->isStateVariable())
return false;
TypePointer prefix = _var.type();
TypePointer originalType = typeWithoutPointer(varDecl->type());
while (
prefix->category() == Type::Category::Mapping ||
prefix->category() == Type::Category::Array
)
{
if (*originalType == *typeWithoutPointer(prefix))
return true;
if (prefix->category() == Type::Category::Mapping)
{
auto mapPrefix = dynamic_cast<MappingType const*>(prefix);
solAssert(mapPrefix, "");
prefix = mapPrefix->valueType();
}
else
{
auto arrayPrefix = dynamic_cast<ArrayType const*>(prefix);
solAssert(arrayPrefix, "");
prefix = arrayPrefix->baseType();
}
}
return false;
});
auto symbArray = dynamic_pointer_cast<smt::SymbolicArrayVariable>(m_context.variable(*varDecl)); auto symbArray = dynamic_pointer_cast<smt::SymbolicArrayVariable>(m_context.variable(*varDecl));
smtutil::Expression store = smtutil::Expression::store( smtutil::Expression store = smtutil::Expression::store(
@ -1160,6 +1108,8 @@ void SMTEncoder::arrayPushPopAssign(Expression const& _expr, smtutil::Expression
{ {
auto varDecl = identifierToVariable(*id); auto varDecl = identifierToVariable(*id);
solAssert(varDecl, ""); solAssert(varDecl, "");
if (varDecl->hasReferenceOrMappingType())
resetReferences(*varDecl);
m_context.addAssertion(m_context.newValue(*varDecl) == _array); m_context.addAssertion(m_context.newValue(*varDecl) == _array);
} }
else if (auto const* indexAccess = dynamic_cast<IndexAccess const*>(&_expr)) else if (auto const* indexAccess = dynamic_cast<IndexAccess const*>(&_expr))
@ -1213,7 +1163,7 @@ void SMTEncoder::arithmeticOperation(BinaryOperation const& _op)
{ {
auto type = _op.annotation().commonType; auto type = _op.annotation().commonType;
solAssert(type, ""); solAssert(type, "");
if (type->category() == Type::Category::Integer) if (type->category() == Type::Category::Integer || type->category() == Type::Category::FixedPoint)
{ {
switch (_op.getOperator()) switch (_op.getOperator())
{ {
@ -1266,13 +1216,21 @@ pair<smtutil::Expression, smtutil::Expression> SMTEncoder::arithmeticOperation(
}; };
solAssert(validOperators.count(_op), ""); solAssert(validOperators.count(_op), "");
solAssert(_commonType, ""); solAssert(_commonType, "");
solAssert(_commonType->category() == Type::Category::Integer, ""); solAssert(
_commonType->category() == Type::Category::Integer || _commonType->category() == Type::Category::FixedPoint,
""
);
IntegerType const* intType = nullptr;
if (auto type = dynamic_cast<IntegerType const*>(_commonType))
intType = type;
else
intType = TypeProvider::uint256();
auto const& intType = dynamic_cast<IntegerType const&>(*_commonType);
smtutil::Expression valueNoMod( smtutil::Expression valueNoMod(
_op == Token::Add ? _left + _right : _op == Token::Add ? _left + _right :
_op == Token::Sub ? _left - _right : _op == Token::Sub ? _left - _right :
_op == Token::Div ? division(_left, _right, intType) : _op == Token::Div ? division(_left, _right, *intType) :
_op == Token::Mul ? _left * _right : _op == Token::Mul ? _left * _right :
/*_op == Token::Mod*/ _left % _right /*_op == Token::Mod*/ _left % _right
); );
@ -1280,20 +1238,23 @@ pair<smtutil::Expression, smtutil::Expression> SMTEncoder::arithmeticOperation(
if (_op == Token::Div || _op == Token::Mod) if (_op == Token::Div || _op == Token::Mod)
m_context.addAssertion(_right != 0); m_context.addAssertion(_right != 0);
smtutil::Expression intValueRange = (0 - smt::minValue(intType)) + smt::maxValue(intType) + 1; auto symbMin = smt::minValue(*intType);
auto symbMax = smt::maxValue(*intType);
smtutil::Expression intValueRange = (0 - symbMin) + symbMax + 1;
auto value = smtutil::Expression::ite( auto value = smtutil::Expression::ite(
valueNoMod > smt::maxValue(intType), valueNoMod > symbMax,
valueNoMod % intValueRange, valueNoMod % intValueRange,
smtutil::Expression::ite( smtutil::Expression::ite(
valueNoMod < smt::minValue(intType), valueNoMod < symbMin,
valueNoMod % intValueRange, valueNoMod % intValueRange,
valueNoMod valueNoMod
) )
); );
if (intType.isSigned()) if (intType->isSigned())
value = smtutil::Expression::ite( value = smtutil::Expression::ite(
value > smt::maxValue(intType), value > symbMax,
value - intValueRange, value - intValueRange,
value value
); );
@ -1422,11 +1383,16 @@ smtutil::Expression SMTEncoder::division(smtutil::Expression _left, smtutil::Exp
void SMTEncoder::assignment( void SMTEncoder::assignment(
Expression const& _left, Expression const& _left,
vector<smtutil::Expression> const& _right, smtutil::Expression const& _right,
TypePointer const& _type, TypePointer const& _type,
langutil::SourceLocation const& _location langutil::SourceLocation const& _location
) )
{ {
solAssert(
_left.annotation().type->category() != Type::Category::Tuple,
"Tuple assignments should be handled by tupleAssignment."
);
if (!smt::isSupportedType(_type->category())) if (!smt::isSupportedType(_type->category()))
{ {
// Give it a new index anyway to keep the SSA scheme sound. // Give it a new index anyway to keep the SSA scheme sound.
@ -1440,26 +1406,9 @@ void SMTEncoder::assignment(
); );
} }
else if (auto varDecl = identifierToVariable(_left)) else if (auto varDecl = identifierToVariable(_left))
{ assignment(*varDecl, _right);
solAssert(_right.size() == 1, "");
assignment(*varDecl, _right.front());
}
else if (dynamic_cast<IndexAccess const*>(&_left)) else if (dynamic_cast<IndexAccess const*>(&_left))
{ arrayIndexAssignment(_left, _right);
solAssert(_right.size() == 1, "");
arrayIndexAssignment(_left, _right.front());
}
else if (auto tuple = dynamic_cast<TupleExpression const*>(&_left))
{
auto const& components = tuple->components();
if (!_right.empty())
{
solAssert(_right.size() == components.size(), "");
for (unsigned i = 0; i < _right.size(); ++i)
if (auto component = components.at(i))
assignment(*component, {_right.at(i)}, component->annotation().type, component->location());
}
}
else else
m_errorReporter.warning( m_errorReporter.warning(
8182_error, 8182_error,
@ -1468,6 +1417,52 @@ void SMTEncoder::assignment(
); );
} }
void SMTEncoder::tupleAssignment(Expression const& _left, Expression const& _right)
{
auto lTuple = dynamic_cast<TupleExpression const*>(&_left);
solAssert(lTuple, "");
auto const& lComponents = lTuple->components();
// If both sides are tuple expressions, we individually and potentially
// recursively assign each pair of components.
// This is because of potential type conversion.
if (auto rTuple = dynamic_cast<TupleExpression const*>(&_right))
{
auto const& rComponents = rTuple->components();
solAssert(lComponents.size() == rComponents.size(), "");
for (unsigned i = 0; i < lComponents.size(); ++i)
{
if (!lComponents.at(i) || !rComponents.at(i))
continue;
auto const& lExpr = *lComponents.at(i);
auto const& rExpr = *rComponents.at(i);
if (lExpr.annotation().type->category() == Type::Category::Tuple)
tupleAssignment(lExpr, rExpr);
else
{
auto type = lExpr.annotation().type;
assignment(lExpr, expr(rExpr, type), type, lExpr.location());
}
}
}
else
{
auto rType = dynamic_cast<TupleType const*>(_right.annotation().type);
solAssert(rType, "");
auto const& rComponents = rType->components();
solAssert(lComponents.size() == rComponents.size(), "");
auto symbRight = expr(_right);
solAssert(symbRight.sort->kind == smtutil::Kind::Tuple, "");
for (unsigned i = 0; i < lComponents.size(); ++i)
if (auto component = lComponents.at(i); component && rComponents.at(i))
assignment(*component, smtutil::Expression::tuple_get(symbRight, i), component->annotation().type, component->location());
}
}
smtutil::Expression SMTEncoder::compoundAssignment(Assignment const& _assignment) smtutil::Expression SMTEncoder::compoundAssignment(Assignment const& _assignment)
{ {
static map<Token, Token> const compoundToArithmetic{ static map<Token, Token> const compoundToArithmetic{
@ -1618,6 +1613,42 @@ void SMTEncoder::resetStateVariables()
m_context.resetVariables([&](VariableDeclaration const& _variable) { return _variable.isStateVariable(); }); m_context.resetVariables([&](VariableDeclaration const& _variable) { return _variable.isStateVariable(); });
} }
void SMTEncoder::resetReferences(VariableDeclaration const& _varDecl)
{
m_context.resetVariables([&](VariableDeclaration const& _var) {
if (_var == _varDecl)
return false;
// If both are state variables no need to clear knowledge.
if (_var.isStateVariable() && _varDecl.isStateVariable())
return false;
TypePointer prefix = _var.type();
TypePointer originalType = typeWithoutPointer(_varDecl.type());
while (
prefix->category() == Type::Category::Mapping ||
prefix->category() == Type::Category::Array
)
{
if (*originalType == *typeWithoutPointer(prefix))
return true;
if (prefix->category() == Type::Category::Mapping)
{
auto mapPrefix = dynamic_cast<MappingType const*>(prefix);
solAssert(mapPrefix, "");
prefix = mapPrefix->valueType();
}
else
{
auto arrayPrefix = dynamic_cast<ArrayType const*>(prefix);
solAssert(arrayPrefix, "");
prefix = arrayPrefix->baseType();
}
}
return false;
});
}
TypePointer SMTEncoder::typeWithoutPointer(TypePointer const& _type) TypePointer SMTEncoder::typeWithoutPointer(TypePointer const& _type)
{ {
if (auto refType = dynamic_cast<ReferenceType const*>(_type)) if (auto refType = dynamic_cast<ReferenceType const*>(_type))
@ -1649,8 +1680,8 @@ void SMTEncoder::mergeVariables(set<VariableDeclaration const*> const& _variable
for (auto const* decl: sortedVars) for (auto const* decl: sortedVars)
{ {
solAssert(_indicesEndTrue.count(decl) && _indicesEndFalse.count(decl), ""); solAssert(_indicesEndTrue.count(decl) && _indicesEndFalse.count(decl), "");
int trueIndex = _indicesEndTrue.at(decl); auto trueIndex = static_cast<unsigned>(_indicesEndTrue.at(decl));
int falseIndex = _indicesEndFalse.at(decl); auto falseIndex = static_cast<unsigned>(_indicesEndFalse.at(decl));
solAssert(trueIndex != falseIndex, ""); solAssert(trueIndex != falseIndex, "");
m_context.addAssertion(m_context.newValue(*decl) == smtutil::Expression::ite( m_context.addAssertion(m_context.newValue(*decl) == smtutil::Expression::ite(
_condition, _condition,
@ -1666,7 +1697,7 @@ smtutil::Expression SMTEncoder::currentValue(VariableDeclaration const& _decl)
return m_context.variable(_decl)->currentValue(); return m_context.variable(_decl)->currentValue();
} }
smtutil::Expression SMTEncoder::valueAtIndex(VariableDeclaration const& _decl, int _index) smtutil::Expression SMTEncoder::valueAtIndex(VariableDeclaration const& _decl, unsigned _index)
{ {
solAssert(m_context.knownVariable(_decl), ""); solAssert(m_context.knownVariable(_decl), "");
return m_context.variable(_decl)->valueAtIndex(_index); return m_context.variable(_decl)->valueAtIndex(_index);
@ -1789,7 +1820,7 @@ SMTEncoder::VariableIndices SMTEncoder::copyVariableIndices()
void SMTEncoder::resetVariableIndices(VariableIndices const& _indices) void SMTEncoder::resetVariableIndices(VariableIndices const& _indices)
{ {
for (auto const& var: _indices) for (auto const& var: _indices)
m_context.variable(*var.first)->setIndex(var.second); m_context.variable(*var.first)->setIndex(static_cast<unsigned>(var.second));
} }
void SMTEncoder::clearIndices(ContractDefinition const* _contract, FunctionDefinition const* _function) void SMTEncoder::clearIndices(ContractDefinition const* _contract, FunctionDefinition const* _function)

View File

@ -157,10 +157,12 @@ protected:
/// Will also be used for assignments of tuple components. /// Will also be used for assignments of tuple components.
void assignment( void assignment(
Expression const& _left, Expression const& _left,
std::vector<smtutil::Expression> const& _right, smtutil::Expression const& _right,
TypePointer const& _type, TypePointer const& _type,
langutil::SourceLocation const& _location langutil::SourceLocation const& _location
); );
/// Handle assignments between tuples.
void tupleAssignment(Expression const& _left, Expression const& _right);
/// Computes the right hand side of a compound assignment. /// Computes the right hand side of a compound assignment.
smtutil::Expression compoundAssignment(Assignment const& _assignment); smtutil::Expression compoundAssignment(Assignment const& _assignment);
@ -181,6 +183,9 @@ protected:
void initializeLocalVariables(FunctionDefinition const& _function); void initializeLocalVariables(FunctionDefinition const& _function);
void initializeFunctionCallParameters(CallableDeclaration const& _function, std::vector<smtutil::Expression> const& _callArgs); void initializeFunctionCallParameters(CallableDeclaration const& _function, std::vector<smtutil::Expression> const& _callArgs);
void resetStateVariables(); void resetStateVariables();
/// Resets all references/pointers that have the same type or have
/// a subexpression of the same type as _varDecl.
void resetReferences(VariableDeclaration const& _varDecl);
/// @returns the type without storage pointer information if it has it. /// @returns the type without storage pointer information if it has it.
TypePointer typeWithoutPointer(TypePointer const& _type); TypePointer typeWithoutPointer(TypePointer const& _type);
@ -196,7 +201,7 @@ protected:
smtutil::Expression currentValue(VariableDeclaration const& _decl); smtutil::Expression currentValue(VariableDeclaration const& _decl);
/// @returns an expression denoting the value of the variable declared in @a _decl /// @returns an expression denoting the value of the variable declared in @a _decl
/// at the given index. Does not ensure that this index exists. /// at the given index. Does not ensure that this index exists.
smtutil::Expression valueAtIndex(VariableDeclaration const& _decl, int _index); smtutil::Expression valueAtIndex(VariableDeclaration const& _decl, unsigned _index);
/// Returns the expression corresponding to the AST node. /// Returns the expression corresponding to the AST node.
/// If _targetType is not null apply conversion. /// If _targetType is not null apply conversion.
/// Throws if the expression does not exist. /// Throws if the expression does not exist.

View File

@ -66,12 +66,12 @@ string SymbolicVariable::currentName() const
return uniqueSymbol(m_ssa->index()); return uniqueSymbol(m_ssa->index());
} }
smtutil::Expression SymbolicVariable::valueAtIndex(int _index) const smtutil::Expression SymbolicVariable::valueAtIndex(unsigned _index) const
{ {
return m_context.newVariable(uniqueSymbol(_index), m_sort); return m_context.newVariable(uniqueSymbol(_index), m_sort);
} }
string SymbolicVariable::nameAtIndex(int _index) const string SymbolicVariable::nameAtIndex(unsigned _index) const
{ {
return uniqueSymbol(_index); return uniqueSymbol(_index);
} }
@ -170,12 +170,12 @@ smtutil::Expression SymbolicFunctionVariable::currentFunctionValue() const
return m_declaration; return m_declaration;
} }
smtutil::Expression SymbolicFunctionVariable::valueAtIndex(int _index) const smtutil::Expression SymbolicFunctionVariable::valueAtIndex(unsigned _index) const
{ {
return m_abstract.valueAtIndex(_index); return m_abstract.valueAtIndex(_index);
} }
smtutil::Expression SymbolicFunctionVariable::functionValueAtIndex(int _index) const smtutil::Expression SymbolicFunctionVariable::functionValueAtIndex(unsigned _index) const
{ {
return SymbolicVariable::valueAtIndex(_index); return SymbolicVariable::valueAtIndex(_index);
} }
@ -304,7 +304,7 @@ smtutil::Expression SymbolicArrayVariable::currentValue(frontend::TypePointer co
return m_pair.currentValue(); return m_pair.currentValue();
} }
smtutil::Expression SymbolicArrayVariable::valueAtIndex(int _index) const smtutil::Expression SymbolicArrayVariable::valueAtIndex(unsigned _index) const
{ {
return m_pair.valueAtIndex(_index); return m_pair.valueAtIndex(_index);
} }

View File

@ -54,8 +54,8 @@ public:
virtual smtutil::Expression currentValue(frontend::TypePointer const& _targetType = TypePointer{}) const; virtual smtutil::Expression currentValue(frontend::TypePointer const& _targetType = TypePointer{}) const;
std::string currentName() const; std::string currentName() const;
virtual smtutil::Expression valueAtIndex(int _index) const; virtual smtutil::Expression valueAtIndex(unsigned _index) const;
virtual std::string nameAtIndex(int _index) const; virtual std::string nameAtIndex(unsigned _index) const;
virtual smtutil::Expression resetIndex(); virtual smtutil::Expression resetIndex();
virtual smtutil::Expression setIndex(unsigned _index); virtual smtutil::Expression setIndex(unsigned _index);
virtual smtutil::Expression increaseIndex(); virtual smtutil::Expression increaseIndex();
@ -165,10 +165,10 @@ public:
// Explicit request the function declaration. // Explicit request the function declaration.
smtutil::Expression currentFunctionValue() const; smtutil::Expression currentFunctionValue() const;
smtutil::Expression valueAtIndex(int _index) const override; smtutil::Expression valueAtIndex(unsigned _index) const override;
// Explicit request the function declaration. // Explicit request the function declaration.
smtutil::Expression functionValueAtIndex(int _index) const; smtutil::Expression functionValueAtIndex(unsigned _index) const;
smtutil::Expression resetIndex() override; smtutil::Expression resetIndex() override;
smtutil::Expression setIndex(unsigned _index) override; smtutil::Expression setIndex(unsigned _index) override;
@ -251,7 +251,7 @@ public:
SymbolicArrayVariable(SymbolicArrayVariable&&) = default; SymbolicArrayVariable(SymbolicArrayVariable&&) = default;
smtutil::Expression currentValue(frontend::TypePointer const& _targetType = TypePointer{}) const override; smtutil::Expression currentValue(frontend::TypePointer const& _targetType = TypePointer{}) const override;
smtutil::Expression valueAtIndex(int _index) const override; smtutil::Expression valueAtIndex(unsigned _index) const override;
smtutil::Expression resetIndex() override { SymbolicVariable::resetIndex(); return m_pair.resetIndex(); } smtutil::Expression resetIndex() override { SymbolicVariable::resetIndex(); return m_pair.resetIndex(); }
smtutil::Expression setIndex(unsigned _index) override { SymbolicVariable::setIndex(_index); return m_pair.setIndex(_index); } smtutil::Expression setIndex(unsigned _index) override { SymbolicVariable::setIndex(_index); return m_pair.setIndex(_index); }
smtutil::Expression increaseIndex() override { SymbolicVariable::increaseIndex(); return m_pair.increaseIndex(); } smtutil::Expression increaseIndex() override { SymbolicVariable::increaseIndex(); return m_pair.increaseIndex(); }

View File

@ -982,7 +982,7 @@ string CompilerStack::applyRemapping(string const& _path, string const& _context
bestMatchTarget = util::sanitizePath(redir.target); bestMatchTarget = util::sanitizePath(redir.target);
} }
string path = bestMatchTarget; string path = bestMatchTarget;
path.append(_path.begin() + longestPrefix, _path.end()); path.append(_path.begin() + static_cast<string::difference_type>(longestPrefix), _path.end());
return path; return path;
} }

View File

@ -54,8 +54,8 @@ GasEstimator::ASTGasConsumptionSelfAccumulated GasEstimator::structuralEstimatio
{ {
solAssert(!!block.startState, ""); solAssert(!!block.startState, "");
GasMeter meter(block.startState->copy(), m_evmVersion); GasMeter meter(block.startState->copy(), m_evmVersion);
auto const end = _items.begin() + block.end; auto const end = _items.begin() + static_cast<ptrdiff_t>(block.end);
for (auto iter = _items.begin() + block.begin; iter != end; ++iter) for (auto iter = _items.begin() + static_cast<ptrdiff_t>(block.begin); iter != end; ++iter)
particularCosts[iter->location()] += meter.estimateMax(*iter); particularCosts[iter->location()] += meter.estimateMax(*iter);
} }

View File

@ -111,7 +111,8 @@ Json::Value formatErrorWithException(
bool const& _warning, bool const& _warning,
string const& _type, string const& _type,
string const& _component, string const& _component,
string const& _message string const& _message,
optional<ErrorId> _errorId = nullopt
) )
{ {
string message; string message;
@ -122,7 +123,7 @@ Json::Value formatErrorWithException(
else else
message = _message; message = _message;
return formatError( Json::Value error = formatError(
_warning, _warning,
_type, _type,
_component, _component,
@ -131,6 +132,11 @@ Json::Value formatErrorWithException(
formatSourceLocation(boost::get_error_info<errinfo_sourceLocation>(_exception)), formatSourceLocation(boost::get_error_info<errinfo_sourceLocation>(_exception)),
formatSecondarySourceLocation(boost::get_error_info<errinfo_secondarySourceLocation>(_exception)) formatSecondarySourceLocation(boost::get_error_info<errinfo_secondarySourceLocation>(_exception))
); );
if (_errorId)
error["errorCode"] = to_string(_errorId.value().error);
return error;
} }
map<string, set<string>> requestedContractNames(Json::Value const& _outputSelection) map<string, set<string>> requestedContractNames(Json::Value const& _outputSelection)
@ -857,7 +863,8 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
err.type() == Error::Type::Warning, err.type() == Error::Type::Warning,
err.typeName(), err.typeName(),
"general", "general",
"" "",
err.errorId()
)); ));
} }
} }

View File

@ -50,7 +50,7 @@ Json::Value StorageLayout::generate(VariableDeclaration const& _var, u256 const&
TypePointer varType = _var.type(); TypePointer varType = _var.type();
varEntry["label"] = _var.name(); varEntry["label"] = _var.name();
varEntry["astId"] = int(_var.id()); varEntry["astId"] = static_cast<int>(_var.id());
varEntry["contract"] = m_contract->fullyQualifiedName(); varEntry["contract"] = m_contract->fullyQualifiedName();
varEntry["slot"] = _slot.str(); varEntry["slot"] = _slot.str();
varEntry["offset"] = _offset; varEntry["offset"] = _offset;

View File

@ -359,6 +359,13 @@ void AsmAnalyzer::operator()(Switch const& _switch)
{ {
yulAssert(_switch.expression, ""); yulAssert(_switch.expression, "");
if (_switch.cases.size() == 1 && !_switch.cases[0].value)
m_errorReporter.warning(
9592_error,
_switch.location,
"\"switch\" statement with only a default case."
);
YulString valueType = expectExpression(*_switch.expression); YulString valueType = expectExpression(*_switch.expression);
set<u256> cases; set<u256> cases;

View File

@ -22,8 +22,11 @@
#include <libyul/Exceptions.h> #include <libyul/Exceptions.h>
#include <libsolutil/CommonData.h> #include <libsolutil/CommonData.h>
#include <libsolutil/Visitor.h>
#include <boost/range/adaptor/reversed.hpp> #include <boost/range/adaptor/reversed.hpp>
#include <boost/range/adaptor/map.hpp>
#include <boost/range/adaptor/transformed.hpp>
using namespace std; using namespace std;
using namespace solidity; using namespace solidity;
@ -81,6 +84,16 @@ bytes toBytes(ValueType _vt)
return toBytes(uint8_t(_vt)); return toBytes(uint8_t(_vt));
} }
ValueType toValueType(wasm::Type _type)
{
if (_type == wasm::Type::i32)
return ValueType::I32;
else if (_type == wasm::Type::i64)
return ValueType::I64;
else
yulAssert(false, "Invalid wasm variable type");
}
enum class Export: uint8_t enum class Export: uint8_t
{ {
Function = 0x0, Function = 0x0,
@ -130,7 +143,17 @@ bytes toBytes(Opcode _o)
return toBytes(uint8_t(_o)); return toBytes(uint8_t(_o));
} }
static std::map<string, uint8_t> const builtins = { 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}, {"i32.load", 0x28},
{"i64.load", 0x29}, {"i64.load", 0x29},
{"i32.load8_s", 0x2c}, {"i32.load8_s", 0x2c},
@ -240,53 +263,94 @@ bytes lebEncodeSigned(int64_t _n)
bytes prefixSize(bytes _data) bytes prefixSize(bytes _data)
{ {
size_t size = _data.size(); size_t size = _data.size();
return lebEncode(size) + std::move(_data); return lebEncode(size) + move(_data);
} }
bytes makeSection(Section _section, bytes _data) bytes makeSection(Section _section, bytes _data)
{ {
return toBytes(_section) + prefixSize(std::move(_data)); return toBytes(_section) + prefixSize(move(_data));
}
/// This is a kind of run-length-encoding of local types.
vector<pair<size_t, ValueType>> groupLocalVariables(vector<VariableDeclaration> _localVariables)
{
vector<pair<size_t, ValueType>> localEntries;
size_t entrySize = 0;
ValueType entryType = ValueType::I32; // Any type would work here
for (VariableDeclaration const& localVariable: _localVariables)
{
ValueType variableType = toValueType(localVariable.type);
if (variableType != entryType)
{
if (entrySize > 0)
localEntries.emplace_back(entrySize, entryType);
entryType = variableType;
entrySize = 0;
}
++entrySize;
}
if (entrySize > 0)
localEntries.emplace_back(entrySize, entryType);
return localEntries;
} }
} }
bytes BinaryTransform::run(Module const& _module) bytes BinaryTransform::run(Module const& _module)
{ {
BinaryTransform bt; map<Type, vector<string>> const types = typeToFunctionMap(_module.imports, _module.functions);
for (size_t i = 0; i < _module.globals.size(); ++i) map<string, size_t> const globalIDs = enumerateGlobals(_module);
bt.m_globals[_module.globals[i].variableName] = i; map<string, size_t> const functionIDs = enumerateFunctions(_module);
map<string, size_t> const functionTypes = enumerateFunctionTypes(types);
size_t funID = 0; yulAssert(globalIDs.size() == _module.globals.size(), "");
for (FunctionImport const& fun: _module.imports) yulAssert(functionIDs.size() == _module.imports.size() + _module.functions.size(), "");
bt.m_functions[fun.internalName] = funID++; yulAssert(functionTypes.size() == functionIDs.size(), "");
for (FunctionDefinition const& fun: _module.functions) yulAssert(functionTypes.size() >= types.size(), "");
bt.m_functions[fun.name] = funID++;
bytes ret{0, 'a', 's', 'm'}; bytes ret{0, 'a', 's', 'm'};
// version // version
ret += bytes{1, 0, 0, 0}; ret += bytes{1, 0, 0, 0};
ret += bt.typeSection(_module.imports, _module.functions); ret += typeSection(types);
ret += bt.importSection(_module.imports); ret += importSection(_module.imports, functionTypes);
ret += bt.functionSection(_module.functions); ret += functionSection(_module.functions, functionTypes);
ret += bt.memorySection(); ret += memorySection();
ret += bt.globalSection(); ret += globalSection(_module.globals);
ret += bt.exportSection(); ret += exportSection(functionIDs);
map<string, pair<size_t, size_t>> subModulePosAndSize;
for (auto const& sub: _module.subModules) for (auto const& sub: _module.subModules)
{ {
// TODO should we prefix and / or shorten the name? // TODO should we prefix and / or shorten the name?
bytes data = BinaryTransform::run(sub.second); bytes data = BinaryTransform::run(sub.second);
size_t length = data.size(); size_t length = data.size();
ret += bt.customSection(sub.first, std::move(data)); ret += customSection(sub.first, move(data));
bt.m_subModulePosAndSize[sub.first] = {ret.size() - length, length}; subModulePosAndSize[sub.first] = {ret.size() - length, length};
} }
BinaryTransform bt(
move(globalIDs),
move(functionIDs),
move(functionTypes),
move(subModulePosAndSize)
);
ret += bt.codeSection(_module.functions); ret += bt.codeSection(_module.functions);
return ret; return ret;
} }
bytes BinaryTransform::operator()(Literal const& _literal) bytes BinaryTransform::operator()(Literal const& _literal)
{ {
return toBytes(Opcode::I64Const) + lebEncodeSigned(_literal.value); return std::visit(GenericVisitor{
[&](uint32_t _value) -> bytes { return toBytes(Opcode::I32Const) + lebEncodeSigned(static_cast<int32_t>(_value)); },
[&](uint64_t _value) -> bytes { return toBytes(Opcode::I64Const) + lebEncodeSigned(static_cast<int64_t>(_value)); },
}, _literal.value);
} }
bytes BinaryTransform::operator()(StringLiteral const&) bytes BinaryTransform::operator()(StringLiteral const&)
@ -302,7 +366,7 @@ bytes BinaryTransform::operator()(LocalVariable const& _variable)
bytes BinaryTransform::operator()(GlobalVariable const& _variable) bytes BinaryTransform::operator()(GlobalVariable const& _variable)
{ {
return toBytes(Opcode::GlobalGet) + lebEncode(m_globals.at(_variable.name)); return toBytes(Opcode::GlobalGet) + lebEncode(m_globalIDs.at(_variable.name));
} }
bytes BinaryTransform::operator()(BuiltinCall const& _call) bytes BinaryTransform::operator()(BuiltinCall const& _call)
@ -311,12 +375,12 @@ bytes BinaryTransform::operator()(BuiltinCall const& _call)
// they are references to object names that should not end up in the code. // they are references to object names that should not end up in the code.
if (_call.functionName == "dataoffset") if (_call.functionName == "dataoffset")
{ {
string name = std::get<StringLiteral>(_call.arguments.at(0)).value; string name = get<StringLiteral>(_call.arguments.at(0)).value;
return toBytes(Opcode::I64Const) + lebEncodeSigned(m_subModulePosAndSize.at(name).first); return toBytes(Opcode::I64Const) + lebEncodeSigned(m_subModulePosAndSize.at(name).first);
} }
else if (_call.functionName == "datasize") else if (_call.functionName == "datasize")
{ {
string name = std::get<StringLiteral>(_call.arguments.at(0)).value; string name = get<StringLiteral>(_call.arguments.at(0)).value;
return toBytes(Opcode::I64Const) + lebEncodeSigned(m_subModulePosAndSize.at(name).second); return toBytes(Opcode::I64Const) + lebEncodeSigned(m_subModulePosAndSize.at(name).second);
} }
@ -331,20 +395,24 @@ bytes BinaryTransform::operator()(BuiltinCall const& _call)
else else
{ {
yulAssert(builtins.count(_call.functionName), "Builtin " + _call.functionName + " not found"); yulAssert(builtins.count(_call.functionName), "Builtin " + _call.functionName + " not found");
bytes ret = std::move(args) + toBytes(builtins.at(_call.functionName)); bytes ret = move(args) + toBytes(builtins.at(_call.functionName));
if ( if (
_call.functionName.find(".load") != string::npos || _call.functionName.find(".load") != string::npos ||
_call.functionName.find(".store") != string::npos _call.functionName.find(".store") != string::npos
) )
// alignment and offset // Alignment hint and offset. Interpreters ignore the alignment. JITs/AOTs can take it
ret += bytes{{3, 0}}; // into account to generate more efficient code but if the hint is invalid it could
// actually be more expensive. It's best to hint at 1-byte alignment if we don't plan
// to control the memory layout accordingly.
ret += bytes{{0, 0}}; // 2^0 == 1-byte alignment
return ret; return ret;
} }
} }
bytes BinaryTransform::operator()(FunctionCall const& _call) bytes BinaryTransform::operator()(FunctionCall const& _call)
{ {
return visit(_call.arguments) + toBytes(Opcode::Call) + lebEncode(m_functions.at(_call.functionName)); return visit(_call.arguments) + toBytes(Opcode::Call) + lebEncode(m_functionIDs.at(_call.functionName));
} }
bytes BinaryTransform::operator()(LocalAssignment const& _assignment) bytes BinaryTransform::operator()(LocalAssignment const& _assignment)
@ -360,7 +428,7 @@ bytes BinaryTransform::operator()(GlobalAssignment const& _assignment)
return return
std::visit(*this, *_assignment.value) + std::visit(*this, *_assignment.value) +
toBytes(Opcode::GlobalSet) + toBytes(Opcode::GlobalSet) +
lebEncode(m_globals.at(_assignment.variableName)); lebEncode(m_globalIDs.at(_assignment.variableName));
} }
bytes BinaryTransform::operator()(If const& _if) bytes BinaryTransform::operator()(If const& _if)
@ -428,16 +496,18 @@ bytes BinaryTransform::operator()(FunctionDefinition const& _function)
{ {
bytes ret; bytes ret;
// This is a kind of run-length-encoding of local types. Has to be adapted once vector<pair<size_t, ValueType>> localEntries = groupLocalVariables(_function.locals);
// we have locals of different types. ret += lebEncode(localEntries.size());
ret += lebEncode(1); // number of locals groups for (pair<size_t, ValueType> const& entry: localEntries)
ret += lebEncode(_function.locals.size()); {
ret += toBytes(ValueType::I64); ret += lebEncode(entry.first);
ret += toBytes(entry.second);
}
m_locals.clear(); m_locals.clear();
size_t varIdx = 0; size_t varIdx = 0;
for (size_t i = 0; i < _function.parameterNames.size(); ++i) for (size_t i = 0; i < _function.parameters.size(); ++i)
m_locals[_function.parameterNames[i]] = varIdx++; m_locals[_function.parameters[i].name] = varIdx++;
for (size_t i = 0; i < _function.locals.size(); ++i) for (size_t i = 0; i < _function.locals.size(); ++i)
m_locals[_function.locals[i].variableName] = varIdx++; m_locals[_function.locals[i].variableName] = varIdx++;
@ -448,48 +518,49 @@ bytes BinaryTransform::operator()(FunctionDefinition const& _function)
yulAssert(m_labels.empty(), "Stray labels."); yulAssert(m_labels.empty(), "Stray labels.");
return prefixSize(std::move(ret)); return prefixSize(move(ret));
} }
BinaryTransform::Type BinaryTransform::typeOf(FunctionImport const& _import) BinaryTransform::Type BinaryTransform::typeOf(FunctionImport const& _import)
{ {
return { return {
encodeTypes(_import.paramTypes), encodeTypes(_import.paramTypes),
encodeTypes(_import.returnType ? vector<string>(1, *_import.returnType) : vector<string>()) encodeTypes(_import.returnType ? vector<wasm::Type>(1, *_import.returnType) : vector<wasm::Type>())
}; };
} }
BinaryTransform::Type BinaryTransform::typeOf(FunctionDefinition const& _funDef) BinaryTransform::Type BinaryTransform::typeOf(FunctionDefinition const& _funDef)
{ {
return { return {
encodeTypes(vector<string>(_funDef.parameterNames.size(), "i64")), encodeTypes(_funDef.parameters),
encodeTypes(vector<string>(_funDef.returns ? 1 : 0, "i64")) encodeTypes(_funDef.returnType ? vector<wasm::Type>(1, *_funDef.returnType) : vector<wasm::Type>())
}; };
} }
uint8_t BinaryTransform::encodeType(string const& _typeName) uint8_t BinaryTransform::encodeType(wasm::Type _type)
{ {
if (_typeName == "i32") return uint8_t(toValueType(_type));
return uint8_t(ValueType::I32);
else if (_typeName == "i64")
return uint8_t(ValueType::I64);
else
yulAssert(false, "");
return 0;
} }
vector<uint8_t> BinaryTransform::encodeTypes(vector<string> const& _typeNames) vector<uint8_t> BinaryTransform::encodeTypes(vector<wasm::Type> const& _types)
{ {
vector<uint8_t> result; vector<uint8_t> result;
for (auto const& t: _typeNames) for (wasm::Type t: _types)
result.emplace_back(encodeType(t)); result.emplace_back(encodeType(t));
return result; return result;
} }
bytes BinaryTransform::typeSection( vector<uint8_t> BinaryTransform::encodeTypes(wasm::TypedNameList const& _typedNameList)
vector<FunctionImport> const& _imports, {
vector<FunctionDefinition> const& _functions 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
) )
{ {
map<Type, vector<string>> types; map<Type, vector<string>> types;
@ -498,12 +569,50 @@ bytes BinaryTransform::typeSection(
for (auto const& fun: _functions) for (auto const& fun: _functions)
types[typeOf(fun)].emplace_back(fun.name); types[typeOf(fun)].emplace_back(fun.name);
bytes result; return types;
size_t index = 0; }
for (auto const& [type, funNames]: types)
map<string, size_t> BinaryTransform::enumerateGlobals(Module const& _module)
{
map<string, size_t> globals;
for (size_t i = 0; i < _module.globals.size(); ++i)
globals[_module.globals[i].variableName] = i;
return globals;
}
map<string, size_t> BinaryTransform::enumerateFunctions(Module const& _module)
{
map<string, size_t> functions;
size_t funID = 0;
for (FunctionImport const& fun: _module.imports)
functions[fun.internalName] = funID++;
for (FunctionDefinition const& fun: _module.functions)
functions[fun.name] = funID++;
return functions;
}
map<string, size_t> BinaryTransform::enumerateFunctionTypes(map<Type, vector<string>> const& _typeToFunctionMap)
{
map<string, size_t> functionTypes;
size_t typeID = 0;
for (vector<string> const& funNames: _typeToFunctionMap | boost::adaptors::map_values)
{ {
for (string const& name: funNames) for (string const& name: funNames)
m_functionTypes[name] = index; functionTypes[name] = typeID;
++typeID;
}
return functionTypes;
}
bytes BinaryTransform::typeSection(map<BinaryTransform::Type, vector<string>> const& _typeToFunctionMap)
{
bytes result;
size_t index = 0;
for (Type const& type: _typeToFunctionMap | boost::adaptors::map_keys)
{
result += toBytes(ValueType::Function); result += toBytes(ValueType::Function);
result += lebEncode(type.first.size()) + type.first; result += lebEncode(type.first.size()) + type.first;
result += lebEncode(type.second.size()) + type.second; result += lebEncode(type.second.size()) + type.second;
@ -511,11 +620,12 @@ bytes BinaryTransform::typeSection(
index++; index++;
} }
return makeSection(Section::TYPE, lebEncode(index) + std::move(result)); return makeSection(Section::TYPE, lebEncode(index) + move(result));
} }
bytes BinaryTransform::importSection( bytes BinaryTransform::importSection(
vector<FunctionImport> const& _imports vector<FunctionImport> const& _imports,
map<string, size_t> const& _functionTypes
) )
{ {
bytes result = lebEncode(_imports.size()); bytes result = lebEncode(_imports.size());
@ -526,17 +636,20 @@ bytes BinaryTransform::importSection(
encodeName(import.module) + encodeName(import.module) +
encodeName(import.externalName) + encodeName(import.externalName) +
toBytes(importKind) + toBytes(importKind) +
lebEncode(m_functionTypes[import.internalName]); lebEncode(_functionTypes.at(import.internalName));
} }
return makeSection(Section::IMPORT, std::move(result)); return makeSection(Section::IMPORT, move(result));
} }
bytes BinaryTransform::functionSection(vector<FunctionDefinition> const& _functions) bytes BinaryTransform::functionSection(
vector<FunctionDefinition> const& _functions,
map<string, size_t> const& _functionTypes
)
{ {
bytes result = lebEncode(_functions.size()); bytes result = lebEncode(_functions.size());
for (auto const& fun: _functions) for (auto const& fun: _functions)
result += lebEncode(m_functionTypes.at(fun.name)); result += lebEncode(_functionTypes.at(fun.name));
return makeSection(Section::FUNCTION, std::move(result)); return makeSection(Section::FUNCTION, move(result));
} }
bytes BinaryTransform::memorySection() bytes BinaryTransform::memorySection()
@ -544,35 +657,38 @@ bytes BinaryTransform::memorySection()
bytes result = lebEncode(1); bytes result = lebEncode(1);
result.push_back(static_cast<uint8_t>(LimitsKind::Min)); result.push_back(static_cast<uint8_t>(LimitsKind::Min));
result.push_back(1); // initial length result.push_back(1); // initial length
return makeSection(Section::MEMORY, std::move(result)); return makeSection(Section::MEMORY, move(result));
} }
bytes BinaryTransform::globalSection() bytes BinaryTransform::globalSection(vector<wasm::GlobalVariableDeclaration> const& _globals)
{ {
bytes result = lebEncode(m_globals.size()); bytes result = lebEncode(_globals.size());
for (size_t i = 0; i < m_globals.size(); ++i) for (wasm::GlobalVariableDeclaration const& global: _globals)
{
ValueType globalType = toValueType(global.type);
result += result +=
toBytes(ValueType::I64) + toBytes(globalType) +
lebEncode(static_cast<uint8_t>(Mutability::Var)) + lebEncode(static_cast<uint8_t>(Mutability::Var)) +
toBytes(Opcode::I64Const) + toBytes(constOpcodeFor(globalType)) +
lebEncodeSigned(0) + lebEncodeSigned(0) +
toBytes(Opcode::End); toBytes(Opcode::End);
}
return makeSection(Section::GLOBAL, std::move(result)); return makeSection(Section::GLOBAL, move(result));
} }
bytes BinaryTransform::exportSection() bytes BinaryTransform::exportSection(map<string, size_t> const& _functionIDs)
{ {
bytes result = lebEncode(2); bytes result = lebEncode(2);
result += encodeName("memory") + toBytes(Export::Memory) + lebEncode(0); result += encodeName("memory") + toBytes(Export::Memory) + lebEncode(0);
result += encodeName("main") + toBytes(Export::Function) + lebEncode(m_functions.at("main")); result += encodeName("main") + toBytes(Export::Function) + lebEncode(_functionIDs.at("main"));
return makeSection(Section::EXPORT, std::move(result)); return makeSection(Section::EXPORT, move(result));
} }
bytes BinaryTransform::customSection(string const& _name, bytes _data) bytes BinaryTransform::customSection(string const& _name, bytes _data)
{ {
bytes result = encodeName(_name) + std::move(_data); bytes result = encodeName(_name) + move(_data);
return makeSection(Section::CUSTOM, std::move(result)); return makeSection(Section::CUSTOM, move(result));
} }
bytes BinaryTransform::codeSection(vector<wasm::FunctionDefinition> const& _functions) bytes BinaryTransform::codeSection(vector<wasm::FunctionDefinition> const& _functions)
@ -580,7 +696,7 @@ bytes BinaryTransform::codeSection(vector<wasm::FunctionDefinition> const& _func
bytes result = lebEncode(_functions.size()); bytes result = lebEncode(_functions.size());
for (FunctionDefinition const& fun: _functions) for (FunctionDefinition const& fun: _functions)
result += (*this)(fun); result += (*this)(fun);
return makeSection(Section::CODE, std::move(result)); return makeSection(Section::CODE, move(result));
} }
bytes BinaryTransform::visit(vector<Expression> const& _expressions) bytes BinaryTransform::visit(vector<Expression> const& _expressions)
@ -611,7 +727,7 @@ bytes BinaryTransform::encodeLabelIdx(string const& _label) const
yulAssert(false, "Label not found."); yulAssert(false, "Label not found.");
} }
bytes BinaryTransform::encodeName(std::string const& _name) bytes BinaryTransform::encodeName(string const& _name)
{ {
// UTF-8 is allowed here by the Wasm spec, but since all names here should stem from // UTF-8 is allowed here by the Wasm spec, but since all names here should stem from
// Solidity or Yul identifiers or similar, non-ascii characters ending up here // Solidity or Yul identifiers or similar, non-ascii characters ending up here

View File

@ -55,23 +55,50 @@ public:
bytes operator()(wasm::FunctionDefinition const& _function); bytes operator()(wasm::FunctionDefinition const& _function);
private: private:
BinaryTransform(
std::map<std::string, size_t> _globalIDs,
std::map<std::string, size_t> _functionIDs,
std::map<std::string, size_t> _functionTypes,
std::map<std::string, std::pair<size_t, size_t>> _subModulePosAndSize
):
m_globalIDs(std::move(_globalIDs)),
m_functionIDs(std::move(_functionIDs)),
m_functionTypes(std::move(_functionTypes)),
m_subModulePosAndSize(std::move(_subModulePosAndSize))
{}
using Type = std::pair<std::vector<std::uint8_t>, std::vector<std::uint8_t>>; using Type = std::pair<std::vector<std::uint8_t>, std::vector<std::uint8_t>>;
static Type typeOf(wasm::FunctionImport const& _import); static Type typeOf(wasm::FunctionImport const& _import);
static Type typeOf(wasm::FunctionDefinition const& _funDef); static Type typeOf(wasm::FunctionDefinition const& _funDef);
static uint8_t encodeType(std::string const& _typeName); static uint8_t encodeType(wasm::Type _type);
static std::vector<uint8_t> encodeTypes(std::vector<std::string> const& _typeNames); static std::vector<uint8_t> encodeTypes(std::vector<wasm::Type> const& _types);
bytes typeSection( 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, std::vector<wasm::FunctionImport> const& _imports,
std::vector<wasm::FunctionDefinition> const& _functions std::vector<wasm::FunctionDefinition> const& _functions
); );
bytes importSection(std::vector<wasm::FunctionImport> const& _imports); static std::map<std::string, size_t> enumerateGlobals(Module const& _module);
bytes functionSection(std::vector<wasm::FunctionDefinition> const& _functions); static std::map<std::string, size_t> enumerateFunctions(Module const& _module);
bytes memorySection(); static std::map<std::string, size_t> enumerateFunctionTypes(
bytes globalSection(); std::map<Type, std::vector<std::string>> const& _typeToFunctionMap
bytes exportSection(); );
bytes customSection(std::string const& _name, bytes _data);
static bytes typeSection(std::map<Type, std::vector<std::string>> const& _typeToFunctionMap);
static bytes importSection(
std::vector<wasm::FunctionImport> const& _imports,
std::map<std::string, size_t> const& _functionTypes
);
static bytes functionSection(
std::vector<wasm::FunctionDefinition> const& _functions,
std::map<std::string, size_t> const& _functionTypes
);
static bytes memorySection();
static bytes globalSection(std::vector<wasm::GlobalVariableDeclaration> const& _globals);
static bytes exportSection(std::map<std::string, size_t> const& _functionIDs);
static bytes customSection(std::string const& _name, bytes _data);
bytes codeSection(std::vector<wasm::FunctionDefinition> const& _functions); bytes codeSection(std::vector<wasm::FunctionDefinition> const& _functions);
bytes visit(std::vector<wasm::Expression> const& _expressions); bytes visit(std::vector<wasm::Expression> const& _expressions);
@ -81,12 +108,13 @@ private:
static bytes encodeName(std::string const& _name); static bytes encodeName(std::string const& _name);
std::map<std::string, size_t> const m_globalIDs;
std::map<std::string, size_t> const m_functionIDs;
std::map<std::string, size_t> const m_functionTypes;
std::map<std::string, std::pair<size_t, size_t>> const m_subModulePosAndSize;
std::map<std::string, size_t> m_locals; std::map<std::string, size_t> m_locals;
std::map<std::string, size_t> m_globals;
std::map<std::string, size_t> m_functions;
std::map<std::string, size_t> m_functionTypes;
std::vector<std::string> m_labels; std::vector<std::string> m_labels;
std::map<std::string, std::pair<size_t, size_t>> m_subModulePosAndSize;
}; };
} }

View File

@ -20,7 +20,10 @@
#include <libyul/backends/wasm/TextTransform.h> #include <libyul/backends/wasm/TextTransform.h>
#include <libyul/Exceptions.h>
#include <libsolutil/StringUtils.h> #include <libsolutil/StringUtils.h>
#include <libsolutil/Visitor.h>
#include <boost/algorithm/string/join.hpp> #include <boost/algorithm/string/join.hpp>
#include <boost/algorithm/string/replace.hpp> #include <boost/algorithm/string/replace.hpp>
@ -44,9 +47,9 @@ string TextTransform::run(wasm::Module const& _module)
{ {
ret += " (import \"" + imp.module + "\" \"" + imp.externalName + "\" (func $" + imp.internalName; ret += " (import \"" + imp.module + "\" \"" + imp.externalName + "\" (func $" + imp.internalName;
if (!imp.paramTypes.empty()) if (!imp.paramTypes.empty())
ret += " (param" + joinHumanReadablePrefixed(imp.paramTypes, " ", " ") + ")"; ret += " (param" + joinHumanReadablePrefixed(imp.paramTypes | boost::adaptors::transformed(encodeType), " ", " ") + ")";
if (imp.returnType) if (imp.returnType)
ret += " (result " + *imp.returnType + ")"; ret += " (result " + encodeType(*imp.returnType) + ")";
ret += "))\n"; ret += "))\n";
} }
@ -56,7 +59,7 @@ string TextTransform::run(wasm::Module const& _module)
ret += " (export \"main\" (func $main))\n"; ret += " (export \"main\" (func $main))\n";
for (auto const& g: _module.globals) for (auto const& g: _module.globals)
ret += " (global $" + g.variableName + " (mut i64) (i64.const 0))\n"; ret += " (global $" + g.variableName + " (mut " + encodeType(g.type) + ") (" + encodeType(g.type) + ".const 0))\n";
ret += "\n"; ret += "\n";
for (auto const& f: _module.functions) for (auto const& f: _module.functions)
ret += transform(f) + "\n"; ret += transform(f) + "\n";
@ -65,7 +68,10 @@ string TextTransform::run(wasm::Module const& _module)
string TextTransform::operator()(wasm::Literal const& _literal) string TextTransform::operator()(wasm::Literal const& _literal)
{ {
return "(i64.const " + to_string(_literal.value) + ")"; return std::visit(GenericVisitor{
[&](uint32_t _value) -> string { return "(i32.const " + to_string(_value) + ")"; },
[&](uint64_t _value) -> string { return "(i64.const " + to_string(_value) + ")"; },
}, _literal.value);
} }
string TextTransform::operator()(wasm::StringLiteral const& _literal) string TextTransform::operator()(wasm::StringLiteral const& _literal)
@ -162,12 +168,12 @@ string TextTransform::indented(string const& _in)
string TextTransform::transform(wasm::FunctionDefinition const& _function) string TextTransform::transform(wasm::FunctionDefinition const& _function)
{ {
string ret = "(func $" + _function.name + "\n"; string ret = "(func $" + _function.name + "\n";
for (auto const& param: _function.parameterNames) for (auto const& param: _function.parameters)
ret += " (param $" + param + " i64)\n"; ret += " (param $" + param.name + " " + encodeType(param.type) + ")\n";
if (_function.returns) if (_function.returnType.has_value())
ret += " (result i64)\n"; ret += " (result " + encodeType(_function.returnType.value()) + ")\n";
for (auto const& local: _function.locals) for (auto const& local: _function.locals)
ret += " (local $" + local.variableName + " i64)\n"; ret += " (local $" + local.variableName + " " + encodeType(local.type) + ")\n";
ret += indented(joinTransformed(_function.body, '\n')); ret += indented(joinTransformed(_function.body, '\n'));
if (ret.back() != '\n') if (ret.back() != '\n')
ret += '\n'; ret += '\n';
@ -193,3 +199,13 @@ string TextTransform::joinTransformed(vector<wasm::Expression> const& _expressio
} }
return ret; return ret;
} }
string TextTransform::encodeType(wasm::Type _type)
{
if (_type == wasm::Type::i32)
return "i32";
else if (_type == wasm::Type::i64)
return "i64";
else
yulAssert(false, "Invalid wasm type");
}

View File

@ -63,6 +63,8 @@ private:
std::vector<wasm::Expression> const& _expressions, std::vector<wasm::Expression> const& _expressions,
char _separator = ' ' char _separator = ' '
); );
static std::string encodeType(wasm::Type _type);
}; };
} }

View File

@ -30,6 +30,15 @@
namespace solidity::yul::wasm namespace solidity::yul::wasm
{ {
enum class Type
{
i32,
i64,
};
struct TypedName { std::string name; Type type; };
using TypedNameList = std::vector<TypedName>;
struct Literal; struct Literal;
struct StringLiteral; struct StringLiteral;
struct LocalVariable; struct LocalVariable;
@ -50,7 +59,7 @@ using Expression = std::variant<
Block, If, Loop, Branch, BranchIf, Return Block, If, Loop, Branch, BranchIf, Return
>; >;
struct Literal { uint64_t value; }; struct Literal { std::variant<uint32_t, uint64_t> value; };
struct StringLiteral { std::string value; }; struct StringLiteral { std::string value; };
struct LocalVariable { std::string name; }; struct LocalVariable { std::string name; };
struct GlobalVariable { std::string name; }; struct GlobalVariable { std::string name; };
@ -70,21 +79,21 @@ struct Branch { Label label; };
struct Return {}; struct Return {};
struct BranchIf { Label label; std::unique_ptr<Expression> condition; }; struct BranchIf { Label label; std::unique_ptr<Expression> condition; };
struct VariableDeclaration { std::string variableName; }; struct VariableDeclaration { std::string variableName; Type type; };
struct GlobalVariableDeclaration { std::string variableName; }; struct GlobalVariableDeclaration { std::string variableName; Type type; };
struct FunctionImport { struct FunctionImport {
std::string module; std::string module;
std::string externalName; std::string externalName;
std::string internalName; std::string internalName;
std::vector<std::string> paramTypes; std::vector<Type> paramTypes;
std::optional<std::string> returnType; std::optional<Type> returnType;
}; };
struct FunctionDefinition struct FunctionDefinition
{ {
std::string name; std::string name;
std::vector<std::string> parameterNames; std::vector<TypedName> parameters;
bool returns; std::optional<Type> returnType;
std::vector<VariableDeclaration> locals; std::vector<VariableDeclaration> locals;
std::vector<Expression> body; std::vector<Expression> body;
}; };

View File

@ -88,7 +88,7 @@ wasm::Expression WasmCodeTransform::operator()(VariableDeclaration const& _varDe
for (auto const& var: _varDecl.variables) for (auto const& var: _varDecl.variables)
{ {
variableNames.emplace_back(var.name.str()); variableNames.emplace_back(var.name.str());
m_localVariables.emplace_back(wasm::VariableDeclaration{variableNames.back()}); m_localVariables.emplace_back(wasm::VariableDeclaration{variableNames.back(), wasm::Type::i64});
} }
if (_varDecl.value) if (_varDecl.value)
@ -127,10 +127,10 @@ wasm::Expression WasmCodeTransform::operator()(FunctionCall const& _call)
builtin->name.str().substr(4), builtin->name.str().substr(4),
builtin->name.str(), builtin->name.str(),
{}, {},
builtin->returns.empty() ? nullopt : make_optional<string>(builtin->returns.front().str()) builtin->returns.empty() ? nullopt : make_optional<wasm::Type>(translatedType(builtin->returns.front()))
}; };
for (auto const& param: builtin->parameters) for (auto const& param: builtin->parameters)
imp.paramTypes.emplace_back(param.str()); imp.paramTypes.emplace_back(translatedType(param));
m_functionsToImport[builtin->name] = std::move(imp); m_functionsToImport[builtin->name] = std::move(imp);
} }
typeConversionNeeded = true; typeConversionNeeded = true;
@ -184,7 +184,7 @@ wasm::Expression WasmCodeTransform::operator()(Literal const& _literal)
{ {
u256 value = valueOfLiteral(_literal); u256 value = valueOfLiteral(_literal);
yulAssert(value <= numeric_limits<uint64_t>::max(), "Literal too large: " + value.str()); yulAssert(value <= numeric_limits<uint64_t>::max(), "Literal too large: " + value.str());
return wasm::Literal{uint64_t(value)}; return wasm::Literal{static_cast<uint64_t>(value)};
} }
wasm::Expression WasmCodeTransform::operator()(If const& _if) wasm::Expression WasmCodeTransform::operator()(If const& _if)
@ -193,7 +193,7 @@ wasm::Expression WasmCodeTransform::operator()(If const& _if)
vector<wasm::Expression> args; vector<wasm::Expression> args;
args.emplace_back(visitReturnByValue(*_if.condition)); args.emplace_back(visitReturnByValue(*_if.condition));
args.emplace_back(wasm::Literal{0}); args.emplace_back(wasm::Literal{static_cast<uint64_t>(0)});
return wasm::If{ return wasm::If{
make_unique<wasm::Expression>(wasm::BuiltinCall{"i64.ne", std::move(args)}), make_unique<wasm::Expression>(wasm::BuiltinCall{"i64.ne", std::move(args)}),
visit(_if.body.statements), visit(_if.body.statements),
@ -205,7 +205,7 @@ wasm::Expression WasmCodeTransform::operator()(Switch const& _switch)
{ {
wasm::Block block; wasm::Block block;
string condition = m_nameDispenser.newName("condition"_yulstring).str(); string condition = m_nameDispenser.newName("condition"_yulstring).str();
m_localVariables.emplace_back(wasm::VariableDeclaration{condition}); m_localVariables.emplace_back(wasm::VariableDeclaration{condition, wasm::Type::i64});
block.statements.emplace_back(wasm::LocalAssignment{condition, visit(*_switch.expression)}); block.statements.emplace_back(wasm::LocalAssignment{condition, visit(*_switch.expression)});
vector<wasm::Expression>* currentBlock = &block.statements; vector<wasm::Expression>* currentBlock = &block.statements;
@ -325,10 +325,11 @@ wasm::FunctionDefinition WasmCodeTransform::translateFunction(yul::FunctionDefin
wasm::FunctionDefinition fun; wasm::FunctionDefinition fun;
fun.name = _fun.name.str(); fun.name = _fun.name.str();
for (auto const& param: _fun.parameters) for (auto const& param: _fun.parameters)
fun.parameterNames.emplace_back(param.name.str()); fun.parameters.push_back({param.name.str(), wasm::Type::i64});
for (auto const& retParam: _fun.returnVariables) for (auto const& retParam: _fun.returnVariables)
fun.locals.emplace_back(wasm::VariableDeclaration{retParam.name.str()}); fun.locals.emplace_back(wasm::VariableDeclaration{retParam.name.str(), wasm::Type::i64});
fun.returns = !_fun.returnVariables.empty(); if (!_fun.returnVariables.empty())
fun.returnType = wasm::Type::i64;
yulAssert(m_localVariables.empty(), ""); yulAssert(m_localVariables.empty(), "");
yulAssert(m_functionBodyLabel.empty(), ""); yulAssert(m_functionBodyLabel.empty(), "");
@ -361,14 +362,14 @@ wasm::Expression WasmCodeTransform::injectTypeConversionIfNeeded(wasm::FunctionC
{ {
wasm::FunctionImport const& import = m_functionsToImport.at(YulString{_call.functionName}); wasm::FunctionImport const& import = m_functionsToImport.at(YulString{_call.functionName});
for (size_t i = 0; i < _call.arguments.size(); ++i) for (size_t i = 0; i < _call.arguments.size(); ++i)
if (import.paramTypes.at(i) == "i32") if (import.paramTypes.at(i) == wasm::Type::i32)
_call.arguments[i] = wasm::BuiltinCall{"i32.wrap_i64", make_vector<wasm::Expression>(std::move(_call.arguments[i]))}; _call.arguments[i] = wasm::BuiltinCall{"i32.wrap_i64", make_vector<wasm::Expression>(std::move(_call.arguments[i]))};
else else
yulAssert(import.paramTypes.at(i) == "i64", "Unknown type " + import.paramTypes.at(i)); yulAssert(import.paramTypes.at(i) == wasm::Type::i64, "Invalid Wasm type");
if (import.returnType && *import.returnType != "i64") if (import.returnType && *import.returnType != wasm::Type::i64)
{ {
yulAssert(*import.returnType == "i32", "Invalid type " + *import.returnType); yulAssert(*import.returnType == wasm::Type::i32, "Invalid Wasm type");
return wasm::BuiltinCall{"i64.extend_i32_u", make_vector<wasm::Expression>(std::move(_call))}; return wasm::BuiltinCall{"i64.extend_i32_u", make_vector<wasm::Expression>(std::move(_call))};
} }
return {std::move(_call)}; return {std::move(_call)};
@ -400,6 +401,17 @@ void WasmCodeTransform::allocateGlobals(size_t _amount)
{ {
while (m_globalVariables.size() < _amount) while (m_globalVariables.size() < _amount)
m_globalVariables.emplace_back(wasm::GlobalVariableDeclaration{ m_globalVariables.emplace_back(wasm::GlobalVariableDeclaration{
m_nameDispenser.newName("global_"_yulstring).str() m_nameDispenser.newName("global_"_yulstring).str(),
wasm::Type::i64
}); });
} }
wasm::Type WasmCodeTransform::translatedType(yul::Type _yulType)
{
if (_yulType == "i32"_yulstring)
return wasm::Type::i32;
else if (_yulType == "i64"_yulstring)
return wasm::Type::i64;
else
yulAssert(false, "This Yul type does not have a corresponding type in Wasm.");
}

View File

@ -89,6 +89,8 @@ private:
/// Makes sure that there are at least @a _amount global variables. /// Makes sure that there are at least @a _amount global variables.
void allocateGlobals(size_t _amount); void allocateGlobals(size_t _amount);
static wasm::Type translatedType(yul::Type _yulType);
Dialect const& m_dialect; Dialect const& m_dialect;
NameDispenser m_nameDispenser; NameDispenser m_nameDispenser;

View File

@ -33,16 +33,16 @@ using namespace solidity::yul;
VarNameCleaner::VarNameCleaner( VarNameCleaner::VarNameCleaner(
Block const& _ast, Block const& _ast,
Dialect const& _dialect, Dialect const& _dialect,
set<YulString> _blacklist set<YulString> _namesToKeep
): ):
m_dialect{_dialect}, m_dialect{_dialect},
m_blacklist{std::move(_blacklist)}, m_namesToKeep{std::move(_namesToKeep)},
m_translatedNames{} m_translatedNames{}
{ {
for (auto const& statement: _ast.statements) for (auto const& statement: _ast.statements)
if (holds_alternative<FunctionDefinition>(statement)) if (holds_alternative<FunctionDefinition>(statement))
m_blacklist.insert(std::get<FunctionDefinition>(statement).name); m_namesToKeep.insert(std::get<FunctionDefinition>(statement).name);
m_usedNames = m_blacklist; m_usedNames = m_namesToKeep;
} }
void VarNameCleaner::operator()(FunctionDefinition& _funDef) void VarNameCleaner::operator()(FunctionDefinition& _funDef)
@ -51,7 +51,7 @@ void VarNameCleaner::operator()(FunctionDefinition& _funDef)
m_insideFunction = true; m_insideFunction = true;
set<YulString> globalUsedNames = std::move(m_usedNames); set<YulString> globalUsedNames = std::move(m_usedNames);
m_usedNames = m_blacklist; m_usedNames = m_namesToKeep;
map<YulString, YulString> globalTranslatedNames; map<YulString, YulString> globalTranslatedNames;
swap(globalTranslatedNames, m_translatedNames); swap(globalTranslatedNames, m_translatedNames);

View File

@ -63,7 +63,7 @@ private:
VarNameCleaner( VarNameCleaner(
Block const& _ast, Block const& _ast,
Dialect const& _dialect, Dialect const& _dialect,
std::set<YulString> _blacklist = {} std::set<YulString> _namesToKeep = {}
); );
/// Tries to rename a list of variables. /// Tries to rename a list of variables.
@ -77,11 +77,13 @@ private:
YulString findCleanName(YulString const& name) const; YulString findCleanName(YulString const& name) const;
/// Tests whether a given name was already used within this pass /// Tests whether a given name was already used within this pass
/// or is on the blacklist. /// or was set to be kept.
bool isUsedName(YulString const& _name) const; bool isUsedName(YulString const& _name) const;
Dialect const& m_dialect; Dialect const& m_dialect;
std::set<YulString> m_blacklist;
/// These names will not be modified.
std::set<YulString> m_namesToKeep;
/// Set of names that are in use. /// Set of names that are in use.
std::set<YulString> m_usedNames; std::set<YulString> m_usedNames;

View File

@ -177,6 +177,7 @@ static string const g_strVersion = "version";
static string const g_strIgnoreMissingFiles = "ignore-missing"; static string const g_strIgnoreMissingFiles = "ignore-missing";
static string const g_strColor = "color"; static string const g_strColor = "color";
static string const g_strNoColor = "no-color"; static string const g_strNoColor = "no-color";
static string const g_strErrorIds = "error-codes";
static string const g_strOldReporter = "old-reporter"; static string const g_strOldReporter = "old-reporter";
static string const g_argAbi = g_strAbi; static string const g_argAbi = g_strAbi;
@ -222,6 +223,7 @@ static string const g_stdinFileName = g_stdinFileNameStr;
static string const g_argIgnoreMissingFiles = g_strIgnoreMissingFiles; static string const g_argIgnoreMissingFiles = g_strIgnoreMissingFiles;
static string const g_argColor = g_strColor; static string const g_argColor = g_strColor;
static string const g_argNoColor = g_strNoColor; static string const g_argNoColor = g_strNoColor;
static string const g_argErrorIds = g_strErrorIds;
static string const g_argOldReporter = g_strOldReporter; static string const g_argOldReporter = g_strOldReporter;
/// Possible arguments to for --combined-json /// Possible arguments to for --combined-json
@ -738,7 +740,7 @@ remap paths using the context:prefix=path syntax.
Example: Example:
solc --)" + g_argBinary + R"( -o /tmp/solcoutput dapp-bin=/usr/local/lib/dapp-bin contract.sol solc --)" + g_argBinary + R"( -o /tmp/solcoutput dapp-bin=/usr/local/lib/dapp-bin contract.sol
Allowed options)").c_str(), General Information)").c_str(),
po::options_description::m_default_line_length, po::options_description::m_default_line_length,
po::options_description::m_default_line_length - 23 po::options_description::m_default_line_length - 23
); );
@ -746,47 +748,67 @@ Allowed options)").c_str(),
(g_argHelp.c_str(), "Show help message and exit.") (g_argHelp.c_str(), "Show help message and exit.")
(g_argVersion.c_str(), "Show version and exit.") (g_argVersion.c_str(), "Show version and exit.")
(g_strLicense.c_str(), "Show licensing information and exit.") (g_strLicense.c_str(), "Show licensing information and exit.")
;
po::options_description inputOptions("Input Options");
inputOptions.add_options()
(
g_argBasePath.c_str(),
po::value<string>()->value_name("path"),
"Use the given path as the root of the source tree instead of the root of the filesystem."
)
(
g_argAllowPaths.c_str(),
po::value<string>()->value_name("path(s)"),
"Allow a given path for imports. A list of paths can be supplied by separating them with a comma."
)
(
g_argIgnoreMissingFiles.c_str(),
"Ignore missing files."
)
(
g_argErrorRecovery.c_str(),
"Enables additional parser error recovery."
)
;
desc.add(inputOptions);
po::options_description outputOptions("Output Options");
outputOptions.add_options()
(
(g_argOutputDir + ",o").c_str(),
po::value<string>()->value_name("path"),
"If given, creates one file per component and contract/file at the specified directory."
)
(
g_strOverwrite.c_str(),
"Overwrite existing files (used together with -o)."
)
( (
g_strEVMVersion.c_str(), g_strEVMVersion.c_str(),
po::value<string>()->value_name("version"), po::value<string>()->value_name("version"),
"Select desired EVM version. Either homestead, tangerineWhistle, spuriousDragon, " "Select desired EVM version. Either homestead, tangerineWhistle, spuriousDragon, "
"byzantium, constantinople, petersburg, istanbul (default) or berlin." "byzantium, constantinople, petersburg, istanbul (default) or berlin."
) )
(g_argPrettyJson.c_str(), "Output JSON in pretty format. Currently it only works with the combined JSON output.")
(
g_argLibraries.c_str(),
po::value<vector<string>>()->value_name("libs"),
"Direct string or file containing library addresses. Syntax: "
"<libraryName>:<address> [, or whitespace] ...\n"
"Address is interpreted as a hex string optionally prefixed by 0x."
)
( (
g_strRevertStrings.c_str(), g_strRevertStrings.c_str(),
po::value<string>()->value_name(boost::join(g_revertStringsArgs, ",")), po::value<string>()->value_name(boost::join(g_revertStringsArgs, ",")),
"Strip revert (and require) reason strings or add additional debugging information." "Strip revert (and require) reason strings or add additional debugging information."
) )
( ;
(g_argOutputDir + ",o").c_str(), desc.add(outputOptions);
po::value<string>()->value_name("path"),
"If given, creates one file per component and contract/file at the specified directory." po::options_description alternativeInputModes("Alternative Input Modes");
) alternativeInputModes.add_options()
(g_strOverwrite.c_str(), "Overwrite existing files (used together with -o).")
(
g_argCombinedJson.c_str(),
po::value<string>()->value_name(boost::join(g_combinedJsonArgs, ",")),
"Output a single json document containing the specified information."
)
(g_argGas.c_str(), "Print an estimate of the maximal gas usage for each function.")
( (
g_argStandardJSON.c_str(), g_argStandardJSON.c_str(),
"Switch to Standard JSON input / output mode, ignoring all options. " "Switch to Standard JSON input / output mode, ignoring all options. "
"It reads from standard input, if no input file was given, otherwise it reads from the provided input file. The result will be written to standard output." "It reads from standard input, if no input file was given, otherwise it reads from the provided input file. The result will be written to standard output."
) )
( (
g_argImportAst.c_str(), g_argLink.c_str(),
("Import ASTs to be compiled, assumes input holds the AST in compact JSON format. " ("Switch to linker mode, ignoring all options apart from --" + g_argLibraries + " "
"Supported Inputs is the output of the --" + g_argStandardJSON + " or the one produced by " "and modify binaries in place.").c_str()
"--" + g_argCombinedJson + " " + g_strAst + "," + g_strCompactJSON).c_str()
) )
( (
g_argAssemble.c_str(), g_argAssemble.c_str(),
@ -807,58 +829,66 @@ Allowed options)").c_str(),
"and assumes input is strict assembly.").c_str() "and assumes input is strict assembly.").c_str()
) )
( (
g_strYulDialect.c_str(), g_argImportAst.c_str(),
po::value<string>()->value_name(boost::join(g_yulDialectArgs, ",")), ("Import ASTs to be compiled, assumes input holds the AST in compact JSON format. "
"Input dialect to use in assembly or yul mode." "Supported Inputs is the output of the --" + g_argStandardJSON + " or the one produced by "
"--" + g_argCombinedJson + " " + g_strAst + "," + g_strCompactJSON).c_str()
) )
;
desc.add(alternativeInputModes);
po::options_description assemblyModeOptions("Assembly Mode Options");
assemblyModeOptions.add_options()
( (
g_argMachine.c_str(), g_argMachine.c_str(),
po::value<string>()->value_name(boost::join(g_machineArgs, ",")), po::value<string>()->value_name(boost::join(g_machineArgs, ",")),
"Target machine in assembly or Yul mode." "Target machine in assembly or Yul mode."
) )
( (
g_argLink.c_str(), g_strYulDialect.c_str(),
("Switch to linker mode, ignoring all options apart from --" + g_argLibraries + " " po::value<string>()->value_name(boost::join(g_yulDialectArgs, ",")),
"and modify binaries in place.").c_str() "Input dialect to use in assembly or yul mode."
)
;
desc.add(assemblyModeOptions);
po::options_description linkerModeOptions("Linker Mode Options");
linkerModeOptions.add_options()
(
g_argLibraries.c_str(),
po::value<vector<string>>()->value_name("libs"),
"Direct string or file containing library addresses. Syntax: "
"<libraryName>:<address> [, or whitespace] ...\n"
"Address is interpreted as a hex string optionally prefixed by 0x."
)
;
desc.add(linkerModeOptions);
po::options_description outputFormatting("Output Formatting");
outputFormatting.add_options()
(
g_argPrettyJson.c_str(),
"Output JSON in pretty format. Currently it only works with the combined JSON output."
) )
( (
g_argMetadataHash.c_str(), g_argColor.c_str(),
po::value<string>()->value_name(boost::join(g_metadataHashArgs, ",")), "Force colored output."
"Choose hash method for the bytecode metadata or disable it."
)
(g_argMetadataLiteral.c_str(), "Store referenced sources as literal data in the metadata output.")
(
g_argAllowPaths.c_str(),
po::value<string>()->value_name("path(s)"),
"Allow a given path for imports. A list of paths can be supplied by separating them with a comma."
) )
( (
g_argBasePath.c_str(), g_argNoColor.c_str(),
po::value<string>()->value_name("path"), "Explicitly disable colored output, disabling terminal auto-detection."
"Use the given path as the root of the source tree instead of the root of the filesystem."
) )
(g_argColor.c_str(), "Force colored output.")
(g_argNoColor.c_str(), "Explicitly disable colored output, disabling terminal auto-detection.")
(g_argOldReporter.c_str(), "Enables old diagnostics reporter.")
(g_argErrorRecovery.c_str(), "Enables additional parser error recovery.")
(g_argIgnoreMissingFiles.c_str(), "Ignore missing files.");
po::options_description optimizerOptions("Optimizer options");
optimizerOptions.add_options()
(g_argOptimize.c_str(), "Enable bytecode optimizer.")
( (
g_argOptimizeRuns.c_str(), g_argErrorIds.c_str(),
po::value<unsigned>()->value_name("n")->default_value(200), "Output error codes."
"Set for how many contract runs to optimize. "
"Lower values will optimize more for initial deployment cost, higher values will optimize more for high-frequency usage."
) )
(g_strOptimizeYul.c_str(), ("Legacy option, ignored. Use the general --" + g_argOptimize + " to enable Yul optimizer.").c_str())
(g_strNoOptimizeYul.c_str(), "Disable Yul optimizer in Solidity.")
( (
g_strYulOptimizations.c_str(), g_argOldReporter.c_str(),
po::value<string>()->value_name("steps"), "Enables old diagnostics reporter (legacy option, will be removed)."
"Forces yul optimizer to use the specified sequence of optimization steps instead of the built-in one." )
); ;
desc.add(optimizerOptions); desc.add(outputFormatting);
po::options_description outputComponents("Output Components"); po::options_description outputComponents("Output Components");
outputComponents.add_options() outputComponents.add_options()
(g_argAstJson.c_str(), "AST of all source files in JSON format.") (g_argAstJson.c_str(), "AST of all source files in JSON format.")
@ -876,9 +906,66 @@ Allowed options)").c_str(),
(g_argNatspecUser.c_str(), "Natspec user documentation of all contracts.") (g_argNatspecUser.c_str(), "Natspec user documentation of all contracts.")
(g_argNatspecDev.c_str(), "Natspec developer documentation of all contracts.") (g_argNatspecDev.c_str(), "Natspec developer documentation of all contracts.")
(g_argMetadata.c_str(), "Combined Metadata JSON whose Swarm hash is stored on-chain.") (g_argMetadata.c_str(), "Combined Metadata JSON whose Swarm hash is stored on-chain.")
(g_argStorageLayout.c_str(), "Slots, offsets and types of the contract's state variables."); (g_argStorageLayout.c_str(), "Slots, offsets and types of the contract's state variables.")
;
desc.add(outputComponents); desc.add(outputComponents);
po::options_description extraOutput("Extra Output");
extraOutput.add_options()
(
g_argGas.c_str(),
"Print an estimate of the maximal gas usage for each function."
)
(
g_argCombinedJson.c_str(),
po::value<string>()->value_name(boost::join(g_combinedJsonArgs, ",")),
"Output a single json document containing the specified information."
)
;
desc.add(extraOutput);
po::options_description metadataOptions("Metadata Options");
metadataOptions.add_options()
(
g_argMetadataHash.c_str(),
po::value<string>()->value_name(boost::join(g_metadataHashArgs, ",")),
"Choose hash method for the bytecode metadata or disable it."
)
(
g_argMetadataLiteral.c_str(),
"Store referenced sources as literal data in the metadata output."
)
;
desc.add(metadataOptions);
po::options_description optimizerOptions("Optimizer Options");
optimizerOptions.add_options()
(
g_argOptimize.c_str(),
"Enable bytecode optimizer."
)
(
g_argOptimizeRuns.c_str(),
po::value<unsigned>()->value_name("n")->default_value(200),
"Set for how many contract runs to optimize. "
"Lower values will optimize more for initial deployment cost, higher values will optimize more for high-frequency usage."
)
(
g_strOptimizeYul.c_str(),
("Legacy option, ignored. Use the general --" + g_argOptimize + " to enable Yul optimizer.").c_str()
)
(
g_strNoOptimizeYul.c_str(),
"Disable Yul optimizer in Solidity."
)
(
g_strYulOptimizations.c_str(),
po::value<string>()->value_name("steps"),
"Forces yul optimizer to use the specified sequence of optimization steps instead of the built-in one."
)
;
desc.add(optimizerOptions);
po::options_description allOptions = desc; po::options_description allOptions = desc;
allOptions.add_options()(g_argInputFile.c_str(), po::value<vector<string>>(), "input file"); allOptions.add_options()(g_argInputFile.c_str(), po::value<vector<string>>(), "input file");
@ -908,6 +995,8 @@ Allowed options)").c_str(),
m_coloredOutput = !m_args.count(g_argNoColor) && (isatty(STDERR_FILENO) || m_args.count(g_argColor)); m_coloredOutput = !m_args.count(g_argNoColor) && (isatty(STDERR_FILENO) || m_args.count(g_argColor));
m_withErrorIds = m_args.count(g_argErrorIds);
if (m_args.count(g_argHelp) || (isatty(fileno(stdin)) && _argc == 1)) if (m_args.count(g_argHelp) || (isatty(fileno(stdin)) && _argc == 1))
{ {
sout() << desc; sout() << desc;
@ -1213,7 +1302,7 @@ bool CommandLineInterface::processInput()
if (m_args.count(g_argOldReporter)) if (m_args.count(g_argOldReporter))
formatter = make_unique<SourceReferenceFormatter>(serr(false)); formatter = make_unique<SourceReferenceFormatter>(serr(false));
else else
formatter = make_unique<SourceReferenceFormatterHuman>(serr(false), m_coloredOutput); formatter = make_unique<SourceReferenceFormatterHuman>(serr(false), m_coloredOutput, m_withErrorIds);
try try
{ {
@ -1651,7 +1740,7 @@ bool CommandLineInterface::assemble(
if (m_args.count(g_argOldReporter)) if (m_args.count(g_argOldReporter))
formatter = make_unique<SourceReferenceFormatter>(serr(false)); formatter = make_unique<SourceReferenceFormatter>(serr(false));
else else
formatter = make_unique<SourceReferenceFormatterHuman>(serr(false), m_coloredOutput); formatter = make_unique<SourceReferenceFormatterHuman>(serr(false), m_coloredOutput, m_withErrorIds);
for (auto const& error: stack.errors()) for (auto const& error: stack.errors())
{ {

View File

@ -131,6 +131,8 @@ private:
CompilerStack::MetadataHash m_metadataHash = CompilerStack::MetadataHash::IPFS; CompilerStack::MetadataHash m_metadataHash = CompilerStack::MetadataHash::IPFS;
/// Whether or not to colorize diagnostics output. /// Whether or not to colorize diagnostics output.
bool m_coloredOutput = true; bool m_coloredOutput = true;
/// Whether or not to output error IDs.
bool m_withErrorIds = false;
}; };
} }

View File

@ -121,6 +121,7 @@ function test_solc_behaviour()
rm "$stdout_path.bak" rm "$stdout_path.bak"
else else
sed -i.bak -e '/^Warning: This is a pre-release compiler version, please do not use it in production./d' "$stderr_path" sed -i.bak -e '/^Warning: This is a pre-release compiler version, please do not use it in production./d' "$stderr_path"
sed -i.bak -e '/^Warning (3805): This is a pre-release compiler version, please do not use it in production./d' "$stderr_path"
sed -i.bak -e 's/\(^[ ]*auxdata: \)0x[0-9a-f]*$/\1AUXDATA REMOVED/' "$stdout_path" sed -i.bak -e 's/\(^[ ]*auxdata: \)0x[0-9a-f]*$/\1AUXDATA REMOVED/' "$stdout_path"
sed -i.bak -e 's/ Consider adding "pragma .*$//' "$stderr_path" sed -i.bak -e 's/ Consider adding "pragma .*$//' "$stderr_path"
# Remove trailing empty lines. Needs a line break to make OSX sed happy. # Remove trailing empty lines. Needs a line break to make OSX sed happy.

View File

@ -0,0 +1 @@
--error-codes

View 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];
| ^^

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,8 @@
// SPDX-License-Identifier: GPL-3.0
contract C {
function f() {
2=0;
""[2];
}
}

View File

@ -45,7 +45,7 @@ object "object" {
Binary representation: Binary representation:
0061736d0100000001160460000060017e017e60057e7e7e7e7e0060027f7f0002190108657468657265756d0c73746f7261676553746f7265000303060500010101020503010001060100071102066d656d6f72790200046d61696e00010acd01052b01017e0240420021004200200020002000200010054220200020002000420110054200a74220a710000b0b1f01017e024020004208864280fe0383200042088842ff01838421010b20010b1e01027e02402000100242108621022002200042108810028421010b20010b1e01027e02402000100342208621022002200042208810038421010b20010b4101007e02402000a7200110043703002000a74208a76aada7200210043703002000a74210a76aada7200310043703002000a74218a76aada7200410043703000b0b 0061736d0100000001160460000060017e017e60057e7e7e7e7e0060027f7f0002190108657468657265756d0c73746f7261676553746f7265000303060500010101020503010001060100071102066d656d6f72790200046d61696e00010acb01052b01017e0240420021004200200020002000200010054220200020002000420110054200a74220a710000b0b1f01017e024020004208864280fe0383200042088842ff01838421010b20010b1e01027e02402000100242108621022002200042108810028421010b20010b1e01027e02402000100342208621022002200042208810038421010b20010b3f0002402000a7200110043700002000a74208a76aada7200210043700002000a74210a76aada7200310043700002000a74218a76aada7200410043700000b0b
Text representation: Text representation:
(module (module

View File

@ -154,7 +154,7 @@ object "object" {
Binary representation: Binary representation:
0061736d0100000001480a60000060017e017e60027e7e017e60037e7e7e017e60047e7e7e7e017e60057e7e7e7e7e0060087e7e7e7e7e7e7e7e0060087e7e7e7e7e7e7e7e017e60027f7f0060037f7f7f0002310208657468657265756d0c73746f7261676553746f7265000808657468657265756d0c63616c6c44617461436f70790009030e0d0003070407020704010101050605030100010610037e0142000b7e0142000b7e0142000b071102066d656d6f72790200046d61696e00020aa9090df302011f7e02404200210002402000200020002000100921012300210223012103230221040b2001210520022106200321072004210842012109200020008420002009848450ada745ada745ad210a02400340200aa745ad500d01024002402005200620072008200020002000420a1008210b2300210c2301210d2302210e0b0240200b200c200d200e1005210f2300211023012111230221120b200f20108420112012848450ada745ad42005204400c030b024020052006200720082000200020004202100621132300211423012115230221160b201320148420152016848450ada745ad42005204400c030b0240200520062007200820002000200042041006211723002118230121192302211a0b20172018842019201a848450ada745ad42005204400c010b0b0240200520062007200820002000200020091004211b2300211c2301211d2302211e0b201b2105201c2106201d2107201e21080c000b0b20002000200020002005200620072008100e0b0b2f01037e0240200020017c2105200520027c21032005200054ada72003200554ada772ada7ad21040b2004240020030b72010b7e0240200320077c210c200c42007c210b024020022006200c200354ada7200b200c54ada772ada7ad1003210d2300210e0b200d210a024020012005200e1003210f230021100b200f2109024020002004201010032111230021120b201121080b20092400200a2401200b240220080b2601047e0240200020018420022003848450ada7ad21070b20052400200624012007240220040b4901047e02402000200451ad42005204402001200551ad42005204402002200651ad42005204402003200751ad42005204404201210b0b0b0b0b0b20092400200a2401200b240220080b2d01027e024002402000200154ad21032003420151044042ffffffff0f2102052000200152ad21020b0b0b20020b960101087e02404200210c0240200020041007210d200d42005104400240200120051007210e200e42005104400240200220061007210f200f42005104402003200754ad210c05200f42015104404200210c054201210c0b0b0b05200e42015104404200210c054201210c0b0b0b05200d42015104404200210c054201210c0b0b0b200ca7ad210b0b20092400200a2401200b240220080b8f0101087e02404200200020018420028452ad4200520440000b4200200342208852ad4200520440000b4200a72003a7ada74220a710014200a7290300100c21084200a74208a76aada7290300100c21094200a74210a76aada7290300100c210a4200a74218a76aada7290300100c210b2008210420092105200a2106200b21070b20052400200624012007240220040b1f01017e024020004208864280fe0383200042088842ff01838421010b20010b1e01027e02402000100a421086210220022000421088100a8421010b20010b1e01027e02402000100b422086210220022000422088100b8421010b20010b4101007e02402000a72001100c3703002000a74208a76aada72002100c3703002000a74210a76aada72003100c3703002000a74218a76aada72004100c3703000b0b2701007e024042002000200120022003100d42202004200520062007100d4200a74220a710000b0b 0061736d0100000001480a60000060017e017e60027e7e017e60037e7e7e017e60047e7e7e7e017e60057e7e7e7e7e0060087e7e7e7e7e7e7e7e0060087e7e7e7e7e7e7e7e017e60027f7f0060037f7f7f0002310208657468657265756d0c73746f7261676553746f7265000808657468657265756d0c63616c6c44617461436f70790009030e0d0003070407020704010101050605030100010610037e0142000b7e0142000b7e0142000b071102066d656d6f72790200046d61696e00020aa5090df302011f7e02404200210002402000200020002000100921012300210223012103230221040b2001210520022106200321072004210842012109200020008420002009848450ada745ada745ad210a02400340200aa745ad500d01024002402005200620072008200020002000420a1008210b2300210c2301210d2302210e0b0240200b200c200d200e1005210f2300211023012111230221120b200f20108420112012848450ada745ad42005204400c030b024020052006200720082000200020004202100621132300211423012115230221160b201320148420152016848450ada745ad42005204400c030b0240200520062007200820002000200042041006211723002118230121192302211a0b20172018842019201a848450ada745ad42005204400c010b0b0240200520062007200820002000200020091004211b2300211c2301211d2302211e0b201b2105201c2106201d2107201e21080c000b0b20002000200020002005200620072008100e0b0b2f01037e0240200020017c2105200520027c21032005200054ada72003200554ada772ada7ad21040b2004240020030b72010b7e0240200320077c210c200c42007c210b024020022006200c200354ada7200b200c54ada772ada7ad1003210d2300210e0b200d210a024020012005200e1003210f230021100b200f2109024020002004201010032111230021120b201121080b20092400200a2401200b240220080b2601047e0240200020018420022003848450ada7ad21070b20052400200624012007240220040b4901047e02402000200451ad42005204402001200551ad42005204402002200651ad42005204402003200751ad42005204404201210b0b0b0b0b0b20092400200a2401200b240220080b2d01027e024002402000200154ad21032003420151044042ffffffff0f2102052000200152ad21020b0b0b20020b960101087e02404200210c0240200020041007210d200d42005104400240200120051007210e200e42005104400240200220061007210f200f42005104402003200754ad210c05200f42015104404200210c054201210c0b0b0b05200e42015104404200210c054201210c0b0b0b05200d42015104404200210c054201210c0b0b0b200ca7ad210b0b20092400200a2401200b240220080b8f0101087e02404200200020018420028452ad4200520440000b4200200342208852ad4200520440000b4200a72003a7ada74220a710014200a7290000100c21084200a74208a76aada7290000100c21094200a74210a76aada7290000100c210a4200a74218a76aada7290000100c210b2008210420092105200a2106200b21070b20052400200624012007240220040b1f01017e024020004208864280fe0383200042088842ff01838421010b20010b1e01027e02402000100a421086210220022000421088100a8421010b20010b1e01027e02402000100b422086210220022000422088100b8421010b20010b3f0002402000a72001100c3700002000a74208a76aada72002100c3700002000a74210a76aada72003100c3700002000a74218a76aada72004100c3700000b0b2500024042002000200120022003100d42202004200520062007100d4200a74220a710000b0b
Text representation: Text representation:
(module (module

View File

@ -1,6 +1,6 @@
{"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}},"b.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! {"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}},"b.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version!
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","errorCode":"3420","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version!
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","errorCode":"2018","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure
contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } } contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }
^------------------------------------------^ ^------------------------------------------^
","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} ","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}}

View File

@ -1,6 +1,6 @@
{"contracts":{"a.sol":{"A2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! {"contracts":{"a.sol":{"A2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version!
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","errorCode":"3420","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version!
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","errorCode":"2018","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure
contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } } contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }
^------------------------------------------^ ^------------------------------------------^
","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} ","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}}

View File

@ -1,6 +1,6 @@
{"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! {"errors":[{"component":"general","errorCode":"3420","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version!
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","errorCode":"3420","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version!
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","errorCode":"2018","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure
contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } } contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }
^------------------------------------------^ ^------------------------------------------^
","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} ","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}}

View File

@ -1,6 +1,6 @@
{"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}},"A2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}},"b.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}},"B2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! {"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}},"A2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}},"b.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}},"B2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version!
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","errorCode":"3420","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version!
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","errorCode":"2018","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure
contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } } contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }
^------------------------------------------^ ^------------------------------------------^
","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} ","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}}

View File

@ -1,2 +1,2 @@
{"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! {"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version!
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}}

View File

@ -1,5 +1,5 @@
{"contracts":{"b.sol":{"B2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version! {"contracts":{"b.sol":{"B2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version!
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","errorCode":"2018","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure
contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } } contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }
^------------------------------------------^ ^------------------------------------------^
","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} ","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}}

View File

@ -1,2 +1,2 @@
{"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}},"A2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! {"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}},"A2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version!
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}}

View File

@ -1,7 +1,7 @@
{"errors":[{"component":"general","formattedMessage":"A:2:58: ParserError: Expected type name {"errors":[{"component":"general","errorCode":"3546","formattedMessage":"A:2:58: ParserError: Expected type name
pragma solidity >=0.0; contract Errort6 { using foo for ; /* missing type name */ } pragma solidity >=0.0; contract Errort6 { using foo for ; /* missing type name */ }
^ ^
","message":"Expected type name","severity":"error","sourceLocation":{"end":94,"file":"A","start":93},"type":"ParserError"},{"component":"general","formattedMessage":"A:2:84: Warning: Recovered in ContractDefinition at '}'. ","message":"Expected type name","severity":"error","sourceLocation":{"end":94,"file":"A","start":93},"type":"ParserError"},{"component":"general","errorCode":"3796","formattedMessage":"A:2:84: Warning: Recovered in ContractDefinition at '}'.
pragma solidity >=0.0; contract Errort6 { using foo for ; /* missing type name */ } pragma solidity >=0.0; contract Errort6 { using foo for ; /* missing type name */ }
^ ^
","message":"Recovered in ContractDefinition at '}'.","severity":"warning","sourceLocation":{"end":120,"file":"A","start":119},"type":"Warning"}],"sources":{"A":{"ast":{"absolutePath":"A","exportedSymbols":{"Errort6":[3]},"id":4,"license":"GPL-3.0","nodeType":"SourceUnit","nodes":[{"id":1,"literals":["solidity",">=","0.0"],"nodeType":"PragmaDirective","src":"36:22:0"},{"abstract":false,"baseContracts":[],"contractDependencies":[],"contractKind":"contract","documentation":null,"fullyImplemented":true,"id":3,"linearizedBaseContracts":[3],"name":"Errort6","nodeType":"ContractDefinition","nodes":[],"scope":4,"src":"59:35:0"}],"src":"36:84:0"},"id":0}}} ","message":"Recovered in ContractDefinition at '}'.","severity":"warning","sourceLocation":{"end":120,"file":"A","start":119},"type":"Warning"}],"sources":{"A":{"ast":{"absolutePath":"A","exportedSymbols":{"Errort6":[3]},"id":4,"license":"GPL-3.0","nodeType":"SourceUnit","nodes":[{"id":1,"literals":["solidity",">=","0.0"],"nodeType":"PragmaDirective","src":"36:22:0"},{"abstract":false,"baseContracts":[],"contractDependencies":[],"contractKind":"contract","documentation":null,"fullyImplemented":true,"id":3,"linearizedBaseContracts":[3],"name":"Errort6","nodeType":"ContractDefinition","nodes":[],"scope":4,"src":"59:35:0"}],"src":"36:84:0"},"id":0}}}

View File

@ -1,4 +1,4 @@
{"errors":[{"component":"general","formattedMessage":":2:24: DeclarationError: Declaration \"A\" not found in \"\" (referenced as \".\"). {"errors":[{"component":"general","errorCode":"2904","formattedMessage":":2:24: DeclarationError: Declaration \"A\" not found in \"\" (referenced as \".\").
pragma solidity >=0.0; import {A} from \".\"; pragma solidity >=0.0; import {A} from \".\";
^------------------^ ^------------------^
","message":"Declaration \"A\" not found in \"\" (referenced as \".\").","severity":"error","type":"DeclarationError"}],"sources":{}} ","message":"Declaration \"A\" not found in \"\" (referenced as \".\").","severity":"error","type":"DeclarationError"}],"sources":{}}

View File

@ -1,2 +1,2 @@
{"contracts":{"a.sol":{"A":{"evm":{"deployedBytecode":{"immutableReferences":{"3":[{"length":32,"start":77}]},"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"36:96:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;74:56;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;108:7;126:1;119:8;;74:56;:::o"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! {"contracts":{"a.sol":{"A":{"evm":{"deployedBytecode":{"immutableReferences":{"3":[{"length":32,"start":77}]},"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"36:96:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;74:56;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;108:7;126:1;119:8;;74:56;:::o"}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version!
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"}],"sources":{"a.sol":{"id":0}}} ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"}],"sources":{"a.sol":{"id":0}}}

View File

@ -1,4 +1,4 @@
{"errors":[{"component":"general","formattedMessage":"A:2:112: DeclarationError: Base constructor arguments given twice. {"errors":[{"component":"general","errorCode":"3364","formattedMessage":"A:2:112: DeclarationError: Base constructor arguments given twice.
pragma solidity >=0.0; contract A { constructor(uint) public {} } contract B is A(2) { } contract C is A(3) {} contract D is B, C {} pragma solidity >=0.0; contract A { constructor(uint) public {} } contract B is A(2) { } contract C is A(3) {} contract D is B, C {}
^-------------------^ ^-------------------^
A:2:81: First constructor call is here: A:2:81: First constructor call is here:

View File

@ -1,2 +1,2 @@
{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":3,"contract":"fileA:A","label":"s1","offset":0,"slot":"0","type":"t_bytes_storage"},{"astId":5,"contract":"fileA:A","label":"s2","offset":0,"slot":"1","type":"t_bytes_storage"}],"types":{"t_bytes_storage":{"encoding":"bytes","label":"bytes","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! {"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":3,"contract":"fileA:A","label":"s1","offset":0,"slot":"0","type":"t_bytes_storage"},{"astId":5,"contract":"fileA:A","label":"s2","offset":0,"slot":"1","type":"t_bytes_storage"}],"types":{"t_bytes_storage":{"encoding":"bytes","label":"bytes","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version!
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}} ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}}

View File

@ -1,2 +1,2 @@
{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":3,"contract":"fileA:A","label":"array1","offset":0,"slot":"0","type":"t_array(t_uint256)dyn_storage"},{"astId":6,"contract":"fileA:A","label":"array2","offset":0,"slot":"1","type":"t_array(t_bool)dyn_storage"}],"types":{"t_array(t_bool)dyn_storage":{"base":"t_bool","encoding":"dynamic_array","label":"bool[]","numberOfBytes":"32"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_bool":{"encoding":"inplace","label":"bool","numberOfBytes":"1"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! {"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":3,"contract":"fileA:A","label":"array1","offset":0,"slot":"0","type":"t_array(t_uint256)dyn_storage"},{"astId":6,"contract":"fileA:A","label":"array2","offset":0,"slot":"1","type":"t_array(t_bool)dyn_storage"}],"types":{"t_array(t_bool)dyn_storage":{"base":"t_bool","encoding":"dynamic_array","label":"bool[]","numberOfBytes":"32"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_bool":{"encoding":"inplace","label":"bool","numberOfBytes":"1"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version!
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}} ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}}

View File

@ -1,2 +1,2 @@
{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":14,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":16,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":18,"contract":"fileA:A","label":"s","offset":0,"slot":"2","type":"t_struct(S)12_storage"},{"astId":20,"contract":"fileA:A","label":"addr","offset":0,"slot":"6","type":"t_address"},{"astId":26,"contract":"fileA:A","label":"map","offset":0,"slot":"7","type":"t_mapping(t_uint256,t_mapping(t_address,t_bool))"},{"astId":29,"contract":"fileA:A","label":"array","offset":0,"slot":"8","type":"t_array(t_uint256)dyn_storage"},{"astId":31,"contract":"fileA:A","label":"s1","offset":0,"slot":"9","type":"t_string_storage"},{"astId":33,"contract":"fileA:A","label":"b1","offset":0,"slot":"10","type":"t_bytes_storage"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_bool":{"encoding":"inplace","label":"bool","numberOfBytes":"1"},"t_bytes_storage":{"encoding":"bytes","label":"bytes","numberOfBytes":"32"},"t_mapping(t_address,t_bool)":{"encoding":"mapping","key":"t_address","label":"mapping(address => bool)","numberOfBytes":"32","value":"t_bool"},"t_mapping(t_uint256,t_mapping(t_address,t_bool))":{"encoding":"mapping","key":"t_uint256","label":"mapping(uint256 => mapping(address => bool))","numberOfBytes":"32","value":"t_mapping(t_address,t_bool)"},"t_string_storage":{"encoding":"bytes","label":"string","numberOfBytes":"32"},"t_struct(S)12_storage":{"encoding":"inplace","label":"struct A.S","members":[{"astId":2,"contract":"fileA:A","label":"a","offset":0,"slot":"0","type":"t_uint128"},{"astId":4,"contract":"fileA:A","label":"b","offset":16,"slot":"0","type":"t_uint128"},{"astId":8,"contract":"fileA:A","label":"staticArray","offset":0,"slot":"1","type":"t_array(t_uint256)2_storage"},{"astId":11,"contract":"fileA:A","label":"dynArray","offset":0,"slot":"3","type":"t_array(t_uint256)dyn_storage"}],"numberOfBytes":"128"},"t_uint128":{"encoding":"inplace","label":"uint128","numberOfBytes":"16"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! {"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":14,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":16,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":18,"contract":"fileA:A","label":"s","offset":0,"slot":"2","type":"t_struct(S)12_storage"},{"astId":20,"contract":"fileA:A","label":"addr","offset":0,"slot":"6","type":"t_address"},{"astId":26,"contract":"fileA:A","label":"map","offset":0,"slot":"7","type":"t_mapping(t_uint256,t_mapping(t_address,t_bool))"},{"astId":29,"contract":"fileA:A","label":"array","offset":0,"slot":"8","type":"t_array(t_uint256)dyn_storage"},{"astId":31,"contract":"fileA:A","label":"s1","offset":0,"slot":"9","type":"t_string_storage"},{"astId":33,"contract":"fileA:A","label":"b1","offset":0,"slot":"10","type":"t_bytes_storage"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_bool":{"encoding":"inplace","label":"bool","numberOfBytes":"1"},"t_bytes_storage":{"encoding":"bytes","label":"bytes","numberOfBytes":"32"},"t_mapping(t_address,t_bool)":{"encoding":"mapping","key":"t_address","label":"mapping(address => bool)","numberOfBytes":"32","value":"t_bool"},"t_mapping(t_uint256,t_mapping(t_address,t_bool))":{"encoding":"mapping","key":"t_uint256","label":"mapping(uint256 => mapping(address => bool))","numberOfBytes":"32","value":"t_mapping(t_address,t_bool)"},"t_string_storage":{"encoding":"bytes","label":"string","numberOfBytes":"32"},"t_struct(S)12_storage":{"encoding":"inplace","label":"struct A.S","members":[{"astId":2,"contract":"fileA:A","label":"a","offset":0,"slot":"0","type":"t_uint128"},{"astId":4,"contract":"fileA:A","label":"b","offset":16,"slot":"0","type":"t_uint128"},{"astId":8,"contract":"fileA:A","label":"staticArray","offset":0,"slot":"1","type":"t_array(t_uint256)2_storage"},{"astId":11,"contract":"fileA:A","label":"dynArray","offset":0,"slot":"3","type":"t_array(t_uint256)dyn_storage"}],"numberOfBytes":"128"},"t_uint128":{"encoding":"inplace","label":"uint128","numberOfBytes":"16"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version!
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}} ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}}

View File

@ -1,2 +1,2 @@
{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":2,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":4,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":10,"contract":"fileA:A","label":"map","offset":0,"slot":"2","type":"t_mapping(t_uint256,t_mapping(t_address,t_bool))"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_bool":{"encoding":"inplace","label":"bool","numberOfBytes":"1"},"t_mapping(t_address,t_bool)":{"encoding":"mapping","key":"t_address","label":"mapping(address => bool)","numberOfBytes":"32","value":"t_bool"},"t_mapping(t_uint256,t_mapping(t_address,t_bool))":{"encoding":"mapping","key":"t_uint256","label":"mapping(uint256 => mapping(address => bool))","numberOfBytes":"32","value":"t_mapping(t_address,t_bool)"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! {"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":2,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":4,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":10,"contract":"fileA:A","label":"map","offset":0,"slot":"2","type":"t_mapping(t_uint256,t_mapping(t_address,t_bool))"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_bool":{"encoding":"inplace","label":"bool","numberOfBytes":"1"},"t_mapping(t_address,t_bool)":{"encoding":"mapping","key":"t_address","label":"mapping(address => bool)","numberOfBytes":"32","value":"t_bool"},"t_mapping(t_uint256,t_mapping(t_address,t_bool))":{"encoding":"mapping","key":"t_uint256","label":"mapping(uint256 => mapping(address => bool))","numberOfBytes":"32","value":"t_mapping(t_address,t_bool)"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version!
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}} ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}}

View File

@ -1,2 +1,2 @@
{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[],"types":null}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! {"contracts":{"fileA":{"A":{"storageLayout":{"storage":[],"types":null}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version!
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}} ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}}

View File

@ -1,2 +1,2 @@
{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[],"types":null}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! {"contracts":{"fileA":{"A":{"storageLayout":{"storage":[],"types":null}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version!
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0},"fileB":{"id":1}}} ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0},"fileB":{"id":1}}}

View File

@ -1,2 +1,2 @@
{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":3,"contract":"fileA:A","label":"s1","offset":0,"slot":"0","type":"t_string_storage"},{"astId":5,"contract":"fileA:A","label":"s2","offset":0,"slot":"1","type":"t_string_storage"}],"types":{"t_string_storage":{"encoding":"bytes","label":"string","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! {"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":3,"contract":"fileA:A","label":"s1","offset":0,"slot":"0","type":"t_string_storage"},{"astId":5,"contract":"fileA:A","label":"s2","offset":0,"slot":"1","type":"t_string_storage"}],"types":{"t_string_storage":{"encoding":"bytes","label":"string","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version!
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}} ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}}

View File

@ -1,2 +1,2 @@
{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":14,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":16,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":18,"contract":"fileA:A","label":"s","offset":0,"slot":"2","type":"t_struct(S)12_storage"},{"astId":20,"contract":"fileA:A","label":"addr","offset":0,"slot":"7","type":"t_address"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_struct(S)12_storage":{"encoding":"inplace","label":"struct A.S","members":[{"astId":2,"contract":"fileA:A","label":"a","offset":0,"slot":"0","type":"t_uint256"},{"astId":4,"contract":"fileA:A","label":"b","offset":0,"slot":"1","type":"t_uint256"},{"astId":8,"contract":"fileA:A","label":"staticArray","offset":0,"slot":"2","type":"t_array(t_uint256)2_storage"},{"astId":11,"contract":"fileA:A","label":"dynArray","offset":0,"slot":"4","type":"t_array(t_uint256)dyn_storage"}],"numberOfBytes":"160"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! {"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":14,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":16,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":18,"contract":"fileA:A","label":"s","offset":0,"slot":"2","type":"t_struct(S)12_storage"},{"astId":20,"contract":"fileA:A","label":"addr","offset":0,"slot":"7","type":"t_address"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_struct(S)12_storage":{"encoding":"inplace","label":"struct A.S","members":[{"astId":2,"contract":"fileA:A","label":"a","offset":0,"slot":"0","type":"t_uint256"},{"astId":4,"contract":"fileA:A","label":"b","offset":0,"slot":"1","type":"t_uint256"},{"astId":8,"contract":"fileA:A","label":"staticArray","offset":0,"slot":"2","type":"t_array(t_uint256)2_storage"},{"astId":11,"contract":"fileA:A","label":"dynArray","offset":0,"slot":"4","type":"t_array(t_uint256)dyn_storage"}],"numberOfBytes":"160"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version!
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}} ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}}

View File

@ -1,2 +1,2 @@
{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":14,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":16,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":18,"contract":"fileA:A","label":"s","offset":0,"slot":"2","type":"t_struct(S)12_storage"},{"astId":20,"contract":"fileA:A","label":"addr","offset":0,"slot":"6","type":"t_address"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_struct(S)12_storage":{"encoding":"inplace","label":"struct A.S","members":[{"astId":2,"contract":"fileA:A","label":"a","offset":0,"slot":"0","type":"t_uint128"},{"astId":4,"contract":"fileA:A","label":"b","offset":16,"slot":"0","type":"t_uint128"},{"astId":8,"contract":"fileA:A","label":"staticArray","offset":0,"slot":"1","type":"t_array(t_uint256)2_storage"},{"astId":11,"contract":"fileA:A","label":"dynArray","offset":0,"slot":"3","type":"t_array(t_uint256)dyn_storage"}],"numberOfBytes":"128"},"t_uint128":{"encoding":"inplace","label":"uint128","numberOfBytes":"16"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! {"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":14,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":16,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":18,"contract":"fileA:A","label":"s","offset":0,"slot":"2","type":"t_struct(S)12_storage"},{"astId":20,"contract":"fileA:A","label":"addr","offset":0,"slot":"6","type":"t_address"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_struct(S)12_storage":{"encoding":"inplace","label":"struct A.S","members":[{"astId":2,"contract":"fileA:A","label":"a","offset":0,"slot":"0","type":"t_uint128"},{"astId":4,"contract":"fileA:A","label":"b","offset":16,"slot":"0","type":"t_uint128"},{"astId":8,"contract":"fileA:A","label":"staticArray","offset":0,"slot":"1","type":"t_array(t_uint256)2_storage"},{"astId":11,"contract":"fileA:A","label":"dynArray","offset":0,"slot":"3","type":"t_array(t_uint256)dyn_storage"}],"numberOfBytes":"128"},"t_uint128":{"encoding":"inplace","label":"uint128","numberOfBytes":"16"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version!
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}} ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}}

View File

@ -1,2 +1,2 @@
{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":2,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":4,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":6,"contract":"fileA:A","label":"addr","offset":0,"slot":"2","type":"t_address"},{"astId":10,"contract":"fileA:A","label":"array","offset":0,"slot":"3","type":"t_array(t_uint256)2_storage"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! {"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":2,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":4,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":6,"contract":"fileA:A","label":"addr","offset":0,"slot":"2","type":"t_address"},{"astId":10,"contract":"fileA:A","label":"array","offset":0,"slot":"3","type":"t_array(t_uint256)2_storage"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version!
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}} ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}}

View File

@ -1,2 +1,2 @@
{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":2,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint64"},{"astId":4,"contract":"fileA:A","label":"y","offset":8,"slot":"0","type":"t_uint128"},{"astId":6,"contract":"fileA:A","label":"z","offset":0,"slot":"1","type":"t_uint128"},{"astId":8,"contract":"fileA:A","label":"addr","offset":0,"slot":"2","type":"t_address"},{"astId":12,"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_uint128":{"encoding":"inplace","label":"uint128","numberOfBytes":"16"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"},"t_uint64":{"encoding":"inplace","label":"uint64","numberOfBytes":"8"}}}}}},"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_uint64"},{"astId":4,"contract":"fileA:A","label":"y","offset":8,"slot":"0","type":"t_uint128"},{"astId":6,"contract":"fileA:A","label":"z","offset":0,"slot":"1","type":"t_uint128"},{"astId":8,"contract":"fileA:A","label":"addr","offset":0,"slot":"2","type":"t_address"},{"astId":12,"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_uint128":{"encoding":"inplace","label":"uint128","numberOfBytes":"16"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"},"t_uint64":{"encoding":"inplace","label":"uint64","numberOfBytes":"8"}}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version!
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}} ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}}

View File

@ -0,0 +1 @@
--yul --yul-dialect ewasm --machine ewasm

View File

@ -0,0 +1 @@
Warning: Yul is still experimental. Please use the output with care.

View File

@ -0,0 +1,17 @@
object "object" {
code {
function main()
{
let m:i64, n:i32, p:i32, q:i64 := multireturn(1:i32, 2:i64, 3:i64, 4:i32)
}
function multireturn(a:i32, b:i64, c:i64, d:i32) -> x:i64, y:i32, z:i32, w:i64
{
x := b
w := c
y := a
z := d
}
}
}

View File

@ -0,0 +1,73 @@
======= wasm_to_wasm_function_returning_multiple_values/input.yul (Ewasm) =======
Pretty printed source:
object "object" {
code {
function main()
{
let m, n:i32, p:i32, q := multireturn(1:i32, 2, 3, 4:i32)
}
function multireturn(a:i32, b, c, d:i32) -> x, y:i32, z:i32, w
{
x := b
w := c
y := a
z := d
}
}
}
Binary representation:
0061736d01000000010c0260000060047e7e7e7e017e020100030302000105030100010610037e0142000b7e0142000b7e0142000b071102066d656d6f72790200046d61696e00000a4a022201047e024002404201420242034204100121002300210123012102230221030b0b0b2501047e0240200121042002210720002105200321060b20052400200624012007240220040b
Text representation:
(module
(memory $memory (export "memory") 1)
(export "main" (func $main))
(global $global_ (mut i64) (i64.const 0))
(global $global__1 (mut i64) (i64.const 0))
(global $global__2 (mut i64) (i64.const 0))
(func $main
(local $m i64)
(local $n i64)
(local $p i64)
(local $q i64)
(block $label_
(block
(local.set $m (call $multireturn (i64.const 1) (i64.const 2) (i64.const 3) (i64.const 4)))
(local.set $n (global.get $global_))
(local.set $p (global.get $global__1))
(local.set $q (global.get $global__2))
)
)
)
(func $multireturn
(param $a i64)
(param $b i64)
(param $c i64)
(param $d i64)
(result i64)
(local $x i64)
(local $y i64)
(local $z i64)
(local $w i64)
(block $label__3
(local.set $x (local.get $b))
(local.set $w (local.get $c))
(local.set $y (local.get $a))
(local.set $z (local.get $d))
)
(global.set $global_ (local.get $y))
(global.set $global__1 (local.get $z))
(global.set $global__2 (local.get $w))
(local.get $x)
)
)

View File

@ -0,0 +1 @@
--yul --yul-dialect ewasm --machine ewasm

View File

@ -0,0 +1 @@
Warning: Yul is still experimental. Please use the output with care.

View File

@ -0,0 +1,8 @@
object "object" {
code {
function main()
{
i64.store8(0x01:i32, 42:i64)
}
}
}

View File

@ -0,0 +1,27 @@
======= wasm_to_wasm_memory_instructions_alignment/input.yul (Ewasm) =======
Pretty printed source:
object "object" {
code {
function main()
{ i64.store8(0x01:i32, 42) }
}
}
Binary representation:
0061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e00000a0f010d0002404201a7422a3c00000b0b
Text representation:
(module
(memory $memory (export "memory") 1)
(export "main" (func $main))
(func $main
(block $label_
(i64.store8 (i32.wrap_i64 (i64.const 1)) (i64.const 42))
)
)
)

View File

@ -606,7 +606,7 @@ BOOST_AUTO_TEST_CASE(bytesNN_arrays)
BOTH_ENCODERS( BOTH_ENCODERS(
for (size_t size = 1; size < 15; size++) for (size_t size = 1; size < 15; size++)
{ {
for (size_t width: {1, 2, 4, 5, 7, 15, 16, 17, 31, 32}) for (size_t width: {1u, 2u, 4u, 5u, 7u, 15u, 16u, 17u, 31u, 32u})
{ {
string source = boost::algorithm::replace_all_copy(sourceCode, "SIZE", to_string(size)); string source = boost::algorithm::replace_all_copy(sourceCode, "SIZE", to_string(size));
source = boost::algorithm::replace_all_copy(source, "UINTWIDTH", to_string(width * 8)); source = boost::algorithm::replace_all_copy(source, "UINTWIDTH", to_string(width * 8));
@ -651,7 +651,7 @@ BOOST_AUTO_TEST_CASE(bytesNN_arrays_dyn)
BOTH_ENCODERS( BOTH_ENCODERS(
for (size_t size = 0; size < 15; size++) for (size_t size = 0; size < 15; size++)
{ {
for (size_t width: {1, 2, 4, 5, 7, 15, 16, 17, 31, 32}) for (size_t width: {1u, 2u, 4u, 5u, 7u, 15u, 16u, 17u, 31u, 32u})
{ {
string source = boost::algorithm::replace_all_copy(sourceCode, "SIZE", to_string(size)); string source = boost::algorithm::replace_all_copy(sourceCode, "SIZE", to_string(size));
source = boost::algorithm::replace_all_copy(source, "UINTWIDTH", to_string(width * 8)); source = boost::algorithm::replace_all_copy(source, "UINTWIDTH", to_string(width * 8));

View File

@ -33,14 +33,14 @@
{ {
"id": 4, "id": 4,
"nodeType": "Block", "nodeType": "Block",
"src": "42:48:1", "src": "42:58:1",
"statements": "statements":
[ [
{ {
"AST": "AST":
{ {
"nodeType": "YulBlock", "nodeType": "YulBlock",
"src": "61:23:1", "src": "61:33:1",
"statements": "statements":
[ [
{ {
@ -50,11 +50,29 @@
"body": "body":
{ {
"nodeType": "YulBlock", "nodeType": "YulBlock",
"src": "80:2:1", "src": "79:2:1",
"statements": [] "statements": []
}, },
"nodeType": "YulCase", "nodeType": "YulCase",
"src": "72:10:1", "src": "72:9:1",
"value":
{
"kind": "number",
"nodeType": "YulLiteral",
"src": "77:1:1",
"type": "",
"value": "0"
}
},
{
"body":
{
"nodeType": "YulBlock",
"src": "90:2:1",
"statements": []
},
"nodeType": "YulCase",
"src": "82:10:1",
"value": "default" "value": "default"
} }
], ],
@ -67,7 +85,7 @@
"value": "0" "value": "0"
}, },
"nodeType": "YulSwitch", "nodeType": "YulSwitch",
"src": "63:19:1" "src": "63:29:1"
} }
] ]
}, },
@ -75,7 +93,7 @@
"externalReferences": [], "externalReferences": [],
"id": 3, "id": 3,
"nodeType": "InlineAssembly", "nodeType": "InlineAssembly",
"src": "52:32:1" "src": "52:42:1"
} }
] ]
}, },
@ -103,15 +121,15 @@
"src": "42:0:1" "src": "42:0:1"
}, },
"scope": 6, "scope": 6,
"src": "17:73:1", "src": "17:83:1",
"stateMutability": "view", "stateMutability": "view",
"virtual": false, "virtual": false,
"visibility": "public" "visibility": "public"
} }
], ],
"scope": 7, "scope": 7,
"src": "0:92:1" "src": "0:102:1"
} }
], ],
"src": "0:93:1" "src": "0:103:1"
} }

View File

@ -1,6 +1,6 @@
contract C { contract C {
function g() view public { function g() view public {
assembly { switch 0 default {} } assembly { switch 0 case 0 {} default {} }
} }
} }

View File

@ -95,30 +95,30 @@
[ [
null null
], ],
"operations": "{\n switch 0\n default { }\n}" "operations": "{\n switch 0\n case 0 { }\n default { }\n}"
}, },
"children": [], "children": [],
"id": 3, "id": 3,
"name": "InlineAssembly", "name": "InlineAssembly",
"src": "52:32:1" "src": "52:42:1"
} }
], ],
"id": 4, "id": 4,
"name": "Block", "name": "Block",
"src": "42:48:1" "src": "42:58:1"
} }
], ],
"id": 5, "id": 5,
"name": "FunctionDefinition", "name": "FunctionDefinition",
"src": "17:73:1" "src": "17:83:1"
} }
], ],
"id": 6, "id": 6,
"name": "ContractDefinition", "name": "ContractDefinition",
"src": "0:92:1" "src": "0:102:1"
} }
], ],
"id": 7, "id": 7,
"name": "SourceUnit", "name": "SourceUnit",
"src": "0:93:1" "src": "0:103:1"
} }

Some files were not shown because too many files have changed in this diff Show More