mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge remote-tracking branch 'origin/develop' into breaking
This commit is contained in:
@@ -68,7 +68,7 @@ struct OverrideGraph
|
||||
std::map<OverrideProxy, int> nodes;
|
||||
std::map<int, OverrideProxy> nodeInv;
|
||||
std::map<int, std::set<int>> edges;
|
||||
int numNodes = 2;
|
||||
size_t numNodes = 2;
|
||||
void addEdge(int _a, int _b)
|
||||
{
|
||||
edges[_a].insert(_b);
|
||||
@@ -82,7 +82,7 @@ private:
|
||||
auto it = nodes.find(_function);
|
||||
if (it != nodes.end())
|
||||
return it->second;
|
||||
int currentNode = numNodes++;
|
||||
int currentNode = static_cast<int>(numNodes++);
|
||||
nodes[_function] = currentNode;
|
||||
nodeInv[currentNode] = _function;
|
||||
if (_function.overrides())
|
||||
@@ -116,21 +116,24 @@ private:
|
||||
std::vector<int> m_parent = std::vector<int>(m_graph.numNodes, -1);
|
||||
std::set<OverrideProxy> m_cutVertices{};
|
||||
|
||||
void run(int _u = 0, int _depth = 0)
|
||||
void run(size_t _u = 0, size_t _depth = 0)
|
||||
{
|
||||
m_visited.at(_u) = true;
|
||||
m_depths.at(_u) = m_low.at(_u) = _depth;
|
||||
for (int v: m_graph.edges.at(_u))
|
||||
if (!m_visited.at(v))
|
||||
m_depths.at(_u) = m_low.at(_u) = static_cast<int>(_depth);
|
||||
for (int const v: m_graph.edges.at(static_cast<int>(_u)))
|
||||
{
|
||||
auto const vInd = static_cast<size_t>(v);
|
||||
if (!m_visited.at(vInd))
|
||||
{
|
||||
m_parent[v] = _u;
|
||||
run(v, _depth + 1);
|
||||
if (m_low[v] >= m_depths[_u] && m_parent[_u] != -1)
|
||||
m_cutVertices.insert(m_graph.nodeInv.at(_u));
|
||||
m_low[_u] = min(m_low[_u], m_low[v]);
|
||||
m_parent[vInd] = static_cast<int>(_u);
|
||||
run(vInd, _depth + 1);
|
||||
if (m_low[vInd] >= m_depths[_u] && m_parent[_u] != -1)
|
||||
m_cutVertices.insert(m_graph.nodeInv.at(static_cast<int>(_u)));
|
||||
m_low[_u] = min(m_low[_u], m_low[vInd]);
|
||||
}
|
||||
else if (v != m_parent[_u])
|
||||
m_low[_u] = min(m_low[_u], m_depths[v]);
|
||||
m_low[_u] = min(m_low[_u], m_depths[vInd]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -213,7 +216,7 @@ bool OverrideProxy::CompareBySignature::operator()(OverrideProxy const& _a, Over
|
||||
size_t OverrideProxy::id() const
|
||||
{
|
||||
return std::visit(GenericVisitor{
|
||||
[&](auto const* _item) -> size_t { return _item->id(); }
|
||||
[&](auto const* _item) -> size_t { return static_cast<size_t>(_item->id()); }
|
||||
}, m_item);
|
||||
}
|
||||
|
||||
|
||||
@@ -668,7 +668,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
{
|
||||
auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier);
|
||||
if (ref == _inlineAssembly.annotation().externalReferences.end())
|
||||
return size_t(-1);
|
||||
return numeric_limits<size_t>::max();
|
||||
Declaration const* declaration = ref->second.declaration;
|
||||
solAssert(!!declaration, "");
|
||||
bool requiresStorage = ref->second.isSlot || ref->second.isOffset;
|
||||
@@ -678,7 +678,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
if (var->immutable())
|
||||
{
|
||||
m_errorReporter.typeError(3773_error, _identifier.location, "Assembly access to immutable variables is not supported.");
|
||||
return size_t(-1);
|
||||
return numeric_limits<size_t>::max();
|
||||
}
|
||||
if (var->isConstant())
|
||||
{
|
||||
@@ -687,17 +687,17 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
if (var && !var->value())
|
||||
{
|
||||
m_errorReporter.typeError(3224_error, _identifier.location, "Constant has no value.");
|
||||
return size_t(-1);
|
||||
return numeric_limits<size_t>::max();
|
||||
}
|
||||
else if (_context == yul::IdentifierContext::LValue)
|
||||
{
|
||||
m_errorReporter.typeError(6252_error, _identifier.location, "Constant variables cannot be assigned to.");
|
||||
return size_t(-1);
|
||||
return numeric_limits<size_t>::max();
|
||||
}
|
||||
else if (requiresStorage)
|
||||
{
|
||||
m_errorReporter.typeError(6617_error, _identifier.location, "The suffixes _offset and _slot can only be used on non-constant storage variables.");
|
||||
return size_t(-1);
|
||||
return numeric_limits<size_t>::max();
|
||||
}
|
||||
else if (var && var->value() && !var->value()->annotation().type && !dynamic_cast<Literal const*>(var->value().get()))
|
||||
{
|
||||
@@ -725,19 +725,19 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
if (!var->isStateVariable() && !var->type()->dataStoredIn(DataLocation::Storage))
|
||||
{
|
||||
m_errorReporter.typeError(3622_error, _identifier.location, "The suffixes _offset and _slot can only be used on storage variables.");
|
||||
return size_t(-1);
|
||||
return numeric_limits<size_t>::max();
|
||||
}
|
||||
else if (_context == yul::IdentifierContext::LValue)
|
||||
{
|
||||
if (var->isStateVariable())
|
||||
{
|
||||
m_errorReporter.typeError(4713_error, _identifier.location, "State variables cannot be assigned to - you have to use \"sstore()\".");
|
||||
return size_t(-1);
|
||||
return numeric_limits<size_t>::max();
|
||||
}
|
||||
else if (ref->second.isOffset)
|
||||
{
|
||||
m_errorReporter.typeError(9739_error, _identifier.location, "Only _slot can be assigned to.");
|
||||
return size_t(-1);
|
||||
return numeric_limits<size_t>::max();
|
||||
}
|
||||
else
|
||||
solAssert(ref->second.isSlot, "");
|
||||
@@ -746,12 +746,12 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
else if (!var->isConstant() && var->isStateVariable())
|
||||
{
|
||||
m_errorReporter.typeError(1408_error, _identifier.location, "Only local variables are supported. To access storage variables, use the _slot and _offset suffixes.");
|
||||
return size_t(-1);
|
||||
return numeric_limits<size_t>::max();
|
||||
}
|
||||
else if (var->type()->dataStoredIn(DataLocation::Storage))
|
||||
{
|
||||
m_errorReporter.typeError(9068_error, _identifier.location, "You have to use the _slot or _offset suffix to access storage reference variables.");
|
||||
return size_t(-1);
|
||||
return numeric_limits<size_t>::max();
|
||||
}
|
||||
else if (var->type()->sizeOnStack() != 1)
|
||||
{
|
||||
@@ -759,21 +759,21 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
m_errorReporter.typeError(2370_error, _identifier.location, "Call data elements cannot be accessed directly. Copy to a local variable first or use \"calldataload\" or \"calldatacopy\" with manually determined offsets and sizes.");
|
||||
else
|
||||
m_errorReporter.typeError(9857_error, _identifier.location, "Only types that use one stack slot are supported.");
|
||||
return size_t(-1);
|
||||
return numeric_limits<size_t>::max();
|
||||
}
|
||||
}
|
||||
else if (requiresStorage)
|
||||
{
|
||||
m_errorReporter.typeError(7944_error, _identifier.location, "The suffixes _offset and _slot can only be used on storage variables.");
|
||||
return size_t(-1);
|
||||
return numeric_limits<size_t>::max();
|
||||
}
|
||||
else if (_context == yul::IdentifierContext::LValue)
|
||||
{
|
||||
if (dynamic_cast<MagicVariableDeclaration const*>(declaration))
|
||||
return size_t(-1);
|
||||
return numeric_limits<size_t>::max();
|
||||
|
||||
m_errorReporter.typeError(1990_error, _identifier.location, "Only local variables can be assigned to in inline assembly.");
|
||||
return size_t(-1);
|
||||
return numeric_limits<size_t>::max();
|
||||
}
|
||||
|
||||
if (_context == yul::IdentifierContext::RValue)
|
||||
@@ -782,7 +782,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
if (dynamic_cast<FunctionDefinition const*>(declaration))
|
||||
{
|
||||
m_errorReporter.declarationError(2025_error, _identifier.location, "Access to functions is not allowed in inline assembly.");
|
||||
return size_t(-1);
|
||||
return numeric_limits<size_t>::max();
|
||||
}
|
||||
else if (dynamic_cast<VariableDeclaration const*>(declaration))
|
||||
{
|
||||
@@ -792,11 +792,11 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
if (!contract->isLibrary())
|
||||
{
|
||||
m_errorReporter.typeError(4977_error, _identifier.location, "Expected a library.");
|
||||
return size_t(-1);
|
||||
return numeric_limits<size_t>::max();
|
||||
}
|
||||
}
|
||||
else
|
||||
return size_t(-1);
|
||||
return numeric_limits<size_t>::max();
|
||||
}
|
||||
ref->second.valueSize = 1;
|
||||
return size_t(1);
|
||||
|
||||
@@ -38,7 +38,7 @@ using namespace solidity;
|
||||
using namespace solidity::frontend;
|
||||
|
||||
ASTNode::ASTNode(int64_t _id, SourceLocation _location):
|
||||
m_id(_id),
|
||||
m_id(static_cast<size_t>(_id)),
|
||||
m_location(std::move(_location))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ public:
|
||||
virtual ~ASTNode() {}
|
||||
|
||||
/// @returns an identifier of this AST node that is unique for a single compilation run.
|
||||
int64_t id() const { return m_id; }
|
||||
int64_t id() const { return int64_t(m_id); }
|
||||
|
||||
virtual void accept(ASTVisitor& _visitor) = 0;
|
||||
virtual void accept(ASTConstVisitor& _visitor) const = 0;
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity::langutil;
|
||||
@@ -134,7 +135,7 @@ size_t ASTJsonConverter::sourceIndexFromLocation(SourceLocation const& _location
|
||||
if (_location.source && m_sourceIndices.count(_location.source->name()))
|
||||
return m_sourceIndices.at(_location.source->name());
|
||||
else
|
||||
return size_t(-1);
|
||||
return numeric_limits<size_t>::max();
|
||||
}
|
||||
|
||||
string ASTJsonConverter::sourceLocationToString(SourceLocation const& _location) const
|
||||
|
||||
@@ -92,7 +92,7 @@ SourceLocation const ASTJsonImporter::createSourceLocation(Json::Value const& _n
|
||||
{
|
||||
astAssert(member(_node, "src").isString(), "'src' must be a string");
|
||||
|
||||
return solidity::langutil::parseSourceLocation(_node["src"].asString(), m_currentSourceName, int(m_sourceLocations.size()));
|
||||
return solidity::langutil::parseSourceLocation(_node["src"].asString(), m_currentSourceName, m_sourceLocations.size());
|
||||
}
|
||||
|
||||
template<class T>
|
||||
|
||||
@@ -113,14 +113,22 @@ public:
|
||||
/// @returns a copy of @a _type having the same location as this (and is not a pointer type)
|
||||
/// if _type is a reference type and an unmodified copy of _type otherwise.
|
||||
/// This function is mostly useful to modify inner types appropriately.
|
||||
static Type const* withLocationIfReference(DataLocation _location, Type const* _type)
|
||||
static Type const* withLocationIfReference(DataLocation _location, Type const* _type, bool _isPointer = false)
|
||||
{
|
||||
if (auto refType = dynamic_cast<ReferenceType const*>(_type))
|
||||
return withLocation(refType, _location, false);
|
||||
return withLocation(refType, _location, _isPointer);
|
||||
|
||||
return _type;
|
||||
}
|
||||
|
||||
static bool isReferenceWithLocation(Type const* _type, DataLocation _location)
|
||||
{
|
||||
if (auto const* refType = dynamic_cast<ReferenceType const*>(_type))
|
||||
if (refType->location() == _location)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// @returns the internally-facing or externally-facing type of a function or the type of a function declaration.
|
||||
static FunctionType const* function(FunctionDefinition const& _function, FunctionType::Kind _kind = FunctionType::Kind::Declaration);
|
||||
|
||||
|
||||
+75
-24
@@ -356,10 +356,18 @@ MemberList::MemberMap Type::boundFunctions(Type const& _type, ContractDefinition
|
||||
for (ContractDefinition const* contract: _scope.annotation().linearizedBaseContracts)
|
||||
for (UsingForDirective const* ufd: contract->usingForDirectives())
|
||||
{
|
||||
if (ufd->typeName() && _type != *TypeProvider::withLocationIfReference(
|
||||
typeLocation,
|
||||
ufd->typeName()->annotation().type
|
||||
))
|
||||
// Convert both types to pointers for comparison to see if the `using for`
|
||||
// directive applies.
|
||||
// Further down, we check more detailed for each function if `_type` is
|
||||
// convertible to the function parameter type.
|
||||
if (ufd->typeName() &&
|
||||
*TypeProvider::withLocationIfReference(typeLocation, &_type, true) !=
|
||||
*TypeProvider::withLocationIfReference(
|
||||
typeLocation,
|
||||
ufd->typeName()->annotation().type,
|
||||
true
|
||||
)
|
||||
)
|
||||
continue;
|
||||
auto const& library = dynamic_cast<ContractDefinition const&>(
|
||||
*ufd->libraryName().annotation().referencedDeclaration
|
||||
@@ -371,7 +379,8 @@ MemberList::MemberMap Type::boundFunctions(Type const& _type, ContractDefinition
|
||||
seenFunctions.insert(function);
|
||||
if (function->parameters().empty())
|
||||
continue;
|
||||
FunctionTypePointer fun = FunctionType(*function, FunctionType::Kind::External).asExternallyCallableFunction(true, true);
|
||||
FunctionTypePointer fun =
|
||||
dynamic_cast<FunctionType const&>(*function->typeViaContractName()).asBoundFunction();
|
||||
if (_type.isImplicitlyConvertibleTo(*fun->selfType()))
|
||||
members.emplace_back(function->name(), fun, function);
|
||||
}
|
||||
@@ -773,7 +782,7 @@ tuple<bool, rational> RationalNumberType::parseRational(string const& _value)
|
||||
denominator = bigint(string(fractionalBegin, _value.end()));
|
||||
denominator /= boost::multiprecision::pow(
|
||||
bigint(10),
|
||||
distance(radixPoint + 1, _value.end())
|
||||
static_cast<size_t>(distance(radixPoint + 1, _value.end()))
|
||||
);
|
||||
numerator = bigint(string(_value.begin(), radixPoint));
|
||||
value = numerator + denominator;
|
||||
@@ -1093,7 +1102,7 @@ TypeResult RationalNumberType::binaryOperatorResult(Token _operator, Type const*
|
||||
if (_base == 1)
|
||||
return 1;
|
||||
else if (_base == -1)
|
||||
return 1 - 2 * int(_exponent & 1);
|
||||
return 1 - 2 * static_cast<int>(_exponent & 1);
|
||||
else
|
||||
return boost::multiprecision::pow(_base, _exponent);
|
||||
};
|
||||
@@ -1199,7 +1208,7 @@ string RationalNumberType::bigintToReadableString(bigint const& _num)
|
||||
string str = _num.str();
|
||||
if (str.size() > 32)
|
||||
{
|
||||
int omitted = str.size() - 8;
|
||||
size_t omitted = str.size() - 8;
|
||||
str = str.substr(0, 4) + "...(" + to_string(omitted) + " digits omitted)..." + str.substr(str.size() - 4, 4);
|
||||
}
|
||||
return str;
|
||||
@@ -1229,7 +1238,7 @@ u256 RationalNumberType::literalValue(Literal const*) const
|
||||
{
|
||||
auto fixed = fixedPointType();
|
||||
solAssert(fixed, "Rational number cannot be represented as fixed point type.");
|
||||
int fractionalDigits = fixed->fractionalDigits();
|
||||
unsigned fractionalDigits = fixed->fractionalDigits();
|
||||
shiftedValue = m_value.numerator() * boost::multiprecision::pow(bigint(10), fractionalDigits) / m_value.denominator();
|
||||
}
|
||||
|
||||
@@ -1319,7 +1328,7 @@ StringLiteralType::StringLiteralType(string _value):
|
||||
BoolResult StringLiteralType::isImplicitlyConvertibleTo(Type const& _convertTo) const
|
||||
{
|
||||
if (auto fixedBytes = dynamic_cast<FixedBytesType const*>(&_convertTo))
|
||||
return size_t(fixedBytes->numBytes()) >= m_value.size();
|
||||
return static_cast<size_t>(fixedBytes->numBytes()) >= m_value.size();
|
||||
else if (auto arrayType = dynamic_cast<ArrayType const*>(&_convertTo))
|
||||
return
|
||||
arrayType->isByteArray() &&
|
||||
@@ -2485,6 +2494,21 @@ set<string> StructType::membersMissingInMemory() const
|
||||
return missing;
|
||||
}
|
||||
|
||||
vector<tuple<string, TypePointer>> StructType::makeStackItems() const
|
||||
{
|
||||
switch (m_location)
|
||||
{
|
||||
case DataLocation::CallData:
|
||||
return {std::make_tuple("offset", TypeProvider::uint256())};
|
||||
case DataLocation::Memory:
|
||||
return {std::make_tuple("mpos", TypeProvider::uint256())};
|
||||
case DataLocation::Storage:
|
||||
return {std::make_tuple("slot", TypeProvider::uint256())};
|
||||
}
|
||||
solAssert(false, "");
|
||||
}
|
||||
|
||||
|
||||
TypePointer EnumType::encodingType() const
|
||||
{
|
||||
return TypeProvider::uint(8 * storageBytes());
|
||||
@@ -3466,34 +3490,61 @@ TypePointer FunctionType::copyAndSetCallOptions(bool _setGas, bool _setValue, bo
|
||||
);
|
||||
}
|
||||
|
||||
FunctionTypePointer FunctionType::asExternallyCallableFunction(bool _inLibrary, bool _bound) const
|
||||
FunctionTypePointer FunctionType::asBoundFunction() const
|
||||
{
|
||||
if (_bound)
|
||||
solAssert(!m_parameterTypes.empty(), "");
|
||||
solAssert(!m_parameterTypes.empty(), "");
|
||||
FunctionDefinition const* fun = dynamic_cast<FunctionDefinition const*>(m_declaration);
|
||||
solAssert(fun && fun->libraryFunction(), "");
|
||||
solAssert(!m_gasSet, "");
|
||||
solAssert(!m_valueSet, "");
|
||||
solAssert(!m_saltSet, "");
|
||||
return TypeProvider::function(
|
||||
m_parameterTypes,
|
||||
m_returnParameterTypes,
|
||||
m_parameterNames,
|
||||
m_returnParameterNames,
|
||||
m_kind,
|
||||
m_arbitraryParameters,
|
||||
m_stateMutability,
|
||||
m_declaration,
|
||||
m_gasSet,
|
||||
m_valueSet,
|
||||
m_saltSet,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
FunctionTypePointer FunctionType::asExternallyCallableFunction(bool _inLibrary) const
|
||||
{
|
||||
TypePointers parameterTypes;
|
||||
for (auto const& t: m_parameterTypes)
|
||||
{
|
||||
auto refType = dynamic_cast<ReferenceType const*>(t);
|
||||
if (refType && refType->location() == DataLocation::CallData)
|
||||
parameterTypes.push_back(TypeProvider::withLocation(refType, DataLocation::Memory, true));
|
||||
if (TypeProvider::isReferenceWithLocation(t, DataLocation::CallData))
|
||||
parameterTypes.push_back(
|
||||
TypeProvider::withLocationIfReference(DataLocation::Memory, t, true)
|
||||
);
|
||||
else
|
||||
parameterTypes.push_back(t);
|
||||
}
|
||||
|
||||
TypePointers returnParameterTypes;
|
||||
for (auto const& returnParamType: m_returnParameterTypes)
|
||||
if (TypeProvider::isReferenceWithLocation(returnParamType, DataLocation::CallData))
|
||||
returnParameterTypes.push_back(
|
||||
TypeProvider::withLocationIfReference(DataLocation::Memory, returnParamType, true)
|
||||
);
|
||||
else
|
||||
returnParameterTypes.push_back(returnParamType);
|
||||
|
||||
Kind kind = m_kind;
|
||||
if (_inLibrary)
|
||||
{
|
||||
solAssert(!!m_declaration, "Declaration has to be available.");
|
||||
if (!m_declaration->isPublic())
|
||||
kind = Kind::Internal; // will be inlined
|
||||
else
|
||||
kind = Kind::DelegateCall;
|
||||
solAssert(m_declaration->isPublic(), "");
|
||||
kind = Kind::DelegateCall;
|
||||
}
|
||||
|
||||
return TypeProvider::function(
|
||||
parameterTypes,
|
||||
m_returnParameterTypes,
|
||||
returnParameterTypes,
|
||||
m_parameterNames,
|
||||
m_returnParameterNames,
|
||||
kind,
|
||||
@@ -3503,7 +3554,7 @@ FunctionTypePointer FunctionType::asExternallyCallableFunction(bool _inLibrary,
|
||||
m_gasSet,
|
||||
m_valueSet,
|
||||
m_saltSet,
|
||||
_bound
|
||||
m_bound
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -980,6 +980,8 @@ public:
|
||||
|
||||
void clearCache() const override;
|
||||
|
||||
protected:
|
||||
std::vector<std::tuple<std::string, TypePointer>> makeStackItems() const override;
|
||||
private:
|
||||
StructDefinition const& m_struct;
|
||||
// Caches for interfaceType(bool)
|
||||
@@ -1302,13 +1304,16 @@ public:
|
||||
/// of the parameters to false.
|
||||
TypePointer copyAndSetCallOptions(bool _setGas, bool _setValue, bool _setSalt) const;
|
||||
|
||||
/// @returns a copy of this function type with the `bound` flag set to true.
|
||||
/// Should only be called on library functions.
|
||||
FunctionTypePointer asBoundFunction() const;
|
||||
|
||||
/// @returns a copy of this function type where the location of reference types is changed
|
||||
/// from CallData to Memory. This is the type that would be used when the function is
|
||||
/// called externally, as opposed to the parameter types that are available inside the function body.
|
||||
/// Also supports variants to be used for library or bound calls.
|
||||
/// @param _inLibrary if true, uses DelegateCall as location.
|
||||
/// @param _bound if true, the function type is set to be bound.
|
||||
FunctionTypePointer asExternallyCallableFunction(bool _inLibrary, bool _bound = false) const;
|
||||
FunctionTypePointer asExternallyCallableFunction(bool _inLibrary) const;
|
||||
|
||||
protected:
|
||||
std::vector<std::tuple<std::string, TypePointer>> makeStackItems() const override;
|
||||
|
||||
@@ -725,7 +725,7 @@ string ABIFunctions::abiEncodingFunctionCompactStorageArray(
|
||||
size_t itemsPerSlot = 32 / storageBytes;
|
||||
solAssert(itemsPerSlot > 0, "");
|
||||
// The number of elements we need to handle manually after the loop.
|
||||
size_t spill = size_t(_from.length() % itemsPerSlot);
|
||||
size_t spill = static_cast<size_t>(_from.length() % itemsPerSlot);
|
||||
Whiskers templ(
|
||||
R"(
|
||||
// <readableTypeNameFrom> -> <readableTypeNameTo>
|
||||
|
||||
@@ -56,7 +56,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
||||
bool directCopy = sourceIsStorage && sourceBaseType->isValueType() && *sourceBaseType == *targetBaseType;
|
||||
bool haveByteOffsetSource = !directCopy && sourceIsStorage && sourceBaseType->storageBytes() <= 16;
|
||||
bool haveByteOffsetTarget = !directCopy && targetBaseType->storageBytes() <= 16;
|
||||
unsigned byteOffsetSize = (haveByteOffsetSource ? 1 : 0) + (haveByteOffsetTarget ? 1 : 0);
|
||||
unsigned byteOffsetSize = (haveByteOffsetSource ? 1u : 0u) + (haveByteOffsetTarget ? 1u : 0u);
|
||||
|
||||
// stack: source_ref [source_length] target_ref
|
||||
// store target_ref
|
||||
|
||||
@@ -133,7 +133,7 @@ void CompilerContext::callLowLevelFunction(
|
||||
*this << lowLevelFunctionTag(_name, _inArgs, _outArgs, _generator);
|
||||
|
||||
appendJump(evmasm::AssemblyItem::JumpType::IntoFunction);
|
||||
adjustStackOffset(int(_outArgs) - 1 - _inArgs);
|
||||
adjustStackOffset(static_cast<int>(_outArgs) - 1 - static_cast<int>(_inArgs));
|
||||
*this << retTag.tag();
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ void CompilerContext::callYulFunction(
|
||||
auto const retTag = pushNewTag();
|
||||
CompilerUtils(*this).moveIntoStack(_inArgs);
|
||||
appendJumpTo(namedTag(_name));
|
||||
adjustStackOffset(int(_outArgs) - 1 - _inArgs);
|
||||
adjustStackOffset(static_cast<int>(_outArgs) - 1 - static_cast<int>(_inArgs));
|
||||
*this << retTag.tag();
|
||||
}
|
||||
|
||||
@@ -181,7 +181,7 @@ void CompilerContext::appendMissingLowLevelFunctions()
|
||||
tie(name, inArgs, outArgs, generator) = m_lowLevelFunctionGenerationQueue.front();
|
||||
m_lowLevelFunctionGenerationQueue.pop();
|
||||
|
||||
setStackOffset(inArgs + 1);
|
||||
setStackOffset(static_cast<int>(inArgs) + 1);
|
||||
*this << m_lowLevelFunctions.at(name).tag();
|
||||
generator(*this);
|
||||
CompilerUtils(*this).moveToStackTop(outArgs);
|
||||
@@ -298,12 +298,12 @@ unsigned CompilerContext::baseStackOffsetOfVariable(Declaration const& _declarat
|
||||
|
||||
unsigned CompilerContext::baseToCurrentStackOffset(unsigned _baseOffset) const
|
||||
{
|
||||
return m_asm->deposit() - _baseOffset - 1;
|
||||
return static_cast<unsigned>(m_asm->deposit()) - _baseOffset - 1;
|
||||
}
|
||||
|
||||
unsigned CompilerContext::currentToBaseStackOffset(unsigned _offset) const
|
||||
{
|
||||
return m_asm->deposit() - _offset - 1;
|
||||
return static_cast<unsigned>(m_asm->deposit()) - _offset - 1;
|
||||
}
|
||||
|
||||
pair<u256, unsigned> CompilerContext::storageLocationOfVariable(Declaration const& _declaration) const
|
||||
@@ -371,7 +371,7 @@ void CompilerContext::appendInlineAssembly(
|
||||
OptimiserSettings const& _optimiserSettings
|
||||
)
|
||||
{
|
||||
int startStackHeight = stackHeight();
|
||||
unsigned startStackHeight = stackHeight();
|
||||
|
||||
set<yul::YulString> externallyUsedIdentifiers;
|
||||
for (auto const& fun: _externallyUsedFunctions)
|
||||
@@ -387,9 +387,9 @@ void CompilerContext::appendInlineAssembly(
|
||||
) -> size_t
|
||||
{
|
||||
if (_insideFunction)
|
||||
return size_t(-1);
|
||||
return numeric_limits<size_t>::max();
|
||||
auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name.str());
|
||||
return it == _localVariables.end() ? size_t(-1) : 1;
|
||||
return it == _localVariables.end() ? numeric_limits<size_t>::max() : 1;
|
||||
};
|
||||
identifierAccess.generateCode = [&](
|
||||
yul::Identifier const& _identifier,
|
||||
@@ -399,8 +399,8 @@ void CompilerContext::appendInlineAssembly(
|
||||
{
|
||||
auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name.str());
|
||||
solAssert(it != _localVariables.end(), "");
|
||||
int stackDepth = _localVariables.end() - it;
|
||||
int stackDiff = _assembly.stackHeight() - startStackHeight + stackDepth;
|
||||
auto stackDepth = static_cast<size_t>(distance(it, _localVariables.end()));
|
||||
size_t stackDiff = static_cast<size_t>(_assembly.stackHeight()) - startStackHeight + stackDepth;
|
||||
if (_context == yul::IdentifierContext::LValue)
|
||||
stackDiff -= 1;
|
||||
if (stackDiff < 1 || stackDiff > 16)
|
||||
|
||||
@@ -377,7 +377,7 @@ private:
|
||||
/// The runtime context if in Creation mode, this is used for generating tags that would be stored into the storage and then used at runtime.
|
||||
CompilerContext *m_runtimeContext;
|
||||
/// The index of the runtime subroutine.
|
||||
size_t m_runtimeSub = -1;
|
||||
size_t m_runtimeSub = std::numeric_limits<size_t>::max();
|
||||
/// An index of low-level function labels by name.
|
||||
std::map<std::string, evmasm::AssemblyItem> m_lowLevelFunctions;
|
||||
/// Collector for yul functions.
|
||||
|
||||
@@ -1351,7 +1351,7 @@ void CompilerUtils::popAndJump(unsigned _toHeight, evmasm::AssemblyItem const& _
|
||||
unsigned amount = m_context.stackHeight() - _toHeight;
|
||||
popStackSlots(amount);
|
||||
m_context.appendJumpTo(_jumpTo);
|
||||
m_context.adjustStackOffset(amount);
|
||||
m_context.adjustStackOffset(static_cast<int>(amount));
|
||||
}
|
||||
|
||||
unsigned CompilerUtils::sizeOnStack(vector<Type const*> const& _variableTypes)
|
||||
@@ -1436,7 +1436,7 @@ unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCallda
|
||||
{
|
||||
bool leftAligned = _type.category() == Type::Category::FixedBytes;
|
||||
// add leading or trailing zeros by dividing/multiplying depending on alignment
|
||||
int shiftFactor = (32 - numBytes) * 8;
|
||||
unsigned shiftFactor = (32 - numBytes) * 8;
|
||||
rightShiftNumberOnStack(shiftFactor);
|
||||
if (leftAligned)
|
||||
{
|
||||
|
||||
@@ -185,7 +185,7 @@ size_t ContractCompiler::packIntoContractCreator(ContractDefinition const& _cont
|
||||
CompilerContext::LocationSetter locationSetter(m_context, _contract);
|
||||
m_context << deployRoutine;
|
||||
|
||||
solAssert(m_context.runtimeSub() != size_t(-1), "Runtime sub not registered");
|
||||
solAssert(m_context.runtimeSub() != numeric_limits<size_t>::max(), "Runtime sub not registered");
|
||||
|
||||
ContractType contractType(_contract);
|
||||
auto const& immutables = contractType.immutableVariables();
|
||||
@@ -221,7 +221,7 @@ size_t ContractCompiler::deployLibrary(ContractDefinition const& _contract)
|
||||
|
||||
CompilerContext::LocationSetter locationSetter(m_context, _contract);
|
||||
|
||||
solAssert(m_context.runtimeSub() != size_t(-1), "Runtime sub not registered");
|
||||
solAssert(m_context.runtimeSub() != numeric_limits<size_t>::max(), "Runtime sub not registered");
|
||||
m_context.pushSubroutineSize(m_context.runtimeSub());
|
||||
m_context.pushSubroutineOffset(m_context.runtimeSub());
|
||||
// This code replaces the address added by appendDeployTimeAddress().
|
||||
@@ -349,11 +349,11 @@ void ContractCompiler::appendInternalSelector(
|
||||
m_context << dupInstruction(1) << u256(FixedHash<4>::Arith(pivot)) << Instruction::GT;
|
||||
evmasm::AssemblyItem lessTag{m_context.appendConditionalJump()};
|
||||
// Here, we have funid >= pivot
|
||||
vector<FixedHash<4>> larger{_ids.begin() + pivotIndex, _ids.end()};
|
||||
vector<FixedHash<4>> larger{_ids.begin() + static_cast<ptrdiff_t>(pivotIndex), _ids.end()};
|
||||
appendInternalSelector(_entryPoints, larger, _notFoundTag, _runs);
|
||||
m_context << lessTag;
|
||||
// Here, we have funid < pivot
|
||||
vector<FixedHash<4>> smaller{_ids.begin(), _ids.begin() + pivotIndex};
|
||||
vector<FixedHash<4>> smaller{_ids.begin(), _ids.begin() + static_cast<ptrdiff_t>(pivotIndex)};
|
||||
appendInternalSelector(_entryPoints, smaller, _notFoundTag, _runs);
|
||||
}
|
||||
else
|
||||
@@ -512,8 +512,8 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac
|
||||
m_context << returnTag;
|
||||
// Return tag and input parameters get consumed.
|
||||
m_context.adjustStackOffset(
|
||||
CompilerUtils(m_context).sizeOnStack(functionType->returnParameterTypes()) -
|
||||
CompilerUtils(m_context).sizeOnStack(functionType->parameterTypes()) -
|
||||
static_cast<int>(CompilerUtils::sizeOnStack(functionType->returnParameterTypes())) -
|
||||
static_cast<int>(CompilerUtils::sizeOnStack(functionType->parameterTypes())) -
|
||||
1
|
||||
);
|
||||
// Consumes the return parameters.
|
||||
@@ -589,7 +589,7 @@ bool ContractCompiler::visit(FunctionDefinition const& _function)
|
||||
unsigned parametersSize = CompilerUtils::sizeOnStack(_function.parameters());
|
||||
if (!_function.isConstructor())
|
||||
// adding 1 for return address.
|
||||
m_context.adjustStackOffset(parametersSize + 1);
|
||||
m_context.adjustStackOffset(static_cast<int>(parametersSize) + 1);
|
||||
for (ASTPointer<VariableDeclaration> const& variable: _function.parameters())
|
||||
{
|
||||
m_context.addVariable(*variable, parametersSize);
|
||||
@@ -609,7 +609,7 @@ bool ContractCompiler::visit(FunctionDefinition const& _function)
|
||||
m_breakTags.clear();
|
||||
m_continueTags.clear();
|
||||
m_currentFunction = &_function;
|
||||
m_modifierDepth = -1;
|
||||
m_modifierDepth = numeric_limits<unsigned>::max();
|
||||
m_scopeStackHeight.clear();
|
||||
m_context.setModifierDepth(0);
|
||||
|
||||
@@ -627,10 +627,10 @@ bool ContractCompiler::visit(FunctionDefinition const& _function)
|
||||
unsigned const c_returnValuesSize = CompilerUtils::sizeOnStack(_function.returnParameters());
|
||||
|
||||
vector<int> stackLayout;
|
||||
stackLayout.push_back(c_returnValuesSize); // target of return address
|
||||
stackLayout.push_back(static_cast<int>(c_returnValuesSize)); // target of return address
|
||||
stackLayout += vector<int>(c_argumentsSize, -1); // discard all arguments
|
||||
for (unsigned i = 0; i < c_returnValuesSize; ++i)
|
||||
stackLayout.push_back(i);
|
||||
for (size_t i = 0; i < c_returnValuesSize; ++i)
|
||||
stackLayout.push_back(static_cast<int>(i));
|
||||
|
||||
if (stackLayout.size() > 17)
|
||||
BOOST_THROW_EXCEPTION(
|
||||
@@ -638,7 +638,7 @@ bool ContractCompiler::visit(FunctionDefinition const& _function)
|
||||
errinfo_sourceLocation(_function.location()) <<
|
||||
errinfo_comment("Stack too deep, try removing local variables.")
|
||||
);
|
||||
while (stackLayout.back() != int(stackLayout.size() - 1))
|
||||
while (stackLayout.back() != static_cast<int>(stackLayout.size() - 1))
|
||||
if (stackLayout.back() < 0)
|
||||
{
|
||||
m_context << Instruction::POP;
|
||||
@@ -646,11 +646,11 @@ bool ContractCompiler::visit(FunctionDefinition const& _function)
|
||||
}
|
||||
else
|
||||
{
|
||||
m_context << swapInstruction(stackLayout.size() - stackLayout.back() - 1);
|
||||
swap(stackLayout[stackLayout.back()], stackLayout.back());
|
||||
m_context << swapInstruction(stackLayout.size() - static_cast<size_t>(stackLayout.back()) - 1);
|
||||
swap(stackLayout[static_cast<size_t>(stackLayout.back())], stackLayout.back());
|
||||
}
|
||||
for (int i = 0; i < int(stackLayout.size()); ++i)
|
||||
if (stackLayout[i] != i)
|
||||
for (size_t i = 0; i < stackLayout.size(); ++i)
|
||||
if (stackLayout[i] != static_cast<int>(i))
|
||||
solAssert(false, "Invalid stack layout on cleanup.");
|
||||
|
||||
for (ASTPointer<VariableDeclaration> const& variable: _function.parameters() + _function.returnParameters())
|
||||
@@ -677,7 +677,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
|
||||
{
|
||||
auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier);
|
||||
if (ref == _inlineAssembly.annotation().externalReferences.end())
|
||||
return size_t(-1);
|
||||
return numeric_limits<size_t>::max();
|
||||
return ref->second.valueSize;
|
||||
};
|
||||
identifierAccess.generateCode = [&](yul::Identifier const& _identifier, yul::IdentifierContext _context, yul::AbstractAssembly& _assembly)
|
||||
@@ -696,7 +696,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
|
||||
functionDef = &functionDef->resolveVirtual(m_context.mostDerivedContract());
|
||||
auto functionEntryLabel = m_context.functionEntryLabel(*functionDef).pushTag();
|
||||
solAssert(functionEntryLabel.data() <= std::numeric_limits<size_t>::max(), "");
|
||||
_assembly.appendLabelReference(size_t(functionEntryLabel.data()));
|
||||
_assembly.appendLabelReference(static_cast<size_t>(functionEntryLabel.data()));
|
||||
// If there is a runtime context, we have to merge both labels into the same
|
||||
// stack slot in case we store it in storage.
|
||||
if (CompilerContext* rtc = m_context.runtimeContext())
|
||||
@@ -705,7 +705,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
|
||||
_assembly.appendInstruction(Instruction::MUL);
|
||||
auto runtimeEntryLabel = rtc->functionEntryLabel(*functionDef).toSubAssemblyTag(m_context.runtimeSub());
|
||||
solAssert(runtimeEntryLabel.data() <= std::numeric_limits<size_t>::max(), "");
|
||||
_assembly.appendLabelReference(size_t(runtimeEntryLabel.data()));
|
||||
_assembly.appendLabelReference(static_cast<size_t>(runtimeEntryLabel.data()));
|
||||
_assembly.appendInstruction(Instruction::OR);
|
||||
}
|
||||
}
|
||||
@@ -772,7 +772,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
|
||||
}
|
||||
else if (m_context.isLocalVariable(decl))
|
||||
{
|
||||
int stackDiff = _assembly.stackHeight() - m_context.baseStackOffsetOfVariable(*variable);
|
||||
unsigned stackDiff = static_cast<unsigned>(_assembly.stackHeight()) - m_context.baseStackOffsetOfVariable(*variable);
|
||||
if (ref->second.isSlot || ref->second.isOffset)
|
||||
{
|
||||
solAssert(variable->type()->dataStoredIn(DataLocation::Storage), "");
|
||||
@@ -816,7 +816,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
|
||||
}
|
||||
else
|
||||
solAssert(false, "Invalid declaration type.");
|
||||
solAssert(_assembly.stackHeight() - depositBefore == int(ref->second.valueSize), "");
|
||||
solAssert(_assembly.stackHeight() - depositBefore == static_cast<int>(ref->second.valueSize), "");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -828,7 +828,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
|
||||
"Can only assign to stack variables in inline assembly."
|
||||
);
|
||||
solAssert(variable->type()->sizeOnStack() == 1, "");
|
||||
int stackDiff = _assembly.stackHeight() - m_context.baseStackOffsetOfVariable(*variable) - 1;
|
||||
unsigned stackDiff = static_cast<unsigned>(_assembly.stackHeight()) - m_context.baseStackOffsetOfVariable(*variable) - 1;
|
||||
if (stackDiff > 16 || stackDiff < 1)
|
||||
BOOST_THROW_EXCEPTION(
|
||||
CompilerError() <<
|
||||
@@ -875,7 +875,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
|
||||
false,
|
||||
m_optimiserSettings.optimizeStackAllocation
|
||||
);
|
||||
m_context.setStackOffset(startStackHeight);
|
||||
m_context.setStackOffset(static_cast<int>(startStackHeight));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -914,7 +914,7 @@ bool ContractCompiler::visit(TryStatement const& _tryStatement)
|
||||
solAssert(params[i] && exprTypes[i] && *params[i]->annotation().type == *exprTypes[i], "");
|
||||
}
|
||||
else
|
||||
CompilerUtils(m_context).popStackSlots(returnSize);
|
||||
CompilerUtils(m_context).popStackSlots(static_cast<size_t>(returnSize));
|
||||
|
||||
_tryStatement.clauses().front()->accept(*this);
|
||||
}
|
||||
@@ -937,7 +937,7 @@ void ContractCompiler::handleCatch(vector<ASTPointer<TryCatchClause>> const& _ca
|
||||
else
|
||||
solAssert(false, "");
|
||||
|
||||
solAssert(_catchClauses.size() == size_t(1 + (structured ? 1 : 0) + (fallback ? 1 : 0)), "");
|
||||
solAssert(_catchClauses.size() == 1ul + (structured ? 1 : 0) + (fallback ? 1 : 0), "");
|
||||
|
||||
evmasm::AssemblyItem endTag = m_context.newTag();
|
||||
evmasm::AssemblyItem fallbackTag = m_context.newTag();
|
||||
|
||||
@@ -100,7 +100,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
|
||||
if (_varDecl.immutable())
|
||||
solAssert(paramTypes.empty(), "");
|
||||
|
||||
m_context.adjustStackOffset(1 + CompilerUtils::sizeOnStack(paramTypes));
|
||||
m_context.adjustStackOffset(static_cast<int>(1 + CompilerUtils::sizeOnStack(paramTypes)));
|
||||
|
||||
if (!_varDecl.immutable())
|
||||
{
|
||||
@@ -242,7 +242,7 @@ bool ExpressionCompiler::visit(Conditional const& _condition)
|
||||
acceptAndConvert(_condition.falseExpression(), *_condition.annotation().type);
|
||||
evmasm::AssemblyItem endTag = m_context.appendJumpToNew();
|
||||
m_context << trueTag;
|
||||
int offset = _condition.annotation().type->sizeOnStack();
|
||||
int offset = static_cast<int>(_condition.annotation().type->sizeOnStack());
|
||||
m_context.adjustStackOffset(-offset);
|
||||
acceptAndConvert(_condition.trueExpression(), *_condition.annotation().type);
|
||||
m_context << endTag;
|
||||
@@ -619,7 +619,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
|
||||
unsigned returnParametersSize = CompilerUtils::sizeOnStack(function.returnParameterTypes());
|
||||
// callee adds return parameters, but removes arguments and return label
|
||||
m_context.adjustStackOffset(returnParametersSize - parameterSize - 1);
|
||||
m_context.adjustStackOffset(static_cast<int>(returnParametersSize - parameterSize) - 1);
|
||||
break;
|
||||
}
|
||||
case FunctionType::Kind::BareCall:
|
||||
@@ -705,7 +705,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
acceptAndConvert(*arguments.front(), *TypeProvider::uint256(), true);
|
||||
// Note that function is not the original function, but the ".gas" function.
|
||||
// Its values of gasSet and valueSet is equal to the original function's though.
|
||||
unsigned stackDepth = (function.gasSet() ? 1 : 0) + (function.valueSet() ? 1 : 0);
|
||||
unsigned stackDepth = (function.gasSet() ? 1u : 0u) + (function.valueSet() ? 1u : 0u);
|
||||
if (stackDepth > 0)
|
||||
m_context << swapInstruction(stackDepth);
|
||||
if (function.gasSet())
|
||||
@@ -814,7 +814,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
case FunctionType::Kind::Log3:
|
||||
case FunctionType::Kind::Log4:
|
||||
{
|
||||
unsigned logNumber = int(function.kind()) - int(FunctionType::Kind::Log0);
|
||||
unsigned logNumber = static_cast<unsigned>(function.kind()) - static_cast<unsigned>(FunctionType::Kind::Log0);
|
||||
for (unsigned arg = logNumber; arg > 0; --arg)
|
||||
acceptAndConvert(*arguments[arg], *function.parameterTypes()[arg], true);
|
||||
arguments.front()->accept(*this);
|
||||
@@ -1088,7 +1088,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
{
|
||||
utils().revertWithStringData(*arguments.at(1)->annotation().type);
|
||||
// Here, the argument is consumed, but in the other branch, it is still there.
|
||||
m_context.adjustStackOffset(arguments.at(1)->annotation().type->sizeOnStack());
|
||||
m_context.adjustStackOffset(static_cast<int>(arguments.at(1)->annotation().type->sizeOnStack()));
|
||||
}
|
||||
else
|
||||
m_context.appendRevert();
|
||||
@@ -1271,9 +1271,9 @@ bool ExpressionCompiler::visit(FunctionCallOptions const& _functionCallOptions)
|
||||
acceptAndConvert(*_functionCallOptions.options()[i], *requiredType);
|
||||
|
||||
solAssert(!contains(presentOptions, newOption), "");
|
||||
size_t insertPos = presentOptions.end() - lower_bound(presentOptions.begin(), presentOptions.end(), newOption);
|
||||
ptrdiff_t insertPos = presentOptions.end() - lower_bound(presentOptions.begin(), presentOptions.end(), newOption);
|
||||
|
||||
utils().moveIntoStack(insertPos, 1);
|
||||
utils().moveIntoStack(static_cast<size_t>(insertPos), 1);
|
||||
presentOptions.insert(presentOptions.end() - insertPos, newOption);
|
||||
}
|
||||
|
||||
@@ -2190,7 +2190,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
||||
// contract address
|
||||
|
||||
unsigned selfSize = _functionType.bound() ? _functionType.selfType()->sizeOnStack() : 0;
|
||||
unsigned gasValueSize = (_functionType.gasSet() ? 1 : 0) + (_functionType.valueSet() ? 1 : 0);
|
||||
unsigned gasValueSize = (_functionType.gasSet() ? 1u : 0u) + (_functionType.valueSet() ? 1u : 0u);
|
||||
unsigned contractStackPos = m_context.currentToBaseStackOffset(1 + gasValueSize + selfSize + (_functionType.isBareCall() ? 0 : 1));
|
||||
unsigned gasStackPos = m_context.currentToBaseStackOffset(gasValueSize);
|
||||
unsigned valueStackPos = m_context.currentToBaseStackOffset(1);
|
||||
@@ -2361,7 +2361,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
||||
m_context << Instruction::CALL;
|
||||
|
||||
unsigned remainsSize =
|
||||
2 + // contract address, input_memory_end
|
||||
2u + // contract address, input_memory_end
|
||||
(_functionType.valueSet() ? 1 : 0) +
|
||||
(_functionType.gasSet() ? 1 : 0) +
|
||||
(!_functionType.isBareCall() ? 1 : 0);
|
||||
|
||||
@@ -1652,8 +1652,7 @@ string YulUtilFunctions::allocateAndInitializeMemoryStructFunction(StructType co
|
||||
return m_functionCollector.createFunction(functionName, [&]() {
|
||||
Whiskers templ(R"(
|
||||
function <functionName>() -> memPtr {
|
||||
let allocSize := <allocSize>()
|
||||
memPtr := <alloc>(allocSize)
|
||||
memPtr := <alloc>(<allocSize>)
|
||||
let offset := memPtr
|
||||
<#member>
|
||||
mstore(offset, <zeroValue>())
|
||||
|
||||
@@ -636,7 +636,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
});
|
||||
|
||||
solAssert(it != callArgumentNames.cend(), "");
|
||||
arguments.push_back(callArguments[std::distance(callArgumentNames.begin(), it)]);
|
||||
arguments.push_back(callArguments[static_cast<size_t>(std::distance(callArgumentNames.begin(), it))]);
|
||||
}
|
||||
|
||||
auto memberAccess = dynamic_cast<MemberAccess const*>(&_functionCall.expression());
|
||||
@@ -1092,7 +1092,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
case FunctionType::Kind::Log3:
|
||||
case FunctionType::Kind::Log4:
|
||||
{
|
||||
unsigned logNumber = int(functionType->kind()) - int(FunctionType::Kind::Log0);
|
||||
unsigned logNumber = static_cast<unsigned>(functionType->kind()) - static_cast<unsigned>(FunctionType::Kind::Log0);
|
||||
solAssert(arguments.size() == logNumber + 1, "");
|
||||
ABIFunctions abi(m_context.evmVersion(), m_context.revertStrings(), m_context.functionCollector());
|
||||
string indexedArgs;
|
||||
@@ -1477,7 +1477,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
||||
pair<u256, unsigned> const& offsets = structType.storageOffsetsOfMember(member);
|
||||
string slot = m_context.newYulVariable();
|
||||
m_code << "let " << slot << " := " <<
|
||||
("add(" + expression.name() + ", " + offsets.first.str() + ")\n");
|
||||
("add(" + expression.part("slot").name() + ", " + offsets.first.str() + ")\n");
|
||||
setLValue(_memberAccess, IRLValue{
|
||||
type(_memberAccess),
|
||||
IRLValue::Storage{slot, offsets.second}
|
||||
@@ -1497,7 +1497,25 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
||||
}
|
||||
case DataLocation::CallData:
|
||||
{
|
||||
solUnimplementedAssert(false, "");
|
||||
string baseRef = expression.part("offset").name();
|
||||
string offset = m_context.newYulVariable();
|
||||
m_code << "let " << offset << " := " << "add(" << baseRef << ", " << to_string(structType.calldataOffsetOfMember(member)) << ")\n";
|
||||
if (_memberAccess.annotation().type->isDynamicallyEncoded())
|
||||
define(_memberAccess) <<
|
||||
m_utils.accessCalldataTailFunction(*_memberAccess.annotation().type) <<
|
||||
"(" <<
|
||||
baseRef <<
|
||||
", " <<
|
||||
offset <<
|
||||
")" <<
|
||||
std::endl;
|
||||
else
|
||||
define(_memberAccess) <<
|
||||
m_utils.readFromCalldata(*_memberAccess.annotation().type) <<
|
||||
"(" <<
|
||||
offset <<
|
||||
")" <<
|
||||
std::endl;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -104,7 +104,7 @@ void CHC::analyze(SourceUnit const& _source)
|
||||
for (auto const* assertion: assertions)
|
||||
{
|
||||
createErrorBlock();
|
||||
connectBlocks(target.value, error(), target.constraints && (target.errorId == assertion->id()));
|
||||
connectBlocks(target.value, error(), target.constraints && (target.errorId == static_cast<size_t>(assertion->id())));
|
||||
auto [result, model] = query(error(), assertion->location());
|
||||
// This should be fine but it's a bug in the old compiler
|
||||
(void)model;
|
||||
@@ -116,7 +116,7 @@ void CHC::analyze(SourceUnit const& _source)
|
||||
{
|
||||
solAssert(dynamic_cast<FunctionCall const*>(scope), "");
|
||||
createErrorBlock();
|
||||
connectBlocks(target.value, error(), target.constraints && (target.errorId == scope->id()));
|
||||
connectBlocks(target.value, error(), target.constraints && (target.errorId == static_cast<size_t>(scope->id())));
|
||||
auto [result, model] = query(error(), scope->location());
|
||||
// This should be fine but it's a bug in the old compiler
|
||||
(void)model;
|
||||
@@ -533,7 +533,9 @@ void CHC::visitAssert(FunctionCall const& _funCall)
|
||||
connectBlocks(
|
||||
m_currentBlock,
|
||||
m_currentFunction->isConstructor() ? summary(*m_currentContract) : summary(*m_currentFunction),
|
||||
currentPathConditions() && !m_context.expression(*args.front())->currentValue() && (m_error.currentValue() == _funCall.id())
|
||||
currentPathConditions() && !m_context.expression(*args.front())->currentValue() && (
|
||||
m_error.currentValue() == static_cast<size_t>(_funCall.id())
|
||||
)
|
||||
);
|
||||
|
||||
m_context.addAssertion(m_error.currentValue() == previousError);
|
||||
@@ -601,7 +603,7 @@ void CHC::makeArrayPopVerificationTarget(FunctionCall const& _arrayPop)
|
||||
connectBlocks(
|
||||
m_currentBlock,
|
||||
m_currentFunction->isConstructor() ? summary(*m_currentContract) : summary(*m_currentFunction),
|
||||
currentPathConditions() && symbArray->length() <= 0 && m_error.currentValue() == _arrayPop.id()
|
||||
currentPathConditions() && symbArray->length() <= 0 && m_error.currentValue() == static_cast<size_t>(_arrayPop.id())
|
||||
);
|
||||
|
||||
m_context.addAssertion(m_error.currentValue() == previousError);
|
||||
@@ -891,13 +893,13 @@ vector<smtutil::Expression> CHC::initialStateVariables()
|
||||
return stateVariablesAtIndex(0);
|
||||
}
|
||||
|
||||
vector<smtutil::Expression> CHC::stateVariablesAtIndex(int _index)
|
||||
vector<smtutil::Expression> CHC::stateVariablesAtIndex(unsigned _index)
|
||||
{
|
||||
solAssert(m_currentContract, "");
|
||||
return applyMap(m_stateVariables, [&](auto _var) { return valueAtIndex(*_var, _index); });
|
||||
}
|
||||
|
||||
vector<smtutil::Expression> CHC::stateVariablesAtIndex(int _index, ContractDefinition const& _contract)
|
||||
vector<smtutil::Expression> CHC::stateVariablesAtIndex(unsigned _index, ContractDefinition const& _contract)
|
||||
{
|
||||
return applyMap(
|
||||
stateVariablesIncludingInheritedAndPrivate(_contract),
|
||||
|
||||
@@ -149,8 +149,8 @@ private:
|
||||
/// @returns the symbolic values of the state variables at the beginning
|
||||
/// of the current transaction.
|
||||
std::vector<smtutil::Expression> initialStateVariables();
|
||||
std::vector<smtutil::Expression> stateVariablesAtIndex(int _index);
|
||||
std::vector<smtutil::Expression> stateVariablesAtIndex(int _index, ContractDefinition const& _contract);
|
||||
std::vector<smtutil::Expression> stateVariablesAtIndex(unsigned _index);
|
||||
std::vector<smtutil::Expression> stateVariablesAtIndex(unsigned _index, ContractDefinition const& _contract);
|
||||
/// @returns the current symbolic values of the current state variables.
|
||||
std::vector<smtutil::Expression> currentStateVariables();
|
||||
|
||||
|
||||
@@ -32,12 +32,23 @@ EncodingContext::EncodingContext():
|
||||
void EncodingContext::reset()
|
||||
{
|
||||
resetAllVariables();
|
||||
resetSlackId();
|
||||
m_expressions.clear();
|
||||
m_globalContext.clear();
|
||||
m_state.reset();
|
||||
m_assertions.clear();
|
||||
}
|
||||
|
||||
void EncodingContext::resetSlackId()
|
||||
{
|
||||
m_nextSlackId = 0;
|
||||
}
|
||||
|
||||
unsigned EncodingContext::newSlackId()
|
||||
{
|
||||
return m_nextSlackId++;
|
||||
}
|
||||
|
||||
void EncodingContext::clear()
|
||||
{
|
||||
m_variables.clear();
|
||||
|
||||
@@ -40,6 +40,10 @@ public:
|
||||
/// alive because of state variables and inlined function calls.
|
||||
/// To be used in the beginning of a root function visit.
|
||||
void reset();
|
||||
/// Resets the fresh id for slack variables.
|
||||
void resetSlackId();
|
||||
/// Returns the current fresh slack id and increments it.
|
||||
unsigned newSlackId();
|
||||
/// Clears the entire context, erasing everything.
|
||||
/// To be used before a model checking engine starts.
|
||||
void clear();
|
||||
@@ -168,6 +172,9 @@ private:
|
||||
/// Whether to conjoin assertions in the assertion stack.
|
||||
bool m_accumulateAssertions = true;
|
||||
//@}
|
||||
|
||||
/// Fresh ids for slack variables to be created deterministically.
|
||||
unsigned m_nextSlackId = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -154,15 +154,16 @@ void SMTEncoder::visitFunctionOrModifier()
|
||||
++m_modifierDepthStack.back();
|
||||
FunctionDefinition const& function = dynamic_cast<FunctionDefinition const&>(*m_callStack.back().first);
|
||||
|
||||
if (m_modifierDepthStack.back() == int(function.modifiers().size()))
|
||||
if (m_modifierDepthStack.back() == static_cast<int>(function.modifiers().size()))
|
||||
{
|
||||
if (function.isImplemented())
|
||||
function.body().accept(*this);
|
||||
}
|
||||
else
|
||||
{
|
||||
solAssert(m_modifierDepthStack.back() < int(function.modifiers().size()), "");
|
||||
ASTPointer<ModifierInvocation> const& modifierInvocation = function.modifiers()[m_modifierDepthStack.back()];
|
||||
solAssert(m_modifierDepthStack.back() < static_cast<int>(function.modifiers().size()), "");
|
||||
ASTPointer<ModifierInvocation> const& modifierInvocation =
|
||||
function.modifiers()[static_cast<size_t>(m_modifierDepthStack.back())];
|
||||
solAssert(modifierInvocation, "");
|
||||
auto refDecl = modifierInvocation->name()->annotation().referencedDeclaration;
|
||||
if (dynamic_cast<ContractDefinition const*>(refDecl))
|
||||
@@ -1203,7 +1204,7 @@ pair<smtutil::Expression, smtutil::Expression> SMTEncoder::arithmeticOperation(
|
||||
smtutil::Expression const& _left,
|
||||
smtutil::Expression const& _right,
|
||||
TypePointer const& _commonType,
|
||||
Expression const&
|
||||
Expression const& _operation
|
||||
)
|
||||
{
|
||||
static set<Token> validOperators{
|
||||
@@ -1226,39 +1227,66 @@ pair<smtutil::Expression, smtutil::Expression> SMTEncoder::arithmeticOperation(
|
||||
else
|
||||
intType = TypeProvider::uint256();
|
||||
|
||||
smtutil::Expression valueNoMod(
|
||||
_op == Token::Add ? _left + _right :
|
||||
_op == Token::Sub ? _left - _right :
|
||||
_op == Token::Div ? division(_left, _right, *intType) :
|
||||
_op == Token::Mul ? _left * _right :
|
||||
/*_op == Token::Mod*/ _left % _right
|
||||
);
|
||||
auto valueUnbounded = [&]() -> smtutil::Expression {
|
||||
switch (_op)
|
||||
{
|
||||
case Token::Add: return _left + _right;
|
||||
case Token::Sub: return _left - _right;
|
||||
case Token::Mul: return _left * _right;
|
||||
case Token::Div: return division(_left, _right, *intType);
|
||||
case Token::Mod: return _left % _right;
|
||||
default: solAssert(false, "");
|
||||
}
|
||||
}();
|
||||
|
||||
if (_op == Token::Div || _op == Token::Mod)
|
||||
{
|
||||
m_context.addAssertion(_right != 0);
|
||||
|
||||
// mod and unsigned division never underflow/overflow
|
||||
if (_op == Token::Mod || !intType->isSigned())
|
||||
return {valueUnbounded, valueUnbounded};
|
||||
|
||||
// The only case where division overflows is
|
||||
// - type is signed
|
||||
// - LHS is type.min
|
||||
// - RHS is -1
|
||||
// the result is then -(type.min), which wraps back to type.min
|
||||
smtutil::Expression maxLeft = _left == smt::minValue(*intType);
|
||||
smtutil::Expression minusOneRight = _right == -1;
|
||||
smtutil::Expression wrap = smtutil::Expression::ite(maxLeft && minusOneRight, smt::minValue(*intType), valueUnbounded);
|
||||
return {wrap, valueUnbounded};
|
||||
}
|
||||
|
||||
auto symbMin = smt::minValue(*intType);
|
||||
auto symbMax = smt::maxValue(*intType);
|
||||
|
||||
smtutil::Expression intValueRange = (0 - symbMin) + symbMax + 1;
|
||||
string suffix = to_string(_operation.id()) + "_" + to_string(m_context.newSlackId());
|
||||
smt::SymbolicIntVariable k(intType, intType, "k_" + suffix, m_context);
|
||||
smt::SymbolicIntVariable m(intType, intType, "m_" + suffix, m_context);
|
||||
|
||||
// To wrap around valueUnbounded in case of overflow or underflow, we replace it with a k, given:
|
||||
// 1. k + m * intValueRange = valueUnbounded
|
||||
// 2. k is in range of the desired integer type
|
||||
auto wrap = k.currentValue();
|
||||
m_context.addAssertion(valueUnbounded == (k.currentValue() + intValueRange * m.currentValue()));
|
||||
m_context.addAssertion(k.currentValue() >= symbMin);
|
||||
m_context.addAssertion(k.currentValue() <= symbMax);
|
||||
|
||||
// TODO this could be refined:
|
||||
// for unsigned types it's enough to check only the upper bound.
|
||||
auto value = smtutil::Expression::ite(
|
||||
valueNoMod > symbMax,
|
||||
valueNoMod % intValueRange,
|
||||
valueUnbounded > symbMax,
|
||||
wrap,
|
||||
smtutil::Expression::ite(
|
||||
valueNoMod < symbMin,
|
||||
valueNoMod % intValueRange,
|
||||
valueNoMod
|
||||
valueUnbounded < symbMin,
|
||||
wrap,
|
||||
valueUnbounded
|
||||
)
|
||||
);
|
||||
|
||||
if (intType->isSigned())
|
||||
value = smtutil::Expression::ite(
|
||||
value > symbMax,
|
||||
value - intValueRange,
|
||||
value
|
||||
);
|
||||
|
||||
return {value, valueNoMod};
|
||||
return {value, valueUnbounded};
|
||||
}
|
||||
|
||||
void SMTEncoder::compareOperation(BinaryOperation const& _op)
|
||||
@@ -1679,8 +1707,8 @@ void SMTEncoder::mergeVariables(set<VariableDeclaration const*> const& _variable
|
||||
for (auto const* decl: sortedVars)
|
||||
{
|
||||
solAssert(_indicesEndTrue.count(decl) && _indicesEndFalse.count(decl), "");
|
||||
int trueIndex = _indicesEndTrue.at(decl);
|
||||
int falseIndex = _indicesEndFalse.at(decl);
|
||||
auto trueIndex = static_cast<unsigned>(_indicesEndTrue.at(decl));
|
||||
auto falseIndex = static_cast<unsigned>(_indicesEndFalse.at(decl));
|
||||
solAssert(trueIndex != falseIndex, "");
|
||||
m_context.addAssertion(m_context.newValue(*decl) == smtutil::Expression::ite(
|
||||
_condition,
|
||||
@@ -1696,7 +1724,7 @@ smtutil::Expression SMTEncoder::currentValue(VariableDeclaration const& _decl)
|
||||
return m_context.variable(_decl)->currentValue();
|
||||
}
|
||||
|
||||
smtutil::Expression SMTEncoder::valueAtIndex(VariableDeclaration const& _decl, int _index)
|
||||
smtutil::Expression SMTEncoder::valueAtIndex(VariableDeclaration const& _decl, unsigned _index)
|
||||
{
|
||||
solAssert(m_context.knownVariable(_decl), "");
|
||||
return m_context.variable(_decl)->valueAtIndex(_index);
|
||||
@@ -1819,7 +1847,7 @@ SMTEncoder::VariableIndices SMTEncoder::copyVariableIndices()
|
||||
void SMTEncoder::resetVariableIndices(VariableIndices const& _indices)
|
||||
{
|
||||
for (auto const& var: _indices)
|
||||
m_context.variable(*var.first)->setIndex(var.second);
|
||||
m_context.variable(*var.first)->setIndex(static_cast<unsigned>(var.second));
|
||||
}
|
||||
|
||||
void SMTEncoder::clearIndices(ContractDefinition const* _contract, FunctionDefinition const* _function)
|
||||
|
||||
@@ -201,7 +201,7 @@ protected:
|
||||
smtutil::Expression currentValue(VariableDeclaration const& _decl);
|
||||
/// @returns an expression denoting the value of the variable declared in @a _decl
|
||||
/// at the given index. Does not ensure that this index exists.
|
||||
smtutil::Expression valueAtIndex(VariableDeclaration const& _decl, int _index);
|
||||
smtutil::Expression valueAtIndex(VariableDeclaration const& _decl, unsigned _index);
|
||||
/// Returns the expression corresponding to the AST node.
|
||||
/// If _targetType is not null apply conversion.
|
||||
/// Throws if the expression does not exist.
|
||||
|
||||
@@ -66,12 +66,12 @@ string SymbolicVariable::currentName() const
|
||||
return uniqueSymbol(m_ssa->index());
|
||||
}
|
||||
|
||||
smtutil::Expression SymbolicVariable::valueAtIndex(int _index) const
|
||||
smtutil::Expression SymbolicVariable::valueAtIndex(unsigned _index) const
|
||||
{
|
||||
return m_context.newVariable(uniqueSymbol(_index), m_sort);
|
||||
}
|
||||
|
||||
string SymbolicVariable::nameAtIndex(int _index) const
|
||||
string SymbolicVariable::nameAtIndex(unsigned _index) const
|
||||
{
|
||||
return uniqueSymbol(_index);
|
||||
}
|
||||
@@ -170,12 +170,12 @@ smtutil::Expression SymbolicFunctionVariable::currentFunctionValue() const
|
||||
return m_declaration;
|
||||
}
|
||||
|
||||
smtutil::Expression SymbolicFunctionVariable::valueAtIndex(int _index) const
|
||||
smtutil::Expression SymbolicFunctionVariable::valueAtIndex(unsigned _index) const
|
||||
{
|
||||
return m_abstract.valueAtIndex(_index);
|
||||
}
|
||||
|
||||
smtutil::Expression SymbolicFunctionVariable::functionValueAtIndex(int _index) const
|
||||
smtutil::Expression SymbolicFunctionVariable::functionValueAtIndex(unsigned _index) const
|
||||
{
|
||||
return SymbolicVariable::valueAtIndex(_index);
|
||||
}
|
||||
@@ -304,7 +304,7 @@ smtutil::Expression SymbolicArrayVariable::currentValue(frontend::TypePointer co
|
||||
return m_pair.currentValue();
|
||||
}
|
||||
|
||||
smtutil::Expression SymbolicArrayVariable::valueAtIndex(int _index) const
|
||||
smtutil::Expression SymbolicArrayVariable::valueAtIndex(unsigned _index) const
|
||||
{
|
||||
return m_pair.valueAtIndex(_index);
|
||||
}
|
||||
|
||||
@@ -54,8 +54,8 @@ public:
|
||||
|
||||
virtual smtutil::Expression currentValue(frontend::TypePointer const& _targetType = TypePointer{}) const;
|
||||
std::string currentName() const;
|
||||
virtual smtutil::Expression valueAtIndex(int _index) const;
|
||||
virtual std::string nameAtIndex(int _index) const;
|
||||
virtual smtutil::Expression valueAtIndex(unsigned _index) const;
|
||||
virtual std::string nameAtIndex(unsigned _index) const;
|
||||
virtual smtutil::Expression resetIndex();
|
||||
virtual smtutil::Expression setIndex(unsigned _index);
|
||||
virtual smtutil::Expression increaseIndex();
|
||||
@@ -165,10 +165,10 @@ public:
|
||||
// Explicit request the function declaration.
|
||||
smtutil::Expression currentFunctionValue() const;
|
||||
|
||||
smtutil::Expression valueAtIndex(int _index) const override;
|
||||
smtutil::Expression valueAtIndex(unsigned _index) const override;
|
||||
|
||||
// Explicit request the function declaration.
|
||||
smtutil::Expression functionValueAtIndex(int _index) const;
|
||||
smtutil::Expression functionValueAtIndex(unsigned _index) const;
|
||||
|
||||
smtutil::Expression resetIndex() override;
|
||||
smtutil::Expression setIndex(unsigned _index) override;
|
||||
@@ -251,7 +251,7 @@ public:
|
||||
SymbolicArrayVariable(SymbolicArrayVariable&&) = default;
|
||||
|
||||
smtutil::Expression currentValue(frontend::TypePointer const& _targetType = TypePointer{}) const override;
|
||||
smtutil::Expression valueAtIndex(int _index) const override;
|
||||
smtutil::Expression valueAtIndex(unsigned _index) const override;
|
||||
smtutil::Expression resetIndex() override { SymbolicVariable::resetIndex(); return m_pair.resetIndex(); }
|
||||
smtutil::Expression setIndex(unsigned _index) override { SymbolicVariable::setIndex(_index); return m_pair.setIndex(_index); }
|
||||
smtutil::Expression increaseIndex() override { SymbolicVariable::increaseIndex(); return m_pair.increaseIndex(); }
|
||||
|
||||
@@ -982,7 +982,7 @@ string CompilerStack::applyRemapping(string const& _path, string const& _context
|
||||
bestMatchTarget = util::sanitizePath(redir.target);
|
||||
}
|
||||
string path = bestMatchTarget;
|
||||
path.append(_path.begin() + longestPrefix, _path.end());
|
||||
path.append(_path.begin() + static_cast<string::difference_type>(longestPrefix), _path.end());
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
@@ -54,8 +54,8 @@ GasEstimator::ASTGasConsumptionSelfAccumulated GasEstimator::structuralEstimatio
|
||||
{
|
||||
solAssert(!!block.startState, "");
|
||||
GasMeter meter(block.startState->copy(), m_evmVersion);
|
||||
auto const end = _items.begin() + block.end;
|
||||
for (auto iter = _items.begin() + block.begin; iter != end; ++iter)
|
||||
auto const end = _items.begin() + static_cast<ptrdiff_t>(block.end);
|
||||
for (auto iter = _items.begin() + static_cast<ptrdiff_t>(block.begin); iter != end; ++iter)
|
||||
particularCosts[iter->location()] += meter.estimateMax(*iter);
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,9 @@ Json::Value Natspec::userDocumentation(ContractDefinition const& _contractDef)
|
||||
Json::Value doc;
|
||||
Json::Value methods(Json::objectValue);
|
||||
|
||||
doc["version"] = Json::Value(c_natspecVersion);
|
||||
doc["kind"] = Json::Value("user");
|
||||
|
||||
auto constructorDefinition(_contractDef.constructor());
|
||||
if (constructorDefinition)
|
||||
{
|
||||
@@ -91,6 +94,9 @@ Json::Value Natspec::devDocumentation(ContractDefinition const& _contractDef)
|
||||
Json::Value doc;
|
||||
Json::Value methods(Json::objectValue);
|
||||
|
||||
doc["version"] = Json::Value(c_natspecVersion);
|
||||
doc["kind"] = Json::Value("dev");
|
||||
|
||||
auto author = extractDoc(_contractDef.annotation().docTags, "author");
|
||||
if (!author.empty())
|
||||
doc["author"] = author;
|
||||
|
||||
@@ -40,6 +40,8 @@ struct DocTag;
|
||||
class Natspec
|
||||
{
|
||||
public:
|
||||
static unsigned int constexpr c_natspecVersion = 1;
|
||||
|
||||
/// Get the User documentation of the contract
|
||||
/// @param _contractDef The contract definition
|
||||
/// @return A JSON representation of the contract's user documentation
|
||||
|
||||
@@ -111,7 +111,8 @@ Json::Value formatErrorWithException(
|
||||
bool const& _warning,
|
||||
string const& _type,
|
||||
string const& _component,
|
||||
string const& _message
|
||||
string const& _message,
|
||||
optional<ErrorId> _errorId = nullopt
|
||||
)
|
||||
{
|
||||
string message;
|
||||
@@ -122,7 +123,7 @@ Json::Value formatErrorWithException(
|
||||
else
|
||||
message = _message;
|
||||
|
||||
return formatError(
|
||||
Json::Value error = formatError(
|
||||
_warning,
|
||||
_type,
|
||||
_component,
|
||||
@@ -131,6 +132,11 @@ Json::Value formatErrorWithException(
|
||||
formatSourceLocation(boost::get_error_info<errinfo_sourceLocation>(_exception)),
|
||||
formatSecondarySourceLocation(boost::get_error_info<errinfo_secondarySourceLocation>(_exception))
|
||||
);
|
||||
|
||||
if (_errorId)
|
||||
error["errorCode"] = to_string(_errorId.value().error);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
map<string, set<string>> requestedContractNames(Json::Value const& _outputSelection)
|
||||
@@ -857,7 +863,8 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
|
||||
err.type() == Error::Type::Warning,
|
||||
err.typeName(),
|
||||
"general",
|
||||
""
|
||||
"",
|
||||
err.errorId()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ Json::Value StorageLayout::generate(VariableDeclaration const& _var, u256 const&
|
||||
TypePointer varType = _var.type();
|
||||
|
||||
varEntry["label"] = _var.name();
|
||||
varEntry["astId"] = int(_var.id());
|
||||
varEntry["astId"] = static_cast<int>(_var.id());
|
||||
varEntry["contract"] = m_contract->fullyQualifiedName();
|
||||
varEntry["slot"] = _slot.str();
|
||||
varEntry["offset"] = _offset;
|
||||
|
||||
Reference in New Issue
Block a user