mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge remote-tracking branch 'origin/develop' into breaking
This commit is contained in:
commit
69a028b49c
@ -531,7 +531,7 @@ jobs:
|
|||||||
xcode: "11.0.0"
|
xcode: "11.0.0"
|
||||||
environment:
|
environment:
|
||||||
TERM: xterm
|
TERM: xterm
|
||||||
CMAKE_BUILD_TYPE: Debug
|
CMAKE_BUILD_TYPE: Release
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
|
@ -30,7 +30,9 @@ Compiler Features:
|
|||||||
Bugfixes:
|
Bugfixes:
|
||||||
* Optimizer: Fixed a bug in BlockDeDuplicator.
|
* Optimizer: Fixed a bug in BlockDeDuplicator.
|
||||||
* Type Checker: Disallow assignments to storage variables of type ``mapping``.
|
* Type Checker: Disallow assignments to storage variables of type ``mapping``.
|
||||||
|
* NatSpec: DocString block is terminated when encountering an empty line.
|
||||||
|
* Scanner: Fix bug when two empty NatSpec comments lead to scanning past EOL.
|
||||||
|
* Code Generator: Trigger proper unimplemented errors on certain array copy operations.
|
||||||
|
|
||||||
### 0.6.8 (2020-05-14)
|
### 0.6.8 (2020-05-14)
|
||||||
|
|
||||||
|
@ -166,7 +166,7 @@ This section gives detailed instructions on how to update prior code for every b
|
|||||||
documentation so long as the notices are in the order they appear in the tuple return type.
|
documentation so long as the notices are in the order they appear in the tuple return type.
|
||||||
|
|
||||||
* Choose unique identifiers for variable declarations in inline assembly that do not conflict
|
* Choose unique identifiers for variable declarations in inline assembly that do not conflict
|
||||||
with declartions outside the inline assembly block.
|
with declarations outside the inline assembly block.
|
||||||
|
|
||||||
* Add ``virtual`` to every non-interface function you intend to override. Add ``virtual``
|
* Add ``virtual`` to every non-interface function you intend to override. Add ``virtual``
|
||||||
to all functions without implementation outside interfaces. For single inheritance, add
|
to all functions without implementation outside interfaces. For single inheritance, add
|
||||||
|
@ -435,10 +435,10 @@ map<u256, u256> Assembly::optimiseInternal(
|
|||||||
// This only modifies PushTags, we have to run again to actually remove code.
|
// This only modifies PushTags, we have to run again to actually remove code.
|
||||||
if (_settings.runDeduplicate)
|
if (_settings.runDeduplicate)
|
||||||
{
|
{
|
||||||
BlockDeduplicator dedup{m_items};
|
BlockDeduplicator deduplicator{m_items};
|
||||||
if (dedup.deduplicate())
|
if (deduplicator.deduplicate())
|
||||||
{
|
{
|
||||||
for (auto const& replacement: dedup.replacedTags())
|
for (auto const& replacement: deduplicator.replacedTags())
|
||||||
{
|
{
|
||||||
assertThrow(
|
assertThrow(
|
||||||
replacement.first <= size_t(-1) && replacement.second <= size_t(-1),
|
replacement.first <= size_t(-1) && replacement.second <= size_t(-1),
|
||||||
|
@ -267,10 +267,13 @@ bool Scanner::skipWhitespace()
|
|||||||
return sourcePos() != startPosition;
|
return sourcePos() != startPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scanner::skipWhitespaceExceptUnicodeLinebreak()
|
bool Scanner::skipWhitespaceExceptUnicodeLinebreak()
|
||||||
{
|
{
|
||||||
|
int const startPosition = sourcePos();
|
||||||
while (isWhiteSpace(m_char) && !isUnicodeLinebreak())
|
while (isWhiteSpace(m_char) && !isUnicodeLinebreak())
|
||||||
advance();
|
advance();
|
||||||
|
// Return whether or not we skipped any characters.
|
||||||
|
return sourcePos() != startPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
Token Scanner::skipSingleLineComment()
|
Token Scanner::skipSingleLineComment()
|
||||||
@ -321,7 +324,7 @@ int Scanner::scanSingleLineDocComment()
|
|||||||
{
|
{
|
||||||
// Check if next line is also a single-line comment.
|
// Check if next line is also a single-line comment.
|
||||||
// If any whitespaces were skipped, use source position before.
|
// If any whitespaces were skipped, use source position before.
|
||||||
if (!skipWhitespace())
|
if (!skipWhitespaceExceptUnicodeLinebreak())
|
||||||
endPosition = m_source->position();
|
endPosition = m_source->position();
|
||||||
|
|
||||||
if (!m_source->isPastEndOfInput(3) &&
|
if (!m_source->isPastEndOfInput(3) &&
|
||||||
@ -329,8 +332,10 @@ int Scanner::scanSingleLineDocComment()
|
|||||||
m_source->get(1) == '/' &&
|
m_source->get(1) == '/' &&
|
||||||
m_source->get(2) == '/')
|
m_source->get(2) == '/')
|
||||||
{
|
{
|
||||||
addCommentLiteralChar('\n');
|
|
||||||
m_char = m_source->advanceAndGet(3);
|
m_char = m_source->advanceAndGet(3);
|
||||||
|
if (atEndOfLine())
|
||||||
|
continue;
|
||||||
|
addCommentLiteralChar('\n');
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
break; // next line is not a documentation comment, we are done
|
break; // next line is not a documentation comment, we are done
|
||||||
@ -389,9 +394,11 @@ Token Scanner::scanMultiLineDocComment()
|
|||||||
}
|
}
|
||||||
else if (!m_source->isPastEndOfInput(1) && m_source->get(0) == '*' && m_source->get(1) != '/')
|
else if (!m_source->isPastEndOfInput(1) && m_source->get(0) == '*' && m_source->get(1) != '/')
|
||||||
{ // skip first '*' in subsequent lines
|
{ // skip first '*' in subsequent lines
|
||||||
|
m_char = m_source->advanceAndGet(1);
|
||||||
|
if (atEndOfLine()) // ignores empty lines
|
||||||
|
continue;
|
||||||
if (charsAdded)
|
if (charsAdded)
|
||||||
addCommentLiteralChar('\n');
|
addCommentLiteralChar('\n'); // corresponds to the end of previous line
|
||||||
m_char = m_source->advanceAndGet(2);
|
|
||||||
}
|
}
|
||||||
else if (!m_source->isPastEndOfInput(1) && m_source->get(0) == '*' && m_source->get(1) == '/')
|
else if (!m_source->isPastEndOfInput(1) && m_source->get(0) == '*' && m_source->get(1) == '/')
|
||||||
{ // if after newline the comment ends, don't insert the newline
|
{ // if after newline the comment ends, don't insert the newline
|
||||||
|
@ -214,7 +214,7 @@ private:
|
|||||||
/// Skips all whitespace and @returns true if something was skipped.
|
/// Skips all whitespace and @returns true if something was skipped.
|
||||||
bool skipWhitespace();
|
bool skipWhitespace();
|
||||||
/// Skips all whitespace that are neither '\r' nor '\n'.
|
/// Skips all whitespace that are neither '\r' nor '\n'.
|
||||||
void skipWhitespaceExceptUnicodeLinebreak();
|
bool skipWhitespaceExceptUnicodeLinebreak();
|
||||||
Token skipSingleLineComment();
|
Token skipSingleLineComment();
|
||||||
Token skipMultiLineComment();
|
Token skipMultiLineComment();
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include <liblangutil/SourceReferenceFormatterHuman.h>
|
#include <liblangutil/SourceReferenceFormatterHuman.h>
|
||||||
#include <liblangutil/Scanner.h>
|
#include <liblangutil/Scanner.h>
|
||||||
#include <liblangutil/Exceptions.h>
|
#include <liblangutil/Exceptions.h>
|
||||||
|
#include <libsolutil/UTF8.h>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
@ -103,12 +104,13 @@ void SourceReferenceFormatterHuman::printSourceLocation(SourceReference const& _
|
|||||||
m_stream << leftpad << ' ';
|
m_stream << leftpad << ' ';
|
||||||
frameColored() << '|';
|
frameColored() << '|';
|
||||||
m_stream << ' ';
|
m_stream << ' ';
|
||||||
|
|
||||||
for_each(
|
for_each(
|
||||||
_ref.text.cbegin(),
|
_ref.text.cbegin(),
|
||||||
_ref.text.cbegin() + _ref.startColumn,
|
_ref.text.cbegin() + numCodepoints(_ref.text.substr(0, _ref.startColumn)),
|
||||||
[this](char ch) { m_stream << (ch == '\t' ? '\t' : ' '); }
|
[this](char ch) { m_stream << (ch == '\t' ? '\t' : ' '); }
|
||||||
);
|
);
|
||||||
diagColored() << string(locationLength, '^');
|
diagColored() << string(numCodepoints(_ref.text.substr(_ref.startColumn, locationLength)), '^');
|
||||||
m_stream << '\n';
|
m_stream << '\n';
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -50,7 +50,8 @@ bool DeclarationTypeChecker::visit(ElementaryTypeName const& _typeName)
|
|||||||
_typeName.annotation().type = TypeProvider::address();
|
_typeName.annotation().type = TypeProvider::address();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
typeError(
|
m_errorReporter.typeError(
|
||||||
|
2311_error,
|
||||||
_typeName.location(),
|
_typeName.location(),
|
||||||
"Address types can only be payable or non-payable."
|
"Address types can only be payable or non-payable."
|
||||||
);
|
);
|
||||||
@ -102,7 +103,11 @@ bool DeclarationTypeChecker::visit(StructDefinition const& _struct)
|
|||||||
auto visitor = [&](StructDefinition const& _struct, auto& _cycleDetector, size_t _depth)
|
auto visitor = [&](StructDefinition const& _struct, auto& _cycleDetector, size_t _depth)
|
||||||
{
|
{
|
||||||
if (_depth >= 256)
|
if (_depth >= 256)
|
||||||
fatalDeclarationError(_struct.location(), "Struct definition exhausts cyclic dependency validator.");
|
m_errorReporter.fatalDeclarationError(
|
||||||
|
5651_error,
|
||||||
|
_struct.location(),
|
||||||
|
"Struct definition exhausts cyclic dependency validator."
|
||||||
|
);
|
||||||
|
|
||||||
for (ASTPointer<VariableDeclaration> const& member: _struct.members())
|
for (ASTPointer<VariableDeclaration> const& member: _struct.members())
|
||||||
{
|
{
|
||||||
@ -119,7 +124,7 @@ bool DeclarationTypeChecker::visit(StructDefinition const& _struct)
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (util::CycleDetector<StructDefinition>(visitor).run(_struct) != nullptr)
|
if (util::CycleDetector<StructDefinition>(visitor).run(_struct) != nullptr)
|
||||||
fatalTypeError(_struct.location(), "Recursive struct definition.");
|
m_errorReporter.fatalTypeError(2046_error, _struct.location(), "Recursive struct definition.");
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -145,9 +150,14 @@ void DeclarationTypeChecker::endVisit(UserDefinedTypeName const& _typeName)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
_typeName.annotation().type = TypeProvider::emptyTuple();
|
_typeName.annotation().type = TypeProvider::emptyTuple();
|
||||||
fatalTypeError(_typeName.location(), "Name has to refer to a struct, enum or contract.");
|
m_errorReporter.fatalTypeError(
|
||||||
|
9755_error,
|
||||||
|
_typeName.location(),
|
||||||
|
"Name has to refer to a struct, enum or contract."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeclarationTypeChecker::visit(FunctionTypeName const& _typeName)
|
bool DeclarationTypeChecker::visit(FunctionTypeName const& _typeName)
|
||||||
{
|
{
|
||||||
if (_typeName.annotation().type)
|
if (_typeName.annotation().type)
|
||||||
@ -165,18 +175,27 @@ bool DeclarationTypeChecker::visit(FunctionTypeName const& _typeName)
|
|||||||
case Visibility::External:
|
case Visibility::External:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fatalTypeError(_typeName.location(), "Invalid visibility, can only be \"external\" or \"internal\".");
|
m_errorReporter.fatalTypeError(
|
||||||
|
7653_error,
|
||||||
|
_typeName.location(),
|
||||||
|
"Invalid visibility, can only be \"external\" or \"internal\"."
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_typeName.isPayable() && _typeName.visibility() != Visibility::External)
|
if (_typeName.isPayable() && _typeName.visibility() != Visibility::External)
|
||||||
{
|
{
|
||||||
fatalTypeError(_typeName.location(), "Only external function types can be payable.");
|
m_errorReporter.fatalTypeError(
|
||||||
|
6138_error,
|
||||||
|
_typeName.location(),
|
||||||
|
"Only external function types can be payable."
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
_typeName.annotation().type = TypeProvider::function(_typeName);
|
_typeName.annotation().type = TypeProvider::function(_typeName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeclarationTypeChecker::endVisit(Mapping const& _mapping)
|
void DeclarationTypeChecker::endVisit(Mapping const& _mapping)
|
||||||
{
|
{
|
||||||
if (_mapping.annotation().type)
|
if (_mapping.annotation().type)
|
||||||
@ -226,7 +245,11 @@ void DeclarationTypeChecker::endVisit(ArrayTypeName const& _typeName)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (baseType->storageBytes() == 0)
|
if (baseType->storageBytes() == 0)
|
||||||
fatalTypeError(_typeName.baseType().location(), "Illegal base type of storage size zero for array.");
|
m_errorReporter.fatalTypeError(
|
||||||
|
9390_error,
|
||||||
|
_typeName.baseType().location(),
|
||||||
|
"Illegal base type of storage size zero for array."
|
||||||
|
);
|
||||||
if (Expression const* length = _typeName.length())
|
if (Expression const* length = _typeName.length())
|
||||||
{
|
{
|
||||||
TypePointer& lengthTypeGeneric = length->annotation().type;
|
TypePointer& lengthTypeGeneric = length->annotation().type;
|
||||||
@ -235,13 +258,17 @@ void DeclarationTypeChecker::endVisit(ArrayTypeName const& _typeName)
|
|||||||
RationalNumberType const* lengthType = dynamic_cast<RationalNumberType const*>(lengthTypeGeneric);
|
RationalNumberType const* lengthType = dynamic_cast<RationalNumberType const*>(lengthTypeGeneric);
|
||||||
u256 lengthValue = 0;
|
u256 lengthValue = 0;
|
||||||
if (!lengthType || !lengthType->mobileType())
|
if (!lengthType || !lengthType->mobileType())
|
||||||
typeError(length->location(), "Invalid array length, expected integer literal or constant expression.");
|
m_errorReporter.typeError(
|
||||||
|
8922_error,
|
||||||
|
length->location(),
|
||||||
|
"Invalid array length, expected integer literal or constant expression."
|
||||||
|
);
|
||||||
else if (lengthType->isZero())
|
else if (lengthType->isZero())
|
||||||
typeError(length->location(), "Array with zero length specified.");
|
m_errorReporter.typeError(1220_error, length->location(), "Array with zero length specified.");
|
||||||
else if (lengthType->isFractional())
|
else if (lengthType->isFractional())
|
||||||
typeError(length->location(), "Array with fractional length specified.");
|
m_errorReporter.typeError(4323_error, length->location(), "Array with fractional length specified.");
|
||||||
else if (lengthType->isNegative())
|
else if (lengthType->isNegative())
|
||||||
typeError(length->location(), "Array with negative length specified.");
|
m_errorReporter.typeError(9308_error, length->location(), "Array with negative length specified.");
|
||||||
else
|
else
|
||||||
lengthValue = lengthType->literalValue(nullptr);
|
lengthValue = lengthType->literalValue(nullptr);
|
||||||
_typeName.annotation().type = TypeProvider::array(DataLocation::Storage, baseType, lengthValue);
|
_typeName.annotation().type = TypeProvider::array(DataLocation::Storage, baseType, lengthValue);
|
||||||
@ -249,15 +276,24 @@ void DeclarationTypeChecker::endVisit(ArrayTypeName const& _typeName)
|
|||||||
else
|
else
|
||||||
_typeName.annotation().type = TypeProvider::array(DataLocation::Storage, baseType);
|
_typeName.annotation().type = TypeProvider::array(DataLocation::Storage, baseType);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeclarationTypeChecker::endVisit(VariableDeclaration const& _variable)
|
void DeclarationTypeChecker::endVisit(VariableDeclaration const& _variable)
|
||||||
{
|
{
|
||||||
if (_variable.annotation().type)
|
if (_variable.annotation().type)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_variable.isConstant() && !_variable.isStateVariable())
|
if (_variable.isConstant() && !_variable.isStateVariable())
|
||||||
m_errorReporter.declarationError(1788_error, _variable.location(), "The \"constant\" keyword can only be used for state variables.");
|
m_errorReporter.declarationError(
|
||||||
|
1788_error,
|
||||||
|
_variable.location(),
|
||||||
|
"The \"constant\" keyword can only be used for state variables."
|
||||||
|
);
|
||||||
if (_variable.immutable() && !_variable.isStateVariable())
|
if (_variable.immutable() && !_variable.isStateVariable())
|
||||||
m_errorReporter.declarationError(8297_error, _variable.location(), "The \"immutable\" keyword can only be used for state variables.");
|
m_errorReporter.declarationError(
|
||||||
|
8297_error,
|
||||||
|
_variable.location(),
|
||||||
|
"The \"immutable\" keyword can only be used for state variables."
|
||||||
|
);
|
||||||
|
|
||||||
if (!_variable.typeName())
|
if (!_variable.typeName())
|
||||||
{
|
{
|
||||||
@ -309,7 +345,7 @@ void DeclarationTypeChecker::endVisit(VariableDeclaration const& _variable)
|
|||||||
errorString += " for variable";
|
errorString += " for variable";
|
||||||
}
|
}
|
||||||
errorString += ", but " + locationToString(varLoc) + " was given.";
|
errorString += ", but " + locationToString(varLoc) + " was given.";
|
||||||
typeError(_variable.location(), errorString);
|
m_errorReporter.typeError(6160_error, _variable.location(), errorString);
|
||||||
|
|
||||||
solAssert(!allowedDataLocations.empty(), "");
|
solAssert(!allowedDataLocations.empty(), "");
|
||||||
varLoc = *allowedDataLocations.begin();
|
varLoc = *allowedDataLocations.begin();
|
||||||
@ -359,24 +395,9 @@ void DeclarationTypeChecker::endVisit(VariableDeclaration const& _variable)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeclarationTypeChecker::typeError(SourceLocation const& _location, string const& _description)
|
|
||||||
{
|
|
||||||
m_errorReporter.typeError(2311_error, _location, _description);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeclarationTypeChecker::fatalTypeError(SourceLocation const& _location, string const& _description)
|
|
||||||
{
|
|
||||||
m_errorReporter.fatalTypeError(5651_error, _location, _description);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeclarationTypeChecker::fatalDeclarationError(SourceLocation const& _location, string const& _description)
|
|
||||||
{
|
|
||||||
m_errorReporter.fatalDeclarationError(2046_error, _location, _description);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DeclarationTypeChecker::check(ASTNode const& _node)
|
bool DeclarationTypeChecker::check(ASTNode const& _node)
|
||||||
{
|
{
|
||||||
unsigned errorCount = m_errorReporter.errorCount();
|
auto watcher = m_errorReporter.errorWatcher();
|
||||||
_node.accept(*this);
|
_node.accept(*this);
|
||||||
return m_errorReporter.errorCount() == errorCount;
|
return watcher.ok();
|
||||||
}
|
}
|
||||||
|
@ -59,15 +59,6 @@ private:
|
|||||||
void endVisit(VariableDeclaration const& _variable) override;
|
void endVisit(VariableDeclaration const& _variable) override;
|
||||||
bool visit(StructDefinition const& _struct) override;
|
bool visit(StructDefinition const& _struct) override;
|
||||||
|
|
||||||
/// Adds a new error to the list of errors.
|
|
||||||
void typeError(langutil::SourceLocation const& _location, std::string const& _description);
|
|
||||||
|
|
||||||
/// Adds a new error to the list of errors and throws to abort reference resolving.
|
|
||||||
void fatalTypeError(langutil::SourceLocation const& _location, std::string const& _description);
|
|
||||||
|
|
||||||
/// Adds a new error to the list of errors and throws to abort reference resolving.
|
|
||||||
void fatalDeclarationError(langutil::SourceLocation const& _location, std::string const& _description);
|
|
||||||
|
|
||||||
langutil::ErrorReporter& m_errorReporter;
|
langutil::ErrorReporter& m_errorReporter;
|
||||||
langutil::EVMVersion m_evmVersion;
|
langutil::EVMVersion m_evmVersion;
|
||||||
bool m_insideFunctionType = false;
|
bool m_insideFunctionType = false;
|
||||||
|
@ -68,14 +68,16 @@ bool DocStringAnalyser::visit(VariableDeclaration const& _variable)
|
|||||||
parseDocStrings(_variable, _variable.annotation(), validPublicTags, "non-public state variables");
|
parseDocStrings(_variable, _variable.annotation(), validPublicTags, "non-public state variables");
|
||||||
if (_variable.annotation().docTags.count("notice") > 0)
|
if (_variable.annotation().docTags.count("notice") > 0)
|
||||||
m_errorReporter.warning(
|
m_errorReporter.warning(
|
||||||
9098_error, _variable.documentation()->location(),
|
7816_error, _variable.documentation()->location(),
|
||||||
"Documentation tag on non-public state variables will be disallowed in 0.7.0. You will need to use the @dev tag explicitly."
|
"Documentation tag on non-public state variables will be disallowed in 0.7.0. "
|
||||||
|
"You will need to use the @dev tag explicitly."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (_variable.annotation().docTags.count("title") > 0 || _variable.annotation().docTags.count("author") > 0)
|
if (_variable.annotation().docTags.count("title") > 0 || _variable.annotation().docTags.count("author") > 0)
|
||||||
m_errorReporter.warning(
|
m_errorReporter.warning(
|
||||||
4822_error, _variable.documentation()->location(),
|
8532_error, _variable.documentation()->location(),
|
||||||
"Documentation tag @title and @author is only allowed on contract definitions. It will be disallowed in 0.7.0."
|
"Documentation tag @title and @author is only allowed on contract definitions. "
|
||||||
|
"It will be disallowed in 0.7.0."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -110,7 +112,8 @@ void DocStringAnalyser::checkParameters(
|
|||||||
auto paramRange = _annotation.docTags.equal_range("param");
|
auto paramRange = _annotation.docTags.equal_range("param");
|
||||||
for (auto i = paramRange.first; i != paramRange.second; ++i)
|
for (auto i = paramRange.first; i != paramRange.second; ++i)
|
||||||
if (!validParams.count(i->second.paramName))
|
if (!validParams.count(i->second.paramName))
|
||||||
appendError(
|
m_errorReporter.docstringParsingError(
|
||||||
|
3881_error,
|
||||||
_node.documentation()->location(),
|
_node.documentation()->location(),
|
||||||
"Documented parameter \"" +
|
"Documented parameter \"" +
|
||||||
i->second.paramName +
|
i->second.paramName +
|
||||||
@ -159,7 +162,8 @@ void DocStringAnalyser::parseDocStrings(
|
|||||||
for (auto const& docTag: _annotation.docTags)
|
for (auto const& docTag: _annotation.docTags)
|
||||||
{
|
{
|
||||||
if (!_validTags.count(docTag.first))
|
if (!_validTags.count(docTag.first))
|
||||||
appendError(
|
m_errorReporter.docstringParsingError(
|
||||||
|
6546_error,
|
||||||
_node.documentation()->location(),
|
_node.documentation()->location(),
|
||||||
"Documentation tag @" + docTag.first + " not valid for " + _nodeName + "."
|
"Documentation tag @" + docTag.first + " not valid for " + _nodeName + "."
|
||||||
);
|
);
|
||||||
@ -170,12 +174,14 @@ void DocStringAnalyser::parseDocStrings(
|
|||||||
if (auto* varDecl = dynamic_cast<VariableDeclaration const*>(&_node))
|
if (auto* varDecl = dynamic_cast<VariableDeclaration const*>(&_node))
|
||||||
{
|
{
|
||||||
if (!varDecl->isPublic())
|
if (!varDecl->isPublic())
|
||||||
appendError(
|
m_errorReporter.docstringParsingError(
|
||||||
|
9440_error,
|
||||||
_node.documentation()->location(),
|
_node.documentation()->location(),
|
||||||
"Documentation tag \"@" + docTag.first + "\" is only allowed on public state-variables."
|
"Documentation tag \"@" + docTag.first + "\" is only allowed on public state-variables."
|
||||||
);
|
);
|
||||||
if (returnTagsVisited > 1)
|
if (returnTagsVisited > 1)
|
||||||
appendError(
|
m_errorReporter.docstringParsingError(
|
||||||
|
5256_error,
|
||||||
_node.documentation()->location(),
|
_node.documentation()->location(),
|
||||||
"Documentation tag \"@" + docTag.first + "\" is only allowed once on state-variables."
|
"Documentation tag \"@" + docTag.first + "\" is only allowed once on state-variables."
|
||||||
);
|
);
|
||||||
@ -186,7 +192,8 @@ void DocStringAnalyser::parseDocStrings(
|
|||||||
string firstWord = content.substr(0, content.find_first_of(" \t"));
|
string firstWord = content.substr(0, content.find_first_of(" \t"));
|
||||||
|
|
||||||
if (returnTagsVisited > function->returnParameters().size())
|
if (returnTagsVisited > function->returnParameters().size())
|
||||||
appendError(
|
m_errorReporter.docstringParsingError(
|
||||||
|
2604_error,
|
||||||
_node.documentation()->location(),
|
_node.documentation()->location(),
|
||||||
"Documentation tag \"@" + docTag.first + " " + docTag.second.content + "\"" +
|
"Documentation tag \"@" + docTag.first + " " + docTag.second.content + "\"" +
|
||||||
" exceeds the number of return parameters."
|
" exceeds the number of return parameters."
|
||||||
@ -195,7 +202,8 @@ void DocStringAnalyser::parseDocStrings(
|
|||||||
{
|
{
|
||||||
auto parameter = function->returnParameters().at(returnTagsVisited - 1);
|
auto parameter = function->returnParameters().at(returnTagsVisited - 1);
|
||||||
if (!parameter->name().empty() && parameter->name() != firstWord)
|
if (!parameter->name().empty() && parameter->name() != firstWord)
|
||||||
appendError(
|
m_errorReporter.docstringParsingError(
|
||||||
|
5856_error,
|
||||||
_node.documentation()->location(),
|
_node.documentation()->location(),
|
||||||
"Documentation tag \"@" + docTag.first + " " + docTag.second.content + "\"" +
|
"Documentation tag \"@" + docTag.first + " " + docTag.second.content + "\"" +
|
||||||
" does not contain the name of its return parameter."
|
" does not contain the name of its return parameter."
|
||||||
@ -205,8 +213,3 @@ void DocStringAnalyser::parseDocStrings(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DocStringAnalyser::appendError(SourceLocation const& _location, string const& _description)
|
|
||||||
{
|
|
||||||
m_errorReporter.docstringParsingError(7816_error, _location, _description);
|
|
||||||
}
|
|
||||||
|
@ -81,8 +81,6 @@ private:
|
|||||||
std::string const& _nodeName
|
std::string const& _nodeName
|
||||||
);
|
);
|
||||||
|
|
||||||
void appendError(langutil::SourceLocation const& _location, std::string const& _description);
|
|
||||||
|
|
||||||
langutil::ErrorReporter& m_errorReporter;
|
langutil::ErrorReporter& m_errorReporter;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ bool ReferencesResolver::visit(Identifier const& _identifier)
|
|||||||
else
|
else
|
||||||
errorMessage += " Did you mean " + std::move(suggestions) + "?";
|
errorMessage += " Did you mean " + std::move(suggestions) + "?";
|
||||||
}
|
}
|
||||||
declarationError(_identifier.location(), errorMessage);
|
m_errorReporter.declarationError(8051_error, _identifier.location(), errorMessage);
|
||||||
}
|
}
|
||||||
else if (declarations.size() == 1)
|
else if (declarations.size() == 1)
|
||||||
_identifier.annotation().referencedDeclaration = declarations.front();
|
_identifier.annotation().referencedDeclaration = declarations.front();
|
||||||
@ -157,7 +157,7 @@ void ReferencesResolver::endVisit(UserDefinedTypeName const& _typeName)
|
|||||||
Declaration const* declaration = m_resolver.pathFromCurrentScope(_typeName.namePath());
|
Declaration const* declaration = m_resolver.pathFromCurrentScope(_typeName.namePath());
|
||||||
if (!declaration)
|
if (!declaration)
|
||||||
{
|
{
|
||||||
fatalDeclarationError(_typeName.location(), "Identifier not found or not unique.");
|
m_errorReporter.fatalDeclarationError(7556_error, _typeName.location(), "Identifier not found or not unique.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,14 +209,22 @@ void ReferencesResolver::operator()(yul::Identifier const& _identifier)
|
|||||||
));
|
));
|
||||||
if (realName.empty())
|
if (realName.empty())
|
||||||
{
|
{
|
||||||
declarationError(_identifier.location, "In variable names _slot and _offset can only be used as a suffix.");
|
m_errorReporter.declarationError(
|
||||||
|
9553_error,
|
||||||
|
_identifier.location,
|
||||||
|
"In variable names _slot and _offset can only be used as a suffix."
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
declarations = m_resolver.nameFromCurrentScope(realName);
|
declarations = m_resolver.nameFromCurrentScope(realName);
|
||||||
}
|
}
|
||||||
if (declarations.size() > 1)
|
if (declarations.size() > 1)
|
||||||
{
|
{
|
||||||
declarationError(_identifier.location, "Multiple matching identifiers. Resolving overloaded identifiers is not supported.");
|
m_errorReporter.declarationError(
|
||||||
|
8827_error,
|
||||||
|
_identifier.location,
|
||||||
|
"Multiple matching identifiers. Resolving overloaded identifiers is not supported."
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (declarations.size() == 0)
|
else if (declarations.size() == 0)
|
||||||
@ -224,7 +232,11 @@ void ReferencesResolver::operator()(yul::Identifier const& _identifier)
|
|||||||
if (auto var = dynamic_cast<VariableDeclaration const*>(declarations.front()))
|
if (auto var = dynamic_cast<VariableDeclaration const*>(declarations.front()))
|
||||||
if (var->isLocalVariable() && m_yulInsideFunction)
|
if (var->isLocalVariable() && m_yulInsideFunction)
|
||||||
{
|
{
|
||||||
declarationError(_identifier.location, "Cannot access local Solidity variables from inside an inline assembly function.");
|
m_errorReporter.declarationError(
|
||||||
|
8477_error,
|
||||||
|
_identifier.location,
|
||||||
|
"Cannot access local Solidity variables from inside an inline assembly function."
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,7 +254,11 @@ void ReferencesResolver::operator()(yul::VariableDeclaration const& _varDecl)
|
|||||||
|
|
||||||
string namePrefix = identifier.name.str().substr(0, identifier.name.str().find('.'));
|
string namePrefix = identifier.name.str().substr(0, identifier.name.str().find('.'));
|
||||||
if (isSlot || isOffset)
|
if (isSlot || isOffset)
|
||||||
declarationError(identifier.location, "In variable declarations _slot and _offset can not be used as a suffix.");
|
m_errorReporter.declarationError(
|
||||||
|
8820_error,
|
||||||
|
identifier.location,
|
||||||
|
"In variable declarations _slot and _offset can not be used as a suffix."
|
||||||
|
);
|
||||||
else if (
|
else if (
|
||||||
auto declarations = m_resolver.nameFromCurrentScope(namePrefix);
|
auto declarations = m_resolver.nameFromCurrentScope(namePrefix);
|
||||||
!declarations.empty()
|
!declarations.empty()
|
||||||
@ -252,7 +268,8 @@ void ReferencesResolver::operator()(yul::VariableDeclaration const& _varDecl)
|
|||||||
for (auto const* decl: declarations)
|
for (auto const* decl: declarations)
|
||||||
ssl.append("The shadowed declaration is here:", decl->location());
|
ssl.append("The shadowed declaration is here:", decl->location());
|
||||||
if (!ssl.infos.empty())
|
if (!ssl.infos.empty())
|
||||||
declarationError(
|
m_errorReporter.declarationError(
|
||||||
|
6005_error,
|
||||||
identifier.location,
|
identifier.location,
|
||||||
ssl,
|
ssl,
|
||||||
namePrefix.size() < identifier.name.str().size() ?
|
namePrefix.size() < identifier.name.str().size() ?
|
||||||
@ -266,19 +283,4 @@ void ReferencesResolver::operator()(yul::VariableDeclaration const& _varDecl)
|
|||||||
visit(*_varDecl.value);
|
visit(*_varDecl.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReferencesResolver::declarationError(SourceLocation const& _location, string const& _description)
|
|
||||||
{
|
|
||||||
m_errorReporter.declarationError(8532_error, _location, _description);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReferencesResolver::declarationError(SourceLocation const& _location, SecondarySourceLocation const& _ssl, string const& _description)
|
|
||||||
{
|
|
||||||
m_errorReporter.declarationError(3881_error, _location, _ssl, _description);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReferencesResolver::fatalDeclarationError(SourceLocation const& _location, string const& _description)
|
|
||||||
{
|
|
||||||
m_errorReporter.fatalDeclarationError(6546_error, _location, _description);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -88,15 +88,6 @@ private:
|
|||||||
void operator()(yul::Identifier const& _identifier) override;
|
void operator()(yul::Identifier const& _identifier) override;
|
||||||
void operator()(yul::VariableDeclaration const& _varDecl) override;
|
void operator()(yul::VariableDeclaration const& _varDecl) override;
|
||||||
|
|
||||||
/// Adds a new error to the list of errors.
|
|
||||||
void declarationError(langutil::SourceLocation const& _location, std::string const& _description);
|
|
||||||
|
|
||||||
/// Adds a new error to the list of errors.
|
|
||||||
void declarationError(langutil::SourceLocation const& _location, langutil::SecondarySourceLocation const& _ssl, std::string const& _description);
|
|
||||||
|
|
||||||
/// Adds a new error to the list of errors and throws to abort reference resolving.
|
|
||||||
void fatalDeclarationError(langutil::SourceLocation const& _location, std::string const& _description);
|
|
||||||
|
|
||||||
langutil::ErrorReporter& m_errorReporter;
|
langutil::ErrorReporter& m_errorReporter;
|
||||||
NameAndTypeResolver& m_resolver;
|
NameAndTypeResolver& m_resolver;
|
||||||
langutil::EVMVersion m_evmVersion;
|
langutil::EVMVersion m_evmVersion;
|
||||||
|
@ -250,7 +250,7 @@ struct ExpressionAnnotation: ASTAnnotation
|
|||||||
bool lValueOfOrdinaryAssignment = false;
|
bool lValueOfOrdinaryAssignment = false;
|
||||||
|
|
||||||
/// Types and - if given - names of arguments if the expr. is a function
|
/// Types and - if given - names of arguments if the expr. is a function
|
||||||
/// that is called, used for overload resoultion
|
/// that is called, used for overload resolution
|
||||||
std::optional<FuncCallArguments> arguments;
|
std::optional<FuncCallArguments> arguments;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -185,6 +185,13 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
|||||||
{
|
{
|
||||||
solAssert(byteOffsetSize == 0, "Byte offset for array as base type.");
|
solAssert(byteOffsetSize == 0, "Byte offset for array as base type.");
|
||||||
auto const& sourceBaseArrayType = dynamic_cast<ArrayType const&>(*sourceBaseType);
|
auto const& sourceBaseArrayType = dynamic_cast<ArrayType const&>(*sourceBaseType);
|
||||||
|
|
||||||
|
solUnimplementedAssert(
|
||||||
|
_sourceType.location() != DataLocation::CallData ||
|
||||||
|
!_sourceType.isDynamicallyEncoded() ||
|
||||||
|
!sourceBaseArrayType.isDynamicallySized(),
|
||||||
|
"Copying nested calldata dynamic arrays to storage is not implemented in the old code generator."
|
||||||
|
);
|
||||||
_context << Instruction::DUP3;
|
_context << Instruction::DUP3;
|
||||||
if (sourceBaseArrayType.location() == DataLocation::Memory)
|
if (sourceBaseArrayType.location() == DataLocation::Memory)
|
||||||
_context << Instruction::MLOAD;
|
_context << Instruction::MLOAD;
|
||||||
|
@ -974,6 +974,14 @@ void CompilerUtils::convertType(
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (auto baseType = dynamic_cast<ArrayType const*>(typeOnStack.baseType()))
|
||||||
|
solUnimplementedAssert(
|
||||||
|
typeOnStack.location() != DataLocation::CallData ||
|
||||||
|
!typeOnStack.isDynamicallyEncoded() ||
|
||||||
|
!baseType->isDynamicallySized(),
|
||||||
|
"Copying nested dynamic calldata arrays to memory is not implemented in the old code generator."
|
||||||
|
);
|
||||||
|
|
||||||
m_context << u256(0) << Instruction::SWAP1;
|
m_context << u256(0) << Instruction::SWAP1;
|
||||||
// stack: <mem start> <source ref> (variably sized) <length> <counter> <mem data pos>
|
// stack: <mem start> <source ref> (variably sized) <length> <counter> <mem data pos>
|
||||||
auto repeat = m_context.newTag();
|
auto repeat = m_context.newTag();
|
||||||
|
@ -286,7 +286,7 @@ public:
|
|||||||
/// Appends code that computes the Keccak-256 hash of the topmost stack element of 32 byte type.
|
/// Appends code that computes the Keccak-256 hash of the topmost stack element of 32 byte type.
|
||||||
void computeHashStatic();
|
void computeHashStatic();
|
||||||
|
|
||||||
/// Apppends code that copies the code of the given contract to memory.
|
/// Appends code that copies the code of the given contract to memory.
|
||||||
/// Stack pre: Memory position
|
/// Stack pre: Memory position
|
||||||
/// Stack post: Updated memory position
|
/// Stack post: Updated memory position
|
||||||
/// @param creation if true, copies creation code, if false copies runtime code.
|
/// @param creation if true, copies creation code, if false copies runtime code.
|
||||||
|
@ -1912,7 +1912,7 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier)
|
|||||||
// If the identifier is called right away, this code is executed in visit(FunctionCall...), because
|
// If the identifier is called right away, this code is executed in visit(FunctionCall...), because
|
||||||
// we want to avoid having a reference to the runtime function entry point in the
|
// we want to avoid having a reference to the runtime function entry point in the
|
||||||
// constructor context, since this would force the compiler to include unreferenced
|
// constructor context, since this would force the compiler to include unreferenced
|
||||||
// internal functions in the runtime contex.
|
// internal functions in the runtime context.
|
||||||
utils().pushCombinedFunctionEntryLabel(functionDef->resolveVirtual(m_context.mostDerivedContract()));
|
utils().pushCombinedFunctionEntryLabel(functionDef->resolveVirtual(m_context.mostDerivedContract()));
|
||||||
else if (auto variable = dynamic_cast<VariableDeclaration const*>(declaration))
|
else if (auto variable = dynamic_cast<VariableDeclaration const*>(declaration))
|
||||||
appendVariable(*variable, static_cast<Expression const&>(_identifier));
|
appendVariable(*variable, static_cast<Expression const&>(_identifier));
|
||||||
|
@ -99,3 +99,13 @@ string IRNames::zeroValue(Type const& _type, string const& _variableName)
|
|||||||
{
|
{
|
||||||
return "zero_value_for_type_" + _type.identifier() + _variableName;
|
return "zero_value_for_type_" + _type.identifier() + _variableName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FunctionDefinition const* IRHelpers::referencedFunctionDeclaration(Expression const& _expression)
|
||||||
|
{
|
||||||
|
if (auto memberAccess = dynamic_cast<MemberAccess const*>(&_expression))
|
||||||
|
return dynamic_cast<FunctionDefinition const*>(memberAccess->annotation().referencedDeclaration);
|
||||||
|
else if (auto identifier = dynamic_cast<Identifier const*>(&_expression))
|
||||||
|
return dynamic_cast<FunctionDefinition const*>(identifier->annotation().referencedDeclaration);
|
||||||
|
else
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
@ -62,6 +62,11 @@ struct IRNames
|
|||||||
static std::string zeroValue(Type const& _type, std::string const& _variableName);
|
static std::string zeroValue(Type const& _type, std::string const& _variableName);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct IRHelpers
|
||||||
|
{
|
||||||
|
static FunctionDefinition const* referencedFunctionDeclaration(Expression const& _expression);
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overloading std::less() makes it possible to use YulArity as a map key. We could define operator<
|
// Overloading std::less() makes it possible to use YulArity as a map key. We could define operator<
|
||||||
|
@ -625,15 +625,22 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
arguments.push_back(callArguments[std::distance(callArgumentNames.begin(), it)]);
|
arguments.push_back(callArguments[std::distance(callArgumentNames.begin(), it)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto memberAccess = dynamic_cast<MemberAccess const*>(&_functionCall.expression()))
|
auto memberAccess = dynamic_cast<MemberAccess const*>(&_functionCall.expression());
|
||||||
|
if (memberAccess)
|
||||||
|
{
|
||||||
if (auto expressionType = dynamic_cast<TypeType const*>(memberAccess->expression().annotation().type))
|
if (auto expressionType = dynamic_cast<TypeType const*>(memberAccess->expression().annotation().type))
|
||||||
|
{
|
||||||
|
solAssert(!functionType->bound(), "");
|
||||||
if (auto contractType = dynamic_cast<ContractType const*>(expressionType->actualType()))
|
if (auto contractType = dynamic_cast<ContractType const*>(expressionType->actualType()))
|
||||||
solUnimplementedAssert(
|
solUnimplementedAssert(
|
||||||
!contractType->contractDefinition().isLibrary() || functionType->kind() == FunctionType::Kind::Internal,
|
!contractType->contractDefinition().isLibrary() || functionType->kind() == FunctionType::Kind::Internal,
|
||||||
"Only internal function calls implemented for libraries"
|
"Only internal function calls implemented for libraries"
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
solAssert(!functionType->bound(), "");
|
||||||
|
|
||||||
solUnimplementedAssert(!functionType->bound(), "");
|
|
||||||
switch (functionType->kind())
|
switch (functionType->kind())
|
||||||
{
|
{
|
||||||
case FunctionType::Kind::Declaration:
|
case FunctionType::Kind::Declaration:
|
||||||
@ -641,53 +648,40 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
break;
|
break;
|
||||||
case FunctionType::Kind::Internal:
|
case FunctionType::Kind::Internal:
|
||||||
{
|
{
|
||||||
optional<FunctionDefinition const*> functionDef;
|
auto identifier = dynamic_cast<Identifier const*>(&_functionCall.expression());
|
||||||
if (auto memberAccess = dynamic_cast<MemberAccess const*>(&_functionCall.expression()))
|
FunctionDefinition const* functionDef = IRHelpers::referencedFunctionDeclaration(_functionCall.expression());
|
||||||
{
|
|
||||||
solUnimplementedAssert(!functionType->bound(), "Internal calls to bound functions are not yet implemented for libraries and not allowed for contracts");
|
|
||||||
|
|
||||||
functionDef = dynamic_cast<FunctionDefinition const*>(memberAccess->annotation().referencedDeclaration);
|
if (functionDef)
|
||||||
if (functionDef.value() != nullptr)
|
|
||||||
solAssert(functionType->declaration() == *memberAccess->annotation().referencedDeclaration, "");
|
|
||||||
else
|
|
||||||
{
|
|
||||||
solAssert(dynamic_cast<VariableDeclaration const*>(memberAccess->annotation().referencedDeclaration), "");
|
|
||||||
solAssert(!functionType->hasDeclaration(), "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (auto identifier = dynamic_cast<Identifier const*>(&_functionCall.expression()))
|
|
||||||
{
|
{
|
||||||
solAssert(!functionType->bound(), "");
|
solAssert(memberAccess || identifier, "");
|
||||||
|
solAssert(functionType->declaration() == *functionDef, "");
|
||||||
|
|
||||||
if (auto unresolvedFunctionDef = dynamic_cast<FunctionDefinition const*>(identifier->annotation().referencedDeclaration))
|
if (identifier)
|
||||||
{
|
functionDef = &functionDef->resolveVirtual(m_context.mostDerivedContract());
|
||||||
functionDef = &unresolvedFunctionDef->resolveVirtual(m_context.mostDerivedContract());
|
|
||||||
solAssert(functionType->declaration() == *identifier->annotation().referencedDeclaration, "");
|
solAssert(functionDef->isImplemented(), "");
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
functionDef = nullptr;
|
|
||||||
solAssert(dynamic_cast<VariableDeclaration const*>(identifier->annotation().referencedDeclaration), "");
|
|
||||||
solAssert(!functionType->hasDeclaration(), "");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
// Not a simple expression like x or A.x
|
solAssert(!functionType->hasDeclaration(), "");
|
||||||
functionDef = nullptr;
|
|
||||||
|
|
||||||
solAssert(functionDef.has_value(), "");
|
solAssert(!functionType->takesArbitraryParameters(), "");
|
||||||
solAssert(functionDef.value() == nullptr || functionDef.value()->isImplemented(), "");
|
|
||||||
|
|
||||||
vector<string> args;
|
vector<string> args;
|
||||||
for (size_t i = 0; i < arguments.size(); ++i)
|
if (functionType->bound())
|
||||||
if (functionType->takesArbitraryParameters())
|
{
|
||||||
args += IRVariable(*arguments[i]).stackSlots();
|
solAssert(memberAccess && functionDef, "");
|
||||||
else
|
solAssert(functionDef->parameters().size() == arguments.size() + 1, "");
|
||||||
args += convert(*arguments[i], *parameterTypes[i]).stackSlots();
|
args += convert(memberAccess->expression(), *functionDef->parameters()[0]->type()).stackSlots();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
solAssert(!functionDef || functionDef->parameters().size() == arguments.size(), "");
|
||||||
|
|
||||||
if (functionDef.value() != nullptr)
|
for (size_t i = 0; i < arguments.size(); ++i)
|
||||||
|
args += convert(*arguments[i], *parameterTypes[i]).stackSlots();
|
||||||
|
|
||||||
|
if (functionDef)
|
||||||
define(_functionCall) <<
|
define(_functionCall) <<
|
||||||
m_context.enqueueFunctionForCodeGeneration(*functionDef.value()) <<
|
m_context.enqueueFunctionForCodeGeneration(*functionDef) <<
|
||||||
"(" <<
|
"(" <<
|
||||||
joinHumanReadable(args) <<
|
joinHumanReadable(args) <<
|
||||||
")\n";
|
")\n";
|
||||||
@ -1237,13 +1231,27 @@ void IRGeneratorForStatements::endVisit(FunctionCallOptions const& _options)
|
|||||||
void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
||||||
{
|
{
|
||||||
ASTString const& member = _memberAccess.memberName();
|
ASTString const& member = _memberAccess.memberName();
|
||||||
if (auto funType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type))
|
auto memberFunctionType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type);
|
||||||
if (funType->bound())
|
Type::Category objectCategory = _memberAccess.expression().annotation().type->category();
|
||||||
{
|
|
||||||
solUnimplementedAssert(false, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (_memberAccess.expression().annotation().type->category())
|
if (memberFunctionType && memberFunctionType->bound())
|
||||||
|
{
|
||||||
|
solAssert((set<Type::Category>{
|
||||||
|
Type::Category::Contract,
|
||||||
|
Type::Category::Bool,
|
||||||
|
Type::Category::Integer,
|
||||||
|
Type::Category::Address,
|
||||||
|
Type::Category::Function,
|
||||||
|
Type::Category::Struct,
|
||||||
|
Type::Category::Enum,
|
||||||
|
Type::Category::Mapping,
|
||||||
|
Type::Category::Array,
|
||||||
|
Type::Category::FixedBytes,
|
||||||
|
}).count(objectCategory) > 0, "");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (objectCategory)
|
||||||
{
|
{
|
||||||
case Type::Category::Contract:
|
case Type::Category::Contract:
|
||||||
{
|
{
|
||||||
@ -1476,9 +1484,9 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
|||||||
{
|
{
|
||||||
if (auto const* variable = dynamic_cast<VariableDeclaration const*>(_memberAccess.annotation().referencedDeclaration))
|
if (auto const* variable = dynamic_cast<VariableDeclaration const*>(_memberAccess.annotation().referencedDeclaration))
|
||||||
handleVariableReference(*variable, _memberAccess);
|
handleVariableReference(*variable, _memberAccess);
|
||||||
else if (auto const* funType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type))
|
else if (memberFunctionType)
|
||||||
{
|
{
|
||||||
switch (funType->kind())
|
switch (memberFunctionType->kind())
|
||||||
{
|
{
|
||||||
case FunctionType::Kind::Declaration:
|
case FunctionType::Kind::Declaration:
|
||||||
break;
|
break;
|
||||||
@ -1497,7 +1505,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
|||||||
break;
|
break;
|
||||||
case FunctionType::Kind::DelegateCall:
|
case FunctionType::Kind::DelegateCall:
|
||||||
define(IRVariable(_memberAccess).part("address"), _memberAccess.expression());
|
define(IRVariable(_memberAccess).part("address"), _memberAccess.expression());
|
||||||
define(IRVariable(_memberAccess).part("functionIdentifier")) << formatNumber(funType->externalIdentifier()) << "\n";
|
define(IRVariable(_memberAccess).part("functionIdentifier")) << formatNumber(memberFunctionType->externalIdentifier()) << "\n";
|
||||||
break;
|
break;
|
||||||
case FunctionType::Kind::External:
|
case FunctionType::Kind::External:
|
||||||
case FunctionType::Kind::Creation:
|
case FunctionType::Kind::Creation:
|
||||||
|
@ -178,7 +178,7 @@ bool isArtifactRequested(Json::Value const& _outputSelection, string const& _art
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @a _outputSelection is a JSON object containining a two-level hashmap, where the first level is the filename,
|
/// @a _outputSelection is a JSON object containing a two-level hashmap, where the first level is the filename,
|
||||||
/// the second level is the contract name and the value is an array of artifact names to be requested for that contract.
|
/// the second level is the contract name and the value is an array of artifact names to be requested for that contract.
|
||||||
/// @a _file is the current file
|
/// @a _file is the current file
|
||||||
/// @a _contract is the current contract
|
/// @a _contract is the current contract
|
||||||
@ -229,7 +229,7 @@ bool isBinaryRequested(Json::Value const& _outputSelection)
|
|||||||
if (!_outputSelection.isObject())
|
if (!_outputSelection.isObject())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// This does not inculde "evm.methodIdentifiers" on purpose!
|
// This does not include "evm.methodIdentifiers" on purpose!
|
||||||
static vector<string> const outputsThatRequireBinaries{
|
static vector<string> const outputsThatRequireBinaries{
|
||||||
"*",
|
"*",
|
||||||
"ir", "irOptimized",
|
"ir", "irOptimized",
|
||||||
|
@ -96,7 +96,10 @@ void DocStringParser::parse(string const& _docString, ErrorReporter& _errorRepor
|
|||||||
auto tagNameEndPos = firstWhitespaceOrNewline(tagPos, end);
|
auto tagNameEndPos = firstWhitespaceOrNewline(tagPos, end);
|
||||||
if (tagNameEndPos == end)
|
if (tagNameEndPos == end)
|
||||||
{
|
{
|
||||||
appendError("End of tag " + string(tagPos, tagNameEndPos) + " not found");
|
m_errorReporter->docstringParsingError(
|
||||||
|
9222_error,
|
||||||
|
"End of tag " + string(tagPos, tagNameEndPos) + " not found"
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,7 +141,7 @@ DocStringParser::iter DocStringParser::parseDocTagParam(iter _pos, iter _end)
|
|||||||
auto nameStartPos = skipWhitespace(_pos, _end);
|
auto nameStartPos = skipWhitespace(_pos, _end);
|
||||||
if (nameStartPos == _end)
|
if (nameStartPos == _end)
|
||||||
{
|
{
|
||||||
appendError("No param name given");
|
m_errorReporter->docstringParsingError(3335_error, "No param name given");
|
||||||
return _end;
|
return _end;
|
||||||
}
|
}
|
||||||
auto nameEndPos = firstNonIdentifier(nameStartPos, _end);
|
auto nameEndPos = firstNonIdentifier(nameStartPos, _end);
|
||||||
@ -149,7 +152,7 @@ DocStringParser::iter DocStringParser::parseDocTagParam(iter _pos, iter _end)
|
|||||||
|
|
||||||
if (descStartPos == nlPos)
|
if (descStartPos == nlPos)
|
||||||
{
|
{
|
||||||
appendError("No description given for param " + paramName);
|
m_errorReporter->docstringParsingError(9942_error, "No description given for param " + paramName);
|
||||||
return _end;
|
return _end;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,8 +192,3 @@ void DocStringParser::newTag(string const& _tagName)
|
|||||||
{
|
{
|
||||||
m_lastTag = &m_docTags.insert(make_pair(_tagName, DocTag()))->second;
|
m_lastTag = &m_docTags.insert(make_pair(_tagName, DocTag()))->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DocStringParser::appendError(string const& _description)
|
|
||||||
{
|
|
||||||
m_errorReporter->docstringParsingError(9440_error, _description);
|
|
||||||
}
|
|
||||||
|
@ -58,8 +58,6 @@ private:
|
|||||||
/// Creates and inserts a new tag and adjusts m_lastTag.
|
/// Creates and inserts a new tag and adjusts m_lastTag.
|
||||||
void newTag(std::string const& _tagName);
|
void newTag(std::string const& _tagName);
|
||||||
|
|
||||||
void appendError(std::string const& _description);
|
|
||||||
|
|
||||||
/// Mapping tag name -> content.
|
/// Mapping tag name -> content.
|
||||||
std::multimap<std::string, DocTag> m_docTags;
|
std::multimap<std::string, DocTag> m_docTags;
|
||||||
DocTag* m_lastTag = nullptr;
|
DocTag* m_lastTag = nullptr;
|
||||||
|
@ -138,4 +138,13 @@ bool validateUTF8(std::string const& _input, size_t& _invalidPosition)
|
|||||||
return validateUTF8(reinterpret_cast<unsigned char const*>(_input.c_str()), _input.length(), _invalidPosition);
|
return validateUTF8(reinterpret_cast<unsigned char const*>(_input.c_str()), _input.length(), _invalidPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t numCodepoints(std::string const& _utf8EncodedInput)
|
||||||
|
{
|
||||||
|
size_t codepoint = 0;
|
||||||
|
for (char c: _utf8EncodedInput)
|
||||||
|
codepoint += (c & 0xc0) != 0x80;
|
||||||
|
|
||||||
|
return codepoint;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -38,4 +38,6 @@ inline bool validateUTF8(std::string const& _input)
|
|||||||
return validateUTF8(_input, invalidPos);
|
return validateUTF8(_input, invalidPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t numCodepoints(std::string const& _utf8EncodedInput);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -382,15 +382,15 @@ bytes BinaryTransform::operator()(Loop const& _loop)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes BinaryTransform::operator()(Break const& _break)
|
bytes BinaryTransform::operator()(Branch const& _branch)
|
||||||
{
|
{
|
||||||
return toBytes(Opcode::Br) + encodeLabelIdx(_break.label.name);
|
return toBytes(Opcode::Br) + encodeLabelIdx(_branch.label.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes BinaryTransform::operator()(BreakIf const& _breakIf)
|
bytes BinaryTransform::operator()(BranchIf const& _branchIf)
|
||||||
{
|
{
|
||||||
bytes result = std::visit(*this, *_breakIf.condition);
|
bytes result = std::visit(*this, *_branchIf.condition);
|
||||||
result += toBytes(Opcode::BrIf) + encodeLabelIdx(_breakIf.label.name);
|
result += toBytes(Opcode::BrIf) + encodeLabelIdx(_branchIf.label.name);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,8 +48,8 @@ public:
|
|||||||
bytes operator()(wasm::GlobalAssignment const& _assignment);
|
bytes operator()(wasm::GlobalAssignment const& _assignment);
|
||||||
bytes operator()(wasm::If const& _if);
|
bytes operator()(wasm::If const& _if);
|
||||||
bytes operator()(wasm::Loop const& _loop);
|
bytes operator()(wasm::Loop const& _loop);
|
||||||
bytes operator()(wasm::Break const& _break);
|
bytes operator()(wasm::Branch const& _branch);
|
||||||
bytes operator()(wasm::BreakIf const& _break);
|
bytes operator()(wasm::BranchIf const& _branchIf);
|
||||||
bytes operator()(wasm::Return const& _return);
|
bytes operator()(wasm::Return const& _return);
|
||||||
bytes operator()(wasm::Block const& _block);
|
bytes operator()(wasm::Block const& _block);
|
||||||
bytes operator()(wasm::FunctionDefinition const& _function);
|
bytes operator()(wasm::FunctionDefinition const& _function);
|
||||||
|
@ -121,14 +121,14 @@ string TextTransform::operator()(wasm::Loop const& _loop)
|
|||||||
return "(loop" + move(label) + "\n" + indented(joinTransformed(_loop.statements, '\n')) + ")\n";
|
return "(loop" + move(label) + "\n" + indented(joinTransformed(_loop.statements, '\n')) + ")\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
string TextTransform::operator()(wasm::Break const& _break)
|
string TextTransform::operator()(wasm::Branch const& _branch)
|
||||||
{
|
{
|
||||||
return "(br $" + _break.label.name + ")\n";
|
return "(br $" + _branch.label.name + ")\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
string TextTransform::operator()(wasm::BreakIf const& _break)
|
string TextTransform::operator()(wasm::BranchIf const& _branchIf)
|
||||||
{
|
{
|
||||||
return "(br_if $" + _break.label.name + " " + visit(*_break.condition) + ")\n";
|
return "(br_if $" + _branchIf.label.name + " " + visit(*_branchIf.condition) + ")\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
string TextTransform::operator()(wasm::Return const&)
|
string TextTransform::operator()(wasm::Return const&)
|
||||||
|
@ -48,9 +48,9 @@ public:
|
|||||||
std::string operator()(wasm::GlobalAssignment const& _assignment);
|
std::string operator()(wasm::GlobalAssignment const& _assignment);
|
||||||
std::string operator()(wasm::If const& _if);
|
std::string operator()(wasm::If const& _if);
|
||||||
std::string operator()(wasm::Loop const& _loop);
|
std::string operator()(wasm::Loop const& _loop);
|
||||||
std::string operator()(wasm::Break const& _break);
|
std::string operator()(wasm::Branch const& _branch);
|
||||||
|
std::string operator()(wasm::BranchIf const& _branchIf);
|
||||||
std::string operator()(wasm::Return const& _return);
|
std::string operator()(wasm::Return const& _return);
|
||||||
std::string operator()(wasm::BreakIf const& _break);
|
|
||||||
std::string operator()(wasm::Block const& _block);
|
std::string operator()(wasm::Block const& _block);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -41,13 +41,13 @@ struct GlobalAssignment;
|
|||||||
struct Block;
|
struct Block;
|
||||||
struct If;
|
struct If;
|
||||||
struct Loop;
|
struct Loop;
|
||||||
struct Break;
|
struct Branch;
|
||||||
struct BreakIf;
|
struct BranchIf;
|
||||||
struct Return;
|
struct Return;
|
||||||
using Expression = std::variant<
|
using Expression = std::variant<
|
||||||
Literal, StringLiteral, LocalVariable, GlobalVariable,
|
Literal, StringLiteral, LocalVariable, GlobalVariable,
|
||||||
FunctionCall, BuiltinCall, LocalAssignment, GlobalAssignment,
|
FunctionCall, BuiltinCall, LocalAssignment, GlobalAssignment,
|
||||||
Block, If, Loop, Break, BreakIf, Return
|
Block, If, Loop, Branch, BranchIf, Return
|
||||||
>;
|
>;
|
||||||
|
|
||||||
struct Literal { uint64_t value; };
|
struct Literal { uint64_t value; };
|
||||||
@ -66,9 +66,9 @@ struct If {
|
|||||||
std::unique_ptr<std::vector<Expression>> elseStatements;
|
std::unique_ptr<std::vector<Expression>> elseStatements;
|
||||||
};
|
};
|
||||||
struct Loop { std::string labelName; std::vector<Expression> statements; };
|
struct Loop { std::string labelName; std::vector<Expression> statements; };
|
||||||
struct Break { Label label; };
|
struct Branch { Label label; };
|
||||||
struct Return {};
|
struct Return {};
|
||||||
struct BreakIf { 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; };
|
||||||
struct GlobalVariableDeclaration { std::string variableName; };
|
struct GlobalVariableDeclaration { std::string variableName; };
|
||||||
|
@ -256,26 +256,26 @@ wasm::Expression WasmCodeTransform::operator()(ForLoop const& _for)
|
|||||||
wasm::Loop loop;
|
wasm::Loop loop;
|
||||||
loop.labelName = newLabel();
|
loop.labelName = newLabel();
|
||||||
loop.statements = visit(_for.pre.statements);
|
loop.statements = visit(_for.pre.statements);
|
||||||
loop.statements.emplace_back(wasm::BreakIf{wasm::Label{breakLabel}, make_unique<wasm::Expression>(
|
loop.statements.emplace_back(wasm::BranchIf{wasm::Label{breakLabel}, make_unique<wasm::Expression>(
|
||||||
wasm::BuiltinCall{"i64.eqz", make_vector<wasm::Expression>(
|
wasm::BuiltinCall{"i64.eqz", make_vector<wasm::Expression>(
|
||||||
visitReturnByValue(*_for.condition)
|
visitReturnByValue(*_for.condition)
|
||||||
)}
|
)}
|
||||||
)});
|
)});
|
||||||
loop.statements.emplace_back(wasm::Block{continueLabel, visit(_for.body.statements)});
|
loop.statements.emplace_back(wasm::Block{continueLabel, visit(_for.body.statements)});
|
||||||
loop.statements += visit(_for.post.statements);
|
loop.statements += visit(_for.post.statements);
|
||||||
loop.statements.emplace_back(wasm::Break{wasm::Label{loop.labelName}});
|
loop.statements.emplace_back(wasm::Branch{wasm::Label{loop.labelName}});
|
||||||
|
|
||||||
return { wasm::Block{breakLabel, make_vector<wasm::Expression>(move(loop))} };
|
return { wasm::Block{breakLabel, make_vector<wasm::Expression>(move(loop))} };
|
||||||
}
|
}
|
||||||
|
|
||||||
wasm::Expression WasmCodeTransform::operator()(Break const&)
|
wasm::Expression WasmCodeTransform::operator()(Break const&)
|
||||||
{
|
{
|
||||||
return wasm::Break{wasm::Label{m_breakContinueLabelNames.top().first}};
|
return wasm::Branch{wasm::Label{m_breakContinueLabelNames.top().first}};
|
||||||
}
|
}
|
||||||
|
|
||||||
wasm::Expression WasmCodeTransform::operator()(Continue const&)
|
wasm::Expression WasmCodeTransform::operator()(Continue const&)
|
||||||
{
|
{
|
||||||
return wasm::Break{wasm::Label{m_breakContinueLabelNames.top().second}};
|
return wasm::Branch{wasm::Label{m_breakContinueLabelNames.top().second}};
|
||||||
}
|
}
|
||||||
|
|
||||||
wasm::Expression WasmCodeTransform::operator()(Leave const&)
|
wasm::Expression WasmCodeTransform::operator()(Leave const&)
|
||||||
|
@ -11,3 +11,4 @@ compilability
|
|||||||
errorstring
|
errorstring
|
||||||
hist
|
hist
|
||||||
otion
|
otion
|
||||||
|
keypair
|
||||||
|
@ -13,7 +13,7 @@ import hashlib
|
|||||||
from os.path import join, isfile
|
from os.path import join, isfile
|
||||||
|
|
||||||
def extract_test_cases(path):
|
def extract_test_cases(path):
|
||||||
lines = open(path, mode='r', encoding='utf8').read().splitlines()
|
lines = open(path, encoding="utf8", errors='ignore', mode='r').read().splitlines()
|
||||||
|
|
||||||
inside = False
|
inside = False
|
||||||
delimiter = ''
|
delimiter = ''
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
## You can pass a branch name as argument to this script (which, if no argument is given,
|
## You can pass a branch name as argument to this script (which, if no argument is given,
|
||||||
## will default to "develop").
|
## will default to "develop").
|
||||||
##
|
##
|
||||||
## If the gien branch is "release", the resulting package will be uplaoded to
|
## If the given branch is "release", the resulting package will be uploaded to
|
||||||
## ethereum/ethereum PPA, or ethereum/ethereum-dev PPA otherwise.
|
## ethereum/ethereum PPA, or ethereum/ethereum-dev PPA otherwise.
|
||||||
##
|
##
|
||||||
## The gnupg key for "builds@ethereum.org" has to be present in order to sign
|
## The gnupg key for "builds@ethereum.org" has to be present in order to sign
|
||||||
|
@ -8,7 +8,7 @@ from os.path import join, isfile
|
|||||||
|
|
||||||
|
|
||||||
def extract_test_cases(path):
|
def extract_test_cases(path):
|
||||||
lines = open(path, 'rb').read().splitlines()
|
lines = open(path, encoding="utf8", errors='ignore', mode='rb').read().splitlines()
|
||||||
|
|
||||||
inside = False
|
inside = False
|
||||||
delimiter = ''
|
delimiter = ''
|
||||||
|
11
test/cmdlineTests/message_format_utf16/err
Normal file
11
test/cmdlineTests/message_format_utf16/err
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: <SPDX-License>" to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information.
|
||||||
|
--> message_format_utf16/input.sol
|
||||||
|
|
||||||
|
Warning: Source file does not specify required compiler version!
|
||||||
|
--> message_format_utf16/input.sol
|
||||||
|
|
||||||
|
Warning: Statement has no effect.
|
||||||
|
--> message_format_utf16/input.sol:2:58:
|
||||||
|
|
|
||||||
|
2 | /* ©©©©ᄅ©©©©© 2017 */ constructor () public { "©©©©ᄅ©©©©©" ; }
|
||||||
|
| ^^^^^^^^^^^^
|
3
test/cmdlineTests/message_format_utf16/input.sol
Normal file
3
test/cmdlineTests/message_format_utf16/input.sol
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
contract Foo {
|
||||||
|
/* ©©©©ᄅ©©©©© 2017 */ constructor () public { "©©©©ᄅ©©©©©" ; }
|
||||||
|
}
|
@ -193,7 +193,7 @@ contract ico is safeMath {
|
|||||||
|
|
||||||
function setICOEthPrice(uint256 value) external {
|
function setICOEthPrice(uint256 value) external {
|
||||||
/*
|
/*
|
||||||
Setting of the ICO ETC USD rates which can only be calle by a pre-defined address.
|
Setting of the ICO ETC USD rates which can only be called by a pre-defined address.
|
||||||
After this function is completed till the call of the next function (which is at least an exchangeRateDelay array) this rate counts.
|
After this function is completed till the call of the next function (which is at least an exchangeRateDelay array) this rate counts.
|
||||||
With this process avoiding the sudden rate changes.
|
With this process avoiding the sudden rate changes.
|
||||||
|
|
||||||
@ -221,8 +221,8 @@ contract ico is safeMath {
|
|||||||
/*
|
/*
|
||||||
Closing the ICO.
|
Closing the ICO.
|
||||||
It is only possible when the ICO period passed and only by the owner.
|
It is only possible when the ICO period passed and only by the owner.
|
||||||
The 96% of the whole amount of the token is generated to the address of the fundation.
|
The 96% of the whole amount of the token is generated to the address of the foundation.
|
||||||
Ethers which are situated in this contract will be sent to the address of the fundation.
|
Ethers which are situated in this contract will be sent to the address of the foundation.
|
||||||
*/
|
*/
|
||||||
require( msg.sender == owner );
|
require( msg.sender == owner );
|
||||||
require( block.number > icoDelay );
|
require( block.number > icoDelay );
|
||||||
|
@ -826,8 +826,8 @@ BOOST_AUTO_TEST_CASE(block_deduplicator)
|
|||||||
Instruction::JUMP,
|
Instruction::JUMP,
|
||||||
AssemblyItem(Tag, 3)
|
AssemblyItem(Tag, 3)
|
||||||
};
|
};
|
||||||
BlockDeduplicator dedup(input);
|
BlockDeduplicator deduplicator(input);
|
||||||
dedup.deduplicate();
|
deduplicator.deduplicate();
|
||||||
|
|
||||||
set<u256> pushTags;
|
set<u256> pushTags;
|
||||||
for (AssemblyItem const& item: input)
|
for (AssemblyItem const& item: input)
|
||||||
@ -857,8 +857,8 @@ BOOST_AUTO_TEST_CASE(block_deduplicator_assign_immutable_same)
|
|||||||
AssemblyItem(PushTag, 1),
|
AssemblyItem(PushTag, 1),
|
||||||
AssemblyItem(PushTag, 1),
|
AssemblyItem(PushTag, 1),
|
||||||
} + blocks;
|
} + blocks;
|
||||||
BlockDeduplicator dedup(input);
|
BlockDeduplicator deduplicator(input);
|
||||||
dedup.deduplicate();
|
deduplicator.deduplicate();
|
||||||
BOOST_CHECK_EQUAL_COLLECTIONS(input.begin(), input.end(), output.begin(), output.end());
|
BOOST_CHECK_EQUAL_COLLECTIONS(input.begin(), input.end(), output.begin(), output.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -876,8 +876,8 @@ BOOST_AUTO_TEST_CASE(block_deduplicator_assign_immutable_different_value)
|
|||||||
AssemblyItem{AssignImmutable, 0x1234},
|
AssemblyItem{AssignImmutable, 0x1234},
|
||||||
Instruction::JUMP
|
Instruction::JUMP
|
||||||
};
|
};
|
||||||
BlockDeduplicator dedup(input);
|
BlockDeduplicator deduplicator(input);
|
||||||
BOOST_CHECK(!dedup.deduplicate());
|
BOOST_CHECK(!deduplicator.deduplicate());
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(block_deduplicator_assign_immutable_different_hash)
|
BOOST_AUTO_TEST_CASE(block_deduplicator_assign_immutable_different_hash)
|
||||||
@ -894,8 +894,8 @@ BOOST_AUTO_TEST_CASE(block_deduplicator_assign_immutable_different_hash)
|
|||||||
AssemblyItem{AssignImmutable, 0xABCD},
|
AssemblyItem{AssignImmutable, 0xABCD},
|
||||||
Instruction::JUMP
|
Instruction::JUMP
|
||||||
};
|
};
|
||||||
BlockDeduplicator dedup(input);
|
BlockDeduplicator deduplicator(input);
|
||||||
BOOST_CHECK(!dedup.deduplicate());
|
BOOST_CHECK(!deduplicator.deduplicate());
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(block_deduplicator_loops)
|
BOOST_AUTO_TEST_CASE(block_deduplicator_loops)
|
||||||
@ -920,8 +920,8 @@ BOOST_AUTO_TEST_CASE(block_deduplicator_loops)
|
|||||||
AssemblyItem(PushTag, 2),
|
AssemblyItem(PushTag, 2),
|
||||||
Instruction::JUMP,
|
Instruction::JUMP,
|
||||||
};
|
};
|
||||||
BlockDeduplicator dedup(input);
|
BlockDeduplicator deduplicator(input);
|
||||||
dedup.deduplicate();
|
deduplicator.deduplicate();
|
||||||
|
|
||||||
set<u256> pushTags;
|
set<u256> pushTags;
|
||||||
for (AssemblyItem const& item: input)
|
for (AssemblyItem const& item: input)
|
||||||
|
@ -78,6 +78,81 @@ private:
|
|||||||
|
|
||||||
BOOST_FIXTURE_TEST_SUITE(SolidityNatspecJSON, DocumentationChecker)
|
BOOST_FIXTURE_TEST_SUITE(SolidityNatspecJSON, DocumentationChecker)
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(user_empty_natspec_test)
|
||||||
|
{
|
||||||
|
char const* sourceCode = R"(
|
||||||
|
contract test {
|
||||||
|
///
|
||||||
|
///
|
||||||
|
function f() public {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
char const* natspec = R"(
|
||||||
|
{
|
||||||
|
"methods": {}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
checkNatspec(sourceCode, "test", natspec, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(user_newline_break)
|
||||||
|
{
|
||||||
|
char const* sourceCode = R"(
|
||||||
|
contract test {
|
||||||
|
///
|
||||||
|
/// @notice hello
|
||||||
|
|
||||||
|
/// @notice world
|
||||||
|
function f() public {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
char const* natspec = R"ABCDEF(
|
||||||
|
{
|
||||||
|
"methods": {
|
||||||
|
"f()":
|
||||||
|
{
|
||||||
|
"notice": "world"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)ABCDEF";
|
||||||
|
|
||||||
|
checkNatspec(sourceCode, "test", natspec, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(user_multiline_empty_lines)
|
||||||
|
{
|
||||||
|
char const* sourceCode = R"(
|
||||||
|
contract test {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @notice hello world
|
||||||
|
*/
|
||||||
|
function f() public {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
char const* natspec = R"ABCDEF(
|
||||||
|
{
|
||||||
|
"methods": {
|
||||||
|
"f()": {
|
||||||
|
"notice": "hello world"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)ABCDEF";
|
||||||
|
|
||||||
|
checkNatspec(sourceCode, "test", natspec, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(user_basic_test)
|
BOOST_AUTO_TEST_CASE(user_basic_test)
|
||||||
{
|
{
|
||||||
char const* sourceCode = R"(
|
char const* sourceCode = R"(
|
||||||
|
@ -361,7 +361,7 @@ BOOST_AUTO_TEST_CASE(multiline_documentation_comments_parsed)
|
|||||||
BOOST_CHECK_EQUAL(scanner.next(), Token::Identifier);
|
BOOST_CHECK_EQUAL(scanner.next(), Token::Identifier);
|
||||||
BOOST_CHECK_EQUAL(scanner.next(), Token::Identifier);
|
BOOST_CHECK_EQUAL(scanner.next(), Token::Identifier);
|
||||||
BOOST_CHECK_EQUAL(scanner.next(), Token::EOS);
|
BOOST_CHECK_EQUAL(scanner.next(), Token::EOS);
|
||||||
BOOST_CHECK_EQUAL(scanner.currentCommentLiteral(), "Send $(value / 1000) chocolates to the user");
|
BOOST_CHECK_EQUAL(scanner.currentCommentLiteral(), " Send $(value / 1000) chocolates to the user");
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(multiline_documentation_no_stars)
|
BOOST_AUTO_TEST_CASE(multiline_documentation_no_stars)
|
||||||
@ -385,7 +385,7 @@ BOOST_AUTO_TEST_CASE(multiline_documentation_whitespace_hell)
|
|||||||
BOOST_CHECK_EQUAL(scanner.next(), Token::Identifier);
|
BOOST_CHECK_EQUAL(scanner.next(), Token::Identifier);
|
||||||
BOOST_CHECK_EQUAL(scanner.next(), Token::Identifier);
|
BOOST_CHECK_EQUAL(scanner.next(), Token::Identifier);
|
||||||
BOOST_CHECK_EQUAL(scanner.next(), Token::EOS);
|
BOOST_CHECK_EQUAL(scanner.next(), Token::EOS);
|
||||||
BOOST_CHECK_EQUAL(scanner.currentCommentLiteral(), "Send $(value / 1000) chocolates to the user");
|
BOOST_CHECK_EQUAL(scanner.currentCommentLiteral(), " Send $(value / 1000) chocolates to the user");
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(comment_before_eos)
|
BOOST_AUTO_TEST_CASE(comment_before_eos)
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
library L {
|
||||||
|
function equals(address a, address b) internal pure returns (bool) {
|
||||||
|
return a == b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
using L for address;
|
||||||
|
|
||||||
|
function foo(address a, address b) public returns (bool) {
|
||||||
|
return a.equals(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// foo(address, address): 0x111122223333444455556666777788889999aAaa, 0x111122223333444455556666777788889999aAaa -> true
|
||||||
|
// foo(address, address): 0x111122223333444455556666777788889999aAaa, 0x0000000000000000000000000000000000000000 -> false
|
@ -0,0 +1,21 @@
|
|||||||
|
library L {
|
||||||
|
function transfer(address a) internal {}
|
||||||
|
function send(address a) internal {}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
using L for address;
|
||||||
|
|
||||||
|
function useTransfer(address a) public {
|
||||||
|
a.transfer();
|
||||||
|
}
|
||||||
|
|
||||||
|
function useSend(address a) public {
|
||||||
|
a.send();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// useTransfer(address): 0x111122223333444455556666777788889999aAaa ->
|
||||||
|
// useSend(address): 0x111122223333444455556666777788889999aAaa ->
|
@ -0,0 +1,19 @@
|
|||||||
|
library L {
|
||||||
|
function pop(uint[2] memory a) internal {}
|
||||||
|
function push(uint[2] memory a) internal {}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
using L for uint[2];
|
||||||
|
|
||||||
|
function test() public {
|
||||||
|
uint[2] memory input;
|
||||||
|
|
||||||
|
input.push();
|
||||||
|
input.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// test() ->
|
@ -0,0 +1,20 @@
|
|||||||
|
library L {
|
||||||
|
function xor(bool a, bool b) internal pure returns (bool) {
|
||||||
|
return a != b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
using L for bool;
|
||||||
|
|
||||||
|
function foo(bool a, bool b) public returns (bool) {
|
||||||
|
return a.xor(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// foo(bool, bool): true, true -> false
|
||||||
|
// foo(bool, bool): true, false -> true
|
||||||
|
// foo(bool, bool): false, true -> true
|
||||||
|
// foo(bool, bool): false, false -> false
|
@ -0,0 +1,21 @@
|
|||||||
|
contract E {}
|
||||||
|
|
||||||
|
library L {
|
||||||
|
function foo(E e) internal pure returns (uint) {
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
using L for E;
|
||||||
|
|
||||||
|
function test() public returns (uint) {
|
||||||
|
E e = new E();
|
||||||
|
return e.foo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// test() -> 42
|
@ -0,0 +1,21 @@
|
|||||||
|
library L {
|
||||||
|
function at(uint[] memory a, uint i) internal pure returns (uint) {
|
||||||
|
return a[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
using L for uint[];
|
||||||
|
|
||||||
|
function secondItem() public returns (uint) {
|
||||||
|
uint[] memory input = new uint[](2);
|
||||||
|
input[0] = 0x11;
|
||||||
|
input[1] = 0x22;
|
||||||
|
|
||||||
|
return input.at(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// secondItem() -> 0x22
|
@ -0,0 +1,21 @@
|
|||||||
|
library L {
|
||||||
|
enum E { A, B }
|
||||||
|
|
||||||
|
function equals(E a, E b) internal pure returns (bool) {
|
||||||
|
return a == b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
using L for L.E;
|
||||||
|
|
||||||
|
function equalsA(uint choice) public returns (bool) {
|
||||||
|
L.E x = L.E.A;
|
||||||
|
return x.equals(L.E(choice));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// equalsA(uint256): 0 -> true
|
||||||
|
// equalsA(uint256): 1 -> false
|
@ -0,0 +1,23 @@
|
|||||||
|
library L {
|
||||||
|
// NOTE: External function takes up two stack slots
|
||||||
|
function double(function(uint) external pure returns (uint) f, uint x) internal pure returns (uint) {
|
||||||
|
return f(x) * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
using L for function(uint) external pure returns (uint);
|
||||||
|
|
||||||
|
function identity(uint x) external pure returns (uint) {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
function test(uint value) public returns (uint) {
|
||||||
|
return this.identity.double(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// test(uint256): 5 -> 10
|
@ -0,0 +1,21 @@
|
|||||||
|
library L {
|
||||||
|
function at(uint[2] memory a, uint i) internal pure returns (uint) {
|
||||||
|
return a[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
using L for uint[2];
|
||||||
|
|
||||||
|
function secondItem() public returns (uint) {
|
||||||
|
uint[2] memory input;
|
||||||
|
input[0] = 0x11;
|
||||||
|
input[1] = 0x22;
|
||||||
|
|
||||||
|
return input.at(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// secondItem() -> 0x22
|
@ -0,0 +1,17 @@
|
|||||||
|
library L {
|
||||||
|
function add(bytes2 a, bytes2 b) internal pure returns (bytes2) {
|
||||||
|
return bytes2(uint16(a) + uint16(b));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
using L for bytes2;
|
||||||
|
|
||||||
|
function sum(bytes2 a, bytes2 b) public returns (bytes2) {
|
||||||
|
return a.add(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// sum(bytes2, bytes2): left(0x1100), left(0x0022) -> left(0x1122)
|
@ -0,0 +1,22 @@
|
|||||||
|
library L {
|
||||||
|
function selector(function(uint) internal pure returns (uint) f, uint x) internal pure returns (uint) {
|
||||||
|
return f(x) * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
using L for function(uint) internal pure returns (uint);
|
||||||
|
|
||||||
|
function identity(uint x) internal pure returns (uint) {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
function test(uint value) public returns (uint) {
|
||||||
|
return identity.selector(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// test(uint256): 5 -> 10
|
@ -0,0 +1,17 @@
|
|||||||
|
library L {
|
||||||
|
function add(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||||
|
return a + b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
using L for uint256;
|
||||||
|
|
||||||
|
function foo(uint256 a, uint256 b) public returns (uint256) {
|
||||||
|
return a.add(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// foo(uint256, uint256): 8, 42 -> 50
|
@ -0,0 +1,22 @@
|
|||||||
|
interface I {}
|
||||||
|
contract E is I {}
|
||||||
|
|
||||||
|
library L {
|
||||||
|
function foo(I i) internal pure returns (uint) {
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
using L for I;
|
||||||
|
|
||||||
|
function test() public returns (uint) {
|
||||||
|
E e = new E();
|
||||||
|
return I(e).foo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// test() -> 42
|
@ -0,0 +1,22 @@
|
|||||||
|
library L {
|
||||||
|
function double(function(uint) internal pure returns (uint) f, uint x) internal pure returns (uint) {
|
||||||
|
return f(x) * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
using L for function(uint) internal pure returns (uint);
|
||||||
|
|
||||||
|
function identity(uint x) internal pure returns (uint) {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
function test(uint value) public returns (uint) {
|
||||||
|
return identity.double(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// test(uint256): 5 -> 10
|
@ -0,0 +1,22 @@
|
|||||||
|
library L {
|
||||||
|
function at(mapping(uint => uint) storage a, uint i) internal view returns (uint) {
|
||||||
|
return a[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
using L for mapping(uint => uint);
|
||||||
|
|
||||||
|
mapping(uint => uint) map;
|
||||||
|
|
||||||
|
function mapValue(uint a) public returns (uint) {
|
||||||
|
map[42] = 0x24;
|
||||||
|
map[66] = 0x66;
|
||||||
|
|
||||||
|
return map.at(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// mapValue(uint256): 42 -> 0x24
|
@ -0,0 +1,18 @@
|
|||||||
|
library L {
|
||||||
|
function at(string memory a, uint i) internal pure returns (uint8) {
|
||||||
|
return uint8(bytes(a)[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
using L for string;
|
||||||
|
|
||||||
|
function secondChar() public returns (uint8) {
|
||||||
|
string memory input = "abc";
|
||||||
|
return input.at(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// secondChar() -> 98
|
17
test/libsolidity/smtCheckerTests/types/unused_mapping.sol
Normal file
17
test/libsolidity/smtCheckerTests/types/unused_mapping.sol
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
pragma experimental SMTChecker;
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
uint x;
|
||||||
|
uint y;
|
||||||
|
mapping (address => bool) public never_used;
|
||||||
|
|
||||||
|
function inc() public {
|
||||||
|
require(x < 10);
|
||||||
|
require(y < 10);
|
||||||
|
|
||||||
|
if(x == 0) x = 0; // noop state var read
|
||||||
|
x++;
|
||||||
|
y++;
|
||||||
|
assert(y == x);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
contract Test {
|
||||||
|
struct shouldBug {
|
||||||
|
bytes[2] deadly;
|
||||||
|
}
|
||||||
|
function killer(bytes[2] calldata weapon) pure external {
|
||||||
|
shouldBug(weapon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// UnimplementedFeatureError: Copying nested dynamic calldata arrays to memory is not implemented in the old code generator.
|
@ -0,0 +1,13 @@
|
|||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
contract Test {
|
||||||
|
struct shouldBug {
|
||||||
|
uint256[][2] deadly;
|
||||||
|
}
|
||||||
|
function killer(uint256[][2] calldata weapon) pure external {
|
||||||
|
shouldBug(weapon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// UnimplementedFeatureError: Copying nested dynamic calldata arrays to memory is not implemented in the old code generator.
|
@ -0,0 +1,13 @@
|
|||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
contract Test {
|
||||||
|
struct shouldBug {
|
||||||
|
uint256[][] deadly;
|
||||||
|
}
|
||||||
|
function killer(uint256[][] calldata weapon) pure external {
|
||||||
|
shouldBug(weapon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// UnimplementedFeatureError: Copying nested dynamic calldata arrays to memory is not implemented in the old code generator.
|
@ -0,0 +1,9 @@
|
|||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
uint[][2] tmp_i;
|
||||||
|
function i(uint[][2] calldata s) external { tmp_i = s; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// UnimplementedFeatureError: Copying nested calldata dynamic arrays to storage is not implemented in the old code generator.
|
@ -0,0 +1,9 @@
|
|||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
uint[][] tmp_i;
|
||||||
|
function i(uint[][] calldata s) external { tmp_i = s; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// UnimplementedFeatureError: Copying nested calldata dynamic arrays to storage is not implemented in the old code generator.
|
@ -0,0 +1,7 @@
|
|||||||
|
contract C {
|
||||||
|
///
|
||||||
|
///
|
||||||
|
function vote(uint id) public {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
Loading…
Reference in New Issue
Block a user