Merge branch 'origin/develop' into develop_060

This commit is contained in:
chriseth 2019-10-02 16:29:36 +02:00
commit f884373142
21 changed files with 175 additions and 50 deletions

View File

@ -115,6 +115,17 @@ defaults:
- store_test_results: *store_test_results
- store_artifacts: *artifacts_test_results
- test_ubuntu1904_clang: &test_ubuntu1904_clang
docker:
- image: ethereum/solidity-buildpack-deps:ubuntu1904-clang
steps:
- checkout
- attach_workspace:
at: build
- run: *run_soltest
- store_test_results: *store_test_results
- store_artifacts: *artifacts_test_results
- test_ubuntu1904_all: &test_ubuntu1904
docker:
- image: ethereum/solidity-buildpack-deps:ubuntu1904
@ -151,6 +162,11 @@ defaults:
requires:
- b_ubu
- workflow_ubuntu1904_clang: &workflow_ubuntu1904_clang
<<: *workflow_trigger_on_tags
requires:
- b_ubu_clang
- workflow_ubuntu1904_release: &workflow_ubuntu1904_release
<<: *workflow_trigger_on_tags
requires:
@ -280,6 +296,18 @@ jobs:
pip install --user z3-solver
- run: *run_proofs
b_ubu_clang: &build_ubuntu1904_clang
docker:
- image: ethereum/solidity-buildpack-deps:ubuntu1904-clang
environment:
CC: clang
CXX: clang++
steps:
- checkout
- run: *run_build
- store_artifacts: *artifacts_solc
- persist_to_workspace: *artifacts_executables
b_ubu: &build_ubuntu1904
docker:
- image: ethereum/solidity-buildpack-deps:ubuntu1904
@ -349,11 +377,11 @@ jobs:
- run: *run_build
b_ubu_ossfuzz:
<<: *build_ubuntu1904
<<: *build_ubuntu1904_clang
environment:
TERM: xterm
CC: /usr/bin/clang-8
CXX: /usr/bin/clang++-8
CC: clang
CXX: clang++
CMAKE_OPTIONS: -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/libfuzzer.cmake
steps:
- checkout
@ -362,7 +390,7 @@ jobs:
- persist_to_workspace: *artifacts_executables_ossfuzz
t_ubu_ossfuzz: &t_ubu_ossfuzz
<<: *test_ubuntu1904
<<: *test_ubuntu1904_clang
steps:
- checkout
- attach_workspace:
@ -495,6 +523,12 @@ jobs:
t_ubu_soltest: &t_ubu_soltest
<<: *test_ubuntu1904
t_ubu_clang_soltest: &t_ubu_clang_soltest
<<: *test_ubuntu1904_clang
environment:
EVM: constantinople
OPTIMIZE: 0
t_ubu_release_soltest: &t_ubu_release_soltest
<<: *t_ubu_soltest
@ -632,6 +666,8 @@ workflows:
- b_ubu18: *workflow_trigger_on_tags
- t_ubu_cli: *workflow_ubuntu1904
- t_ubu_soltest: *workflow_ubuntu1904
- b_ubu_clang: *workflow_trigger_on_tags
- t_ubu_clang_soltest: *workflow_ubuntu1904_clang
# Ubuntu fake release build and tests
- b_ubu_release: *workflow_trigger_on_tags

View File

@ -28,7 +28,9 @@ Compiler Features:
Bugfixes:
### 0.5.12 (unreleased)
### 0.5.13 (unreleased)
### 0.5.12 (2019-10-01)
Language Features:
* Type Checker: Allow assignment to external function arguments except for reference types.
@ -43,7 +45,10 @@ Compiler Features:
Bugfixes:
* Fix internal error when popping a dynamic storage array of mappings.
* Code Generator: Fix internal error when popping a dynamic storage array of mappings.
* Name Resolver: Fix wrong source location when warning on shadowed aliases in import declarations.
* Scanner: Fix multi-line natspec comment parsing with triple slashes when file is encoded with CRLF instead of LF.
* Type System: Fix arrays of recursive structs.
* Yul Optimizer: Fix reordering bug in connection with shifted one and mul/div-instructions in for loop conditions.

View File

@ -1,7 +1,7 @@
# Inherit default options
include("${CMAKE_CURRENT_LIST_DIR}/default.cmake")
# Disable Z3 and CVC4 since none of the existing fuzzers need them
set(USE_Z3 OFF CACHE BOOL "Disable Z3" FORCE)
# Enable Z3, disable CVC4
set(USE_Z3 ON CACHE BOOL "Enable Z3" FORCE)
set(USE_CVC4 OFF CACHE BOOL "Disable CVC4" FORCE)
# Build fuzzing binaries
set(OSSFUZZ ON CACHE BOOL "Enable fuzzer build" FORCE)

View File

@ -444,16 +444,16 @@ JSON
The JSON format for a contract's interface is given by an array of function and/or event descriptions.
A function description is a JSON object with the fields:
- ``type``: ``"function"``, ``"constructor"``, or ``"fallback"`` (the :ref:`unnamed "default" function <fallback-function>`);
- ``name``: the name of the function;
- ``type``: ``"function"``, ``"constructor"``, or ``"fallback"`` (the :ref:`unnamed "default" function <fallback-function>`).
- ``name``: the name of the function.
- ``inputs``: an array of objects, each of which contains:
* ``name``: the name of the parameter;
* ``name``: the name of the parameter.
* ``type``: the canonical type of the parameter (more below).
* ``components``: used for tuple types (more below).
- ``outputs``: an array of objects similar to ``inputs``, can be omitted if function doesn't return anything;
- ``stateMutability``: a string with one of the following values: ``pure`` (:ref:`specified to not read blockchain state <pure-functions>`), ``view`` (:ref:`specified to not modify the blockchain state <view-functions>`), ``nonpayable`` (function does not accept Ether) and ``payable`` (function accepts Ether);
- ``outputs``: an array of objects similar to ``inputs``.
- ``stateMutability``: a string with one of the following values: ``pure`` (:ref:`specified to not read blockchain state <pure-functions>`), ``view`` (:ref:`specified to not modify the blockchain state <view-functions>`), ``nonpayable`` (function does not accept Ether) and ``payable`` (function accepts Ether).
Constructor and fallback function never have ``name`` or ``outputs``. Fallback function doesn't have ``inputs`` either.
@ -463,10 +463,10 @@ Constructor and fallback function never have ``name`` or ``outputs``. Fallback f
An event description is a JSON object with fairly similar fields:
- ``type``: always ``"event"``
- ``name``: the name of the event;
- ``name``: the name of the event.
- ``inputs``: an array of objects, each of which contains:
* ``name``: the name of the parameter;
* ``name``: the name of the parameter.
* ``type``: the canonical type of the parameter (more below).
* ``components``: used for tuple types (more below).
* ``indexed``: ``true`` if the field is part of the log's topics, ``false`` if it one of the log's data segment.

View File

@ -750,6 +750,10 @@
"bugs": [],
"released": "2019-08-12"
},
"0.5.12": {
"bugs": [],
"released": "2019-10-01"
},
"0.5.2": {
"bugs": [
"SignedArrayStorageCopy",

View File

@ -37,3 +37,7 @@ add_library(devcore ${sources})
target_link_libraries(devcore PUBLIC jsoncpp Boost::boost Boost::filesystem Boost::regex Boost::system)
target_include_directories(devcore PUBLIC "${CMAKE_SOURCE_DIR}")
add_dependencies(devcore solidity_BuildInfo.h)
if(SOLC_LINK_STATIC)
target_link_libraries(devcore PUBLIC Threads::Threads)
endif()

View File

@ -30,11 +30,6 @@ inline bool isHexDigit(char c)
('A' <= c && c <= 'F');
}
inline bool isLineTerminator(char c)
{
return c == '\n';
}
inline bool isWhiteSpace(char c)
{
return c == ' ' || c == '\n' || c == '\t' || c == '\r';

View File

@ -280,6 +280,29 @@ Token Scanner::skipSingleLineComment()
return Token::Whitespace;
}
bool Scanner::atEndOfLine() const
{
return m_char == '\n' || m_char == '\r';
}
bool Scanner::tryScanEndOfLine()
{
if (m_char == '\n')
{
advance();
return true;
}
if (m_char == '\r')
{
if (advance() && m_char == '\n')
advance();
return true;
}
return false;
}
Token Scanner::scanSingleLineDocComment()
{
LiteralScope literal(this, LITERAL_TYPE_COMMENT);
@ -289,7 +312,7 @@ Token Scanner::scanSingleLineDocComment()
while (!isSourcePastEndOfInput())
{
if (isLineTerminator(m_char))
if (tryScanEndOfLine())
{
// check if next line is also a documentation comment
skipWhitespace();
@ -303,7 +326,6 @@ Token Scanner::scanSingleLineDocComment()
}
else
break; // next line is not a documentation comment, we are done
}
else if (isUnicodeLinebreak())
// Any line terminator that is not '\n' is considered to end the
@ -343,13 +365,13 @@ Token Scanner::scanMultiLineDocComment()
bool endFound = false;
bool charsAdded = false;
while (isWhiteSpace(m_char) && !isLineTerminator(m_char))
while (isWhiteSpace(m_char) && !atEndOfLine())
advance();
while (!isSourcePastEndOfInput())
{
//handle newlines in multline comments
if (isLineTerminator(m_char))
if (atEndOfLine())
{
skipWhitespace();
if (!m_source->isPastEndOfInput(1) && m_source->get(0) == '*' && m_source->get(1) == '*')
@ -664,10 +686,12 @@ void Scanner::scanToken()
bool Scanner::scanEscape()
{
char c = m_char;
advance();
// Skip escaped newlines.
if (isLineTerminator(c))
if (tryScanEndOfLine())
return true;
advance();
switch (c)
{
case '\'': // fall through

View File

@ -219,6 +219,12 @@ private:
Token skipSingleLineComment();
Token skipMultiLineComment();
/// Tests if current source position is CR, LF or CRLF.
bool atEndOfLine() const;
/// Tries to consume CR, LF or CRLF line terminators and returns success or failure.
bool tryScanEndOfLine();
void scanDecimalDigits();
Token scanNumber(char _charSeen = 0);
std::tuple<Token, unsigned, unsigned> scanIdentifierOrKeyword();

View File

@ -91,13 +91,13 @@ bool NameAndTypeResolver::performImports(SourceUnit& _sourceUnit, map<string, So
if (!imp->symbolAliases().empty())
for (auto const& alias: imp->symbolAliases())
{
auto declarations = scope->second->resolveName(alias.first->name(), false);
auto declarations = scope->second->resolveName(alias.symbol->name(), false);
if (declarations.empty())
{
m_errorReporter.declarationError(
imp->location(),
"Declaration \"" +
alias.first->name() +
alias.symbol->name() +
"\" not found in \"" +
path +
"\" (referenced as \"" +
@ -109,7 +109,7 @@ bool NameAndTypeResolver::performImports(SourceUnit& _sourceUnit, map<string, So
else
for (Declaration const* declaration: declarations)
if (!DeclarationRegistrationHelper::registerDeclaration(
target, *declaration, alias.second.get(), &imp->location(), true, false, m_errorReporter
target, *declaration, alias.alias.get(), &alias.location, true, false, m_errorReporter
))
error = true;
}
@ -523,7 +523,7 @@ bool DeclarationRegistrationHelper::registerDeclaration(
{
if (dynamic_cast<MagicVariableDeclaration const*>(shadowedDeclaration))
_errorReporter.warning(
_declaration.location(),
*_errorLocation,
"This declaration shadows a builtin symbol."
);
else

View File

@ -280,22 +280,31 @@ private:
class ImportDirective: public Declaration
{
public:
struct SymbolAlias
{
ASTPointer<Identifier> symbol;
ASTPointer<ASTString> alias;
SourceLocation location;
};
using SymbolAliasList = std::vector<SymbolAlias>;
ImportDirective(
SourceLocation const& _location,
ASTPointer<ASTString> const& _path,
ASTPointer<ASTString> const& _unitAlias,
std::vector<std::pair<ASTPointer<Identifier>, ASTPointer<ASTString>>>&& _symbolAliases
SymbolAliasList _symbolAliases
):
Declaration(_location, _unitAlias),
m_path(_path),
m_symbolAliases(_symbolAliases)
m_symbolAliases(move(_symbolAliases))
{ }
void accept(ASTVisitor& _visitor) override;
void accept(ASTConstVisitor& _visitor) const override;
ASTString const& path() const { return *m_path; }
std::vector<std::pair<ASTPointer<Identifier>, ASTPointer<ASTString>>> const& symbolAliases() const
SymbolAliasList const& symbolAliases() const
{
return m_symbolAliases;
}
@ -306,9 +315,9 @@ public:
private:
ASTPointer<ASTString> m_path;
/// The aliases for the specific symbols to import. If non-empty import the specific symbols.
/// If the second component is empty, import the identifier unchanged.
/// If the `alias` component is empty, import the identifier unchanged.
/// If both m_unitAlias and m_symbolAlias are empty, import all symbols into the current scope.
std::vector<std::pair<ASTPointer<Identifier>, ASTPointer<ASTString>>> m_symbolAliases;
SymbolAliasList m_symbolAliases;
};
/**

View File

@ -243,9 +243,9 @@ bool ASTJsonConverter::visit(ImportDirective const& _node)
for (auto const& symbolAlias: _node.symbolAliases())
{
Json::Value tuple(Json::objectValue);
solAssert(symbolAlias.first, "");
tuple["foreign"] = nodeId(*symbolAlias.first);
tuple["local"] = symbolAlias.second ? Json::Value(*symbolAlias.second) : Json::nullValue;
solAssert(symbolAlias.symbol, "");
tuple["foreign"] = nodeId(*symbolAlias.symbol);
tuple["local"] = symbolAlias.alias ? Json::Value(*symbolAlias.alias) : Json::nullValue;
symbolAliases.append(tuple);
}
attributes.emplace_back("symbolAliases", std::move(symbolAliases));

View File

@ -2086,6 +2086,8 @@ unsigned StructType::calldataOffsetOfMember(std::string const& _member) const
bool StructType::isDynamicallyEncoded() const
{
if (recursive())
return true;
solAssert(interfaceType(false).get(), "");
for (auto t: memoryMemberTypes())
{

View File

@ -186,7 +186,7 @@ ASTPointer<ImportDirective> Parser::parseImportDirective()
expectToken(Token::Import);
ASTPointer<ASTString> path;
ASTPointer<ASTString> unitAlias = make_shared<string>();
vector<pair<ASTPointer<Identifier>, ASTPointer<ASTString>>> symbolAliases;
ImportDirective::SymbolAliasList symbolAliases;
if (m_scanner->currentToken() == Token::StringLiteral)
{
@ -204,14 +204,16 @@ ASTPointer<ImportDirective> Parser::parseImportDirective()
m_scanner->next();
while (true)
{
ASTPointer<Identifier> id = parseIdentifier();
ASTPointer<ASTString> alias;
SourceLocation aliasLocation = SourceLocation{position(), endPosition(), source()};
ASTPointer<Identifier> id = parseIdentifier();
if (m_scanner->currentToken() == Token::As)
{
expectToken(Token::As);
aliasLocation = SourceLocation{position(), endPosition(), source()};
alias = expectIdentifierToken();
}
symbolAliases.emplace_back(move(id), move(alias));
symbolAliases.emplace_back(ImportDirective::SymbolAlias{move(id), move(alias), aliasLocation});
if (m_scanner->currentToken() != Token::Comma)
break;
m_scanner->next();

View File

@ -568,7 +568,7 @@ BOOST_AUTO_TEST_CASE(multiline_comment_at_eos)
BOOST_AUTO_TEST_CASE(regular_line_break_in_single_line_comment)
{
for (auto const& nl: {"\r", "\n"})
for (auto const& nl: {"\r", "\n", "\r\n"})
{
Scanner scanner(CharStream("// abc " + string(nl) + " def ", ""));
BOOST_CHECK_EQUAL(scanner.currentCommentLiteral(), "");
@ -595,7 +595,7 @@ BOOST_AUTO_TEST_CASE(irregular_line_breaks_in_single_line_comment)
BOOST_AUTO_TEST_CASE(regular_line_breaks_in_single_line_doc_comment)
{
for (auto const& nl: {"\r", "\n"})
for (auto const& nl: {"\r", "\n", "\r\n"})
{
Scanner scanner(CharStream("/// abc " + string(nl) + " def ", ""));
BOOST_CHECK_EQUAL(scanner.currentCommentLiteral(), "abc ");
@ -605,6 +605,22 @@ BOOST_AUTO_TEST_CASE(regular_line_breaks_in_single_line_doc_comment)
}
}
BOOST_AUTO_TEST_CASE(regular_line_breaks_in_multiline_doc_comment)
{
// Test CR, LF, CRLF as line valid terminators for code comments.
// Any accepted non-LF is being canonicalized to LF.
for (auto const& nl : {"\r"s, "\n"s, "\r\n"s})
{
Scanner scanner{CharStream{"/// Hello" + nl + "/// World" + nl + "ident", ""}};
auto const& lit = scanner.currentCommentLiteral();
BOOST_CHECK_EQUAL(lit, "Hello\n World");
BOOST_CHECK_EQUAL(scanner.currentCommentLiteral(), "Hello\n World");
BOOST_CHECK_EQUAL(scanner.currentToken(), Token::Identifier);
BOOST_CHECK_EQUAL(scanner.currentLiteral(), "ident");
BOOST_CHECK_EQUAL(scanner.next(), Token::EOS);
}
}
BOOST_AUTO_TEST_CASE(irregular_line_breaks_in_single_line_doc_comment)
{
for (auto const& nl: {"\v", "\f", "\xE2\x80\xA8", "\xE2\x80\xA9"})
@ -622,9 +638,9 @@ BOOST_AUTO_TEST_CASE(irregular_line_breaks_in_single_line_doc_comment)
BOOST_AUTO_TEST_CASE(regular_line_breaks_in_strings)
{
for (auto const& nl: {"\n", "\r"})
for (auto const& nl: {"\r"s, "\n"s, "\r\n"s})
{
Scanner scanner(CharStream("\"abc " + string(nl) + " def\"", ""));
Scanner scanner(CharStream("\"abc " + nl + " def\"", ""));
BOOST_CHECK_EQUAL(scanner.currentToken(), Token::Illegal);
BOOST_CHECK_EQUAL(scanner.next(), Token::Identifier);
BOOST_CHECK_EQUAL(scanner.currentLiteral(), "def");

View File

@ -0,0 +1,12 @@
contract Test {
struct RecursiveStruct {
RecursiveStruct[] vals;
}
function func() public pure {
RecursiveStruct[1] memory val = [ RecursiveStruct(new RecursiveStruct[](42)) ];
assert(val[0].vals.length == 42);
}
}
// -----
// func() ->

View File

@ -5,4 +5,4 @@ library A {}
==== Source: c ====
import {A} from "./a"; import {A} from "./b";
// ----
// DeclarationError: (c:23-45): Identifier already declared.
// DeclarationError: (c:31-32): Identifier already declared.

View File

@ -3,4 +3,4 @@ contract C {}
==== Source: b ====
import {C as msg} from "B.sol";
// ----
// Warning: (B.sol:0-13): This declaration shadows a builtin symbol.
// Warning: (b:13-16): This declaration shadows a builtin symbol.

View File

@ -7,5 +7,5 @@ contract C {
// ----
// Warning: (B.sol:0-15): This declaration shadows a builtin symbol.
// Warning: (B.sol:16-32): This declaration shadows a builtin symbol.
// Warning: (B.sol:0-15): This declaration shadows a builtin symbol.
// Warning: (B.sol:16-32): This declaration shadows a builtin symbol.
// Warning: (b:8-11): This declaration shadows a builtin symbol.
// Warning: (b:13-18): This declaration shadows a builtin symbol.

View File

@ -5,4 +5,4 @@ library A {}
==== Source: c ====
import {A} from "./a"; import {A} from "./b";
// ----
// DeclarationError: (c:23-45): Identifier already declared.
// DeclarationError: (c:31-32): Identifier already declared.

View File

@ -0,0 +1,10 @@
contract Test {
struct RecursiveStruct {
RecursiveStruct[] vals;
}
function func() private pure {
RecursiveStruct[1] memory val;
val;
}
}