mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #3950 from ethereum/develop
Merge develop into release for 0.4.23
This commit is contained in:
commit
124ca40dc5
@ -159,7 +159,8 @@ cache:
|
||||
install:
|
||||
- test $SOLC_INSTALL_DEPS_TRAVIS != On || (scripts/install_deps.sh)
|
||||
- test "$TRAVIS_OS_NAME" != "linux" || (scripts/install_cmake.sh)
|
||||
# - if [ "$TRAVIS_BRANCH" != release -a -z "$TRAVIS_TAG" ]; then SOLC_TESTS=Off; fi
|
||||
# Disable tests unless run on the release branch, on tags or with daily cron
|
||||
#- if [ "$TRAVIS_BRANCH" != release -a -z "$TRAVIS_TAG" -a "$TRAVIS_EVENT_TYPE" != cron ]; then SOLC_TESTS=Off; fi
|
||||
- SOLC_TESTS=Off
|
||||
- if [ "$TRAVIS_BRANCH" = release -o -n "$TRAVIS_TAG" ]; then echo -n > prerelease.txt; else date -u +"nightly.%Y.%-m.%-d" > prerelease.txt; fi
|
||||
- echo -n "$TRAVIS_COMMIT" > commit_hash.txt
|
||||
|
@ -8,7 +8,7 @@ include(EthPolicy)
|
||||
eth_policy()
|
||||
|
||||
# project name and version should be set after cmake_policy CMP0048
|
||||
set(PROJECT_VERSION "0.4.22")
|
||||
set(PROJECT_VERSION "0.4.23")
|
||||
project(solidity VERSION ${PROJECT_VERSION})
|
||||
|
||||
option(SOLC_LINK_STATIC "Link solc executable statically on supported platforms" OFF)
|
||||
|
317
CODING_STYLE.md
317
CODING_STYLE.md
@ -1,35 +1,24 @@
|
||||
0. Formatting
|
||||
## 0. Formatting
|
||||
|
||||
GOLDEN RULE: Follow the style of the existing code when you make changes.
|
||||
**GOLDEN RULE**: Follow the style of the existing code when you make changes.
|
||||
|
||||
a. Use tabs for leading indentation
|
||||
- tab stops are every 4 characters (only relevant for line length).
|
||||
- One indentation level -> exactly one byte (i.e. a tab character) in the source file.
|
||||
b. Line widths:
|
||||
- Lines should be at most 99 characters wide to make diff views readable and reduce merge conflicts.
|
||||
- Lines of comments should be formatted according to ease of viewing, but simplicity is to be preferred over beauty.
|
||||
c. Single-statement blocks should not have braces, unless required for clarity.
|
||||
d. Never place condition bodies on same line as condition.
|
||||
e. Space between keyword and opening parenthesis, but not following opening parenthesis or before final parenthesis.
|
||||
f. No spaces for unary operators, `->` or `.`.
|
||||
g. No space before ':' but one after it, except in the ternary operator: one on both sides.
|
||||
h. Add spaces around all other operators.
|
||||
i. Braces, when used, always have their own lines and are at same indentation level as "parent" scope.
|
||||
j. If lines are broken, a list of elements enclosed with parentheses (of any kind) and separated by a
|
||||
separator (of any kind) are formatted such that there is exactly one element per line, followed by
|
||||
the separator, the opening parenthesis is on the first line, followed by a line break and the closing
|
||||
parenthesis is on a line of its own (unindented). See example below.
|
||||
1. Use tabs for leading indentation:
|
||||
- tab stops are every 4 characters (only relevant for line length).
|
||||
- one indentation level -> exactly one byte (i.e. a tab character) in the source file.
|
||||
2. Line widths:
|
||||
- Lines should be at most 99 characters wide to make diff views readable and reduce merge conflicts.
|
||||
- Lines of comments should be formatted according to ease of viewing, but simplicity is to be preferred over beauty.
|
||||
3. Single-statement blocks should not have braces, unless required for clarity.
|
||||
4. Never place condition bodies on same line as condition.
|
||||
5. Space between keyword and opening parenthesis, but not following opening parenthesis or before final parenthesis.
|
||||
6. No spaces for unary operators, `->` or `.`.
|
||||
7. No space before `:` but one after it, except in the ternary operator: one on both sides.
|
||||
8. Add spaces around all other operators.
|
||||
9. Braces, when used, always have their own lines and are at same indentation level as "parent" scope.
|
||||
10. If lines are broken, a list of elements enclosed with parentheses (of any kind) and separated by a separator (of any kind) are formatted such that there is exactly one element per line, followed by the separator, the opening parenthesis is on the first line, followed by a line break and the closing parenthesis is on a line of its own unindented). See example below.
|
||||
|
||||
(WRONG)
|
||||
if( a==b[ i ] ) { printf ("Hello\n"); }
|
||||
foo->bar(someLongVariableName,
|
||||
anotherLongVariableName,
|
||||
anotherLongVariableName,
|
||||
anotherLongVariableName,
|
||||
anotherLongVariableName);
|
||||
cout << "some very long string that contains completely irrelevant text that talks about this and that and contains the words \"lorem\" and \"ipsum\"" << endl;
|
||||
|
||||
(RIGHT)
|
||||
Yes:
|
||||
```cpp
|
||||
if (a == b[i])
|
||||
printf("Hello\n"); // NOTE spaces used instead of tab here for clarity - first byte should be '\t'.
|
||||
foo->bar(
|
||||
@ -44,99 +33,92 @@ cout <<
|
||||
"text that talks about this and that and contains the words " <<
|
||||
"\"lorem\" and \"ipsum\"" <<
|
||||
endl;
|
||||
```
|
||||
|
||||
No:
|
||||
```cpp
|
||||
if( a==b[ i ] ) { printf ("Hello\n"); }
|
||||
foo->bar(someLongVariableName,
|
||||
anotherLongVariableName,
|
||||
anotherLongVariableName,
|
||||
anotherLongVariableName,
|
||||
anotherLongVariableName);
|
||||
cout << "some very long string that contains completely irrelevant text that talks about this and that and contains the words \"lorem\" and \"ipsum\"" << endl;
|
||||
```
|
||||
|
||||
## 1. Namespaces
|
||||
|
||||
1. Namespaces;
|
||||
1. No `using namespace` declarations in header files.
|
||||
2. All symbols should be declared in a namespace except for final applications.
|
||||
3. Use anonymous namespaces for helpers whose scope is a cpp file only.
|
||||
4. Preprocessor symbols should be prefixed with the namespace in all-caps and an underscore.
|
||||
|
||||
a. No "using namespace" declarations in header files.
|
||||
b. All symbols should be declared in a namespace except for final applications.
|
||||
c. Use anonymous namespaces for helpers whose scope is a cpp file only.
|
||||
d. Preprocessor symbols should be prefixed with the namespace in all-caps and an underscore.
|
||||
Yes:
|
||||
```cpp
|
||||
#include <cassert>
|
||||
std::tuple<float, float> meanAndSigma(std::vector<float> const& _v);
|
||||
```
|
||||
|
||||
(WRONG)
|
||||
No:
|
||||
```cpp
|
||||
#include <cassert>
|
||||
using namespace std;
|
||||
tuple<float, float> meanAndSigma(vector<float> const& _v);
|
||||
```
|
||||
|
||||
(CORRECT)
|
||||
#include <cassert>
|
||||
std::tuple<float, float> meanAndSigma(std::vector<float> const& _v);
|
||||
## 2. Preprocessor
|
||||
|
||||
1. File comment is always at top, and includes:
|
||||
- Copyright
|
||||
- License (e.g. see COPYING)
|
||||
2. Never use `#ifdef`/`#define`/`#endif` file guards. Prefer `#pragma` once as first line below file comment.
|
||||
3. Prefer static const variable to value macros.
|
||||
4. Prefer inline constexpr functions to function macros.
|
||||
5. Split complex macro on multiple lines with `\`.
|
||||
|
||||
## 3. Capitalization
|
||||
|
||||
2. Preprocessor;
|
||||
|
||||
a. File comment is always at top, and includes:
|
||||
- Copyright.
|
||||
- License (e.g. see COPYING).
|
||||
b. Never use #ifdef/#define/#endif file guards. Prefer #pragma once as first line below file comment.
|
||||
c. Prefer static const variable to value macros.
|
||||
d. Prefer inline constexpr functions to function macros.
|
||||
e. Split complex macro on multiple lines with '\'.
|
||||
|
||||
|
||||
|
||||
3. Capitalization;
|
||||
|
||||
GOLDEN RULE: Preprocessor: ALL_CAPS; C++: camelCase.
|
||||
|
||||
a. Use camelCase for splitting words in names, except where obviously extending STL/boost functionality in which case follow those naming conventions.
|
||||
b. The following entities' first alpha is upper case:
|
||||
- Type names.
|
||||
- Template parameters.
|
||||
- Enum members.
|
||||
- static const variables that form an external API.
|
||||
c. All preprocessor symbols (macros, macro arguments) in full uppercase with underscore word separation.
|
||||
**GOLDEN RULE**: Preprocessor: `ALL_CAPS`; C++: `camelCase`.
|
||||
|
||||
1. Use camelCase for splitting words in names, except where obviously extending STL/boost functionality in which case follow those naming conventions.
|
||||
2. The following entities' first alpha is upper case:
|
||||
- Type names
|
||||
- Template parameters
|
||||
- Enum members
|
||||
- static const variables that form an external API.
|
||||
3. All preprocessor symbols (macros, macro arguments) in full uppercase with underscore word separation.
|
||||
|
||||
All other entities' first alpha is lower case.
|
||||
|
||||
## 4. Variable prefixes
|
||||
|
||||
1. Leading underscore "_" to parameter names:
|
||||
- Exception: "o_parameterName" when it is used exclusively for output. See 6(f).
|
||||
- Exception: "io_parameterName" when it is used for both input and output. See 6(f).
|
||||
2. Leading "g_" to global (non-const) variables.
|
||||
3. Leading "s_" to static (non-const, non-global) variables.
|
||||
|
||||
4. Variable prefixes:
|
||||
## 5. Assertions
|
||||
|
||||
a. Leading underscore "_" to parameter names.
|
||||
- Exception: "o_parameterName" when it is used exclusively for output. See 6(f).
|
||||
- Exception: "io_parameterName" when it is used for both input and output. See 6(f).
|
||||
b. Leading "g_" to global (non-const) variables.
|
||||
c. Leading "s_" to static (non-const, non-global) variables.
|
||||
Use `solAssert` and `solUnimplementedAssert` generously to check assumptions that span across different parts of the code base, for example before dereferencing a pointer.
|
||||
|
||||
## 6. Declarations
|
||||
|
||||
1. {Typename} + {qualifiers} + {name}.
|
||||
2. Only one per line.
|
||||
3. Associate */& with type, not variable (at ends with parser, but more readable, and safe if in conjunction with (b)).
|
||||
4. Favour declarations close to use; don't habitually declare at top of scope ala C.
|
||||
5. Pass non-trivial parameters as const reference, unless the data is to be copied into the function, then either pass by const reference or by value and use std::move.
|
||||
6. If a function returns multiple values, use std::tuple (std::pair acceptable) or better introduce a struct type. Do not use */& arguments.
|
||||
7. Use parameters of pointer type only if ``nullptr`` is a valid argument, use references otherwise. Often, ``boost::optional`` is better suited than a raw pointer.
|
||||
8. Never use a macro where adequate non-preprocessor C++ can be written.
|
||||
9. Only use ``auto`` if the type is very long and rather irrelevant.
|
||||
10. Do not pass bools: prefer enumerations instead.
|
||||
11. Prefer enum class to straight enum.
|
||||
12. Always initialize POD variables, even if their value is overwritten later.
|
||||
|
||||
5. Assertions:
|
||||
|
||||
- use `solAssert` and `solUnimplementedAssert` generously to check assumptions
|
||||
that span across different parts of the code base, for example before dereferencing
|
||||
a pointer.
|
||||
|
||||
|
||||
6. Declarations:
|
||||
|
||||
a. {Typename} + {qualifiers} + {name}.
|
||||
b. Only one per line.
|
||||
c. Associate */& with type, not variable (at ends with parser, but more readable, and safe if in conjunction with (b)).
|
||||
d. Favour declarations close to use; don't habitually declare at top of scope ala C.
|
||||
e. Pass non-trivial parameters as const reference, unless the data is to be copied into the function, then either pass by const reference or by value and use std::move.
|
||||
f. If a function returns multiple values, use std::tuple (std::pair acceptable) or better introduce a struct type. Do not use */& arguments.
|
||||
g. Use parameters of pointer type only if ``nullptr`` is a valid argument, use references otherwise. Often, ``boost::optional`` is better suited than a raw pointer.
|
||||
h. Never use a macro where adequate non-preprocessor C++ can be written.
|
||||
i. Only use ``auto`` if the type is very long and rather irrelevant.
|
||||
j. Do not pass bools: prefer enumerations instead.
|
||||
k. Prefer enum class to straight enum.
|
||||
l. Always initialize POD variables, even if their value is overwritten later.
|
||||
|
||||
|
||||
(WRONG)
|
||||
const double d = 0;
|
||||
int i, j;
|
||||
char *s;
|
||||
float meanAndSigma(std::vector<float> _v, float* _sigma, bool _approximate);
|
||||
Derived* x(dynamic_cast<Derived*>(base));
|
||||
for (map<ComplexTypeOne, ComplexTypeTwo>::iterator i = l.begin(); i != l.end(); ++l) {}
|
||||
|
||||
|
||||
(CORRECT)
|
||||
Yes:
|
||||
```cpp
|
||||
enum class Accuracy
|
||||
{
|
||||
Approximate,
|
||||
@ -154,78 +136,78 @@ char* s;
|
||||
MeanAndSigma ms meanAndSigma(std::vector<float> const& _v, Accuracy _a);
|
||||
Derived* x = dynamic_cast<Derived*>(base);
|
||||
for (auto i = x->begin(); i != x->end(); ++i) {}
|
||||
```
|
||||
|
||||
No:
|
||||
```cp
|
||||
const double d = 0;
|
||||
int i, j;
|
||||
char *s;
|
||||
float meanAndSigma(std::vector<float> _v, float* _sigma, bool _approximate);
|
||||
Derived* x(dynamic_cast<Derived*>(base));
|
||||
for (map<ComplexTypeOne, ComplexTypeTwo>::iterator i = l.begin(); i != l.end(); ++l) {}
|
||||
```
|
||||
|
||||
7. Structs & classes
|
||||
## 7. Structs & classes
|
||||
|
||||
a. Structs to be used when all members public and no virtual functions.
|
||||
- In this case, members should be named naturally and not prefixed with 'm_'
|
||||
b. Classes to be used in all other circumstances.
|
||||
1. Structs to be used when all members public and no virtual functions:
|
||||
- In this case, members should be named naturally and not prefixed with `m_`.
|
||||
2. Classes to be used in all other circumstances.
|
||||
|
||||
## 8. Members
|
||||
|
||||
1. One member per line only.
|
||||
2. Private, non-static, non-const fields prefixed with `m_`.
|
||||
3. Avoid public fields, except in structs.
|
||||
4. Use override, final and const as much as possible.
|
||||
5. No implementations with the class declaration, except:
|
||||
- template or force-inline method (though prefer implementation at bottom of header file).
|
||||
- one-line implementation (in which case include it in same line as declaration).
|
||||
6. For a property `foo`
|
||||
- Member: `m_foo`
|
||||
- Getter: `foo()` [ also: for booleans, `isFoo()` ]
|
||||
- Setter: `setFoo()`
|
||||
|
||||
8. Members:
|
||||
## 9. Naming
|
||||
|
||||
a. One member per line only.
|
||||
b. Private, non-static, non-const fields prefixed with m_.
|
||||
c. Avoid public fields, except in structs.
|
||||
d. Use override, final and const as much as possible.
|
||||
e. No implementations with the class declaration, except:
|
||||
- template or force-inline method (though prefer implementation at bottom of header file).
|
||||
- one-line implementation (in which case include it in same line as declaration).
|
||||
f. For a property 'foo'
|
||||
- Member: m_foo;
|
||||
- Getter: foo() [ also: for booleans, isFoo() ];
|
||||
- Setter: setFoo();
|
||||
1. Avoid unpronouncable names.
|
||||
2. Names should be shortened only if they are extremely common, but shortening should be generally avoided
|
||||
3. Avoid prefixes of initials (e.g. do not use `IMyInterface`, `CMyImplementation`)
|
||||
4. Find short, memorable & (at least semi-) descriptive names for commonly used classes or name-fragments:
|
||||
- A dictionary and thesaurus are your friends;
|
||||
- Spell correctly;
|
||||
- Think carefully about the class's purpose;
|
||||
- Imagine it as an isolated component to try to decontextualise it when considering its name;
|
||||
- Don't be trapped into naming it (purely) in terms of its implementation.
|
||||
|
||||
## 10. Type definitions
|
||||
|
||||
1. Prefer `using` to `typedef`. e.g. `using ints = std::vector<int>;` rather than typedef `std::vector<int> ints;`
|
||||
2. Generally avoid shortening a standard form that already includes all important information:
|
||||
- e.g. stick to `shared_ptr<X>` rather than shortening to `ptr<X>`.
|
||||
3. Where there are exceptions to this (due to excessive use and clear meaning), note the change prominently and use it consistently:
|
||||
- e.g. `using Guard = std::lock_guard<std::mutex>;` ///< Guard is used throughout the codebase since it is clear in meaning and used commonly.
|
||||
4. In general expressions should be roughly as important/semantically meaningful as the space they occupy.
|
||||
5. Avoid introducing aliases for types unless they are very complicated. Consider the number of items a brain can keep track of at the same time.
|
||||
|
||||
9. Naming
|
||||
## 11. Commenting
|
||||
|
||||
a. Avoid unpronouncable names
|
||||
b. Names should be shortened only if they are extremely common, but shortening should be generally avoided
|
||||
c. Avoid prefixes of initials (e.g. do not use IMyInterface, CMyImplementation)
|
||||
c. Find short, memorable & (at least semi-) descriptive names for commonly used classes or name-fragments.
|
||||
- A dictionary and thesaurus are your friends.
|
||||
- Spell correctly.
|
||||
- Think carefully about the class's purpose.
|
||||
- Imagine it as an isolated component to try to decontextualise it when considering its name.
|
||||
- Don't be trapped into naming it (purely) in terms of its implementation.
|
||||
1. Comments should be doxygen-compilable, using @notation rather than \notation.
|
||||
2. Document the interface, not the implementation:
|
||||
- Documentation should be able to remain completely unchanged, even if the method is reimplemented;
|
||||
- Comment in terms of the method properties and intended alteration to class state (or what aspects of the state it reports);
|
||||
- Be careful to scrutinise documentation that extends only to intended purpose and usage;
|
||||
- Reject documentation that is simply an English transaction of the implementation.
|
||||
3. Avoid in-code comments. Instead, try to extract blocks of functionality into functions. This often already eliminates the need for an in-code comment.
|
||||
|
||||
## 12. Include Headers
|
||||
|
||||
|
||||
10. Type-definitions
|
||||
|
||||
a. Prefer 'using' to 'typedef'. e.g. using ints = std::vector<int>; rather than typedef std::vector<int> ints;
|
||||
b. Generally avoid shortening a standard form that already includes all important information:
|
||||
- e.g. stick to shared_ptr<X> rather than shortening to ptr<X>.
|
||||
c. Where there are exceptions to this (due to excessive use and clear meaning), note the change prominently and use it consistently.
|
||||
- e.g. using Guard = std::lock_guard<std::mutex>; ///< Guard is used throughout the codebase since it is clear in meaning and used commonly.
|
||||
d. In general expressions should be roughly as important/semantically meaningful as the space they occupy.
|
||||
e. Avoid introducing aliases for types unless they are very complicated. Consider the number of items a brain can keep track of at the same time.
|
||||
|
||||
|
||||
|
||||
11. Commenting
|
||||
|
||||
a. Comments should be doxygen-compilable, using @notation rather than \notation.
|
||||
b. Document the interface, not the implementation.
|
||||
- Documentation should be able to remain completely unchanged, even if the method is reimplemented.
|
||||
- Comment in terms of the method properties and intended alteration to class state (or what aspects of the state it reports).
|
||||
- Be careful to scrutinise documentation that extends only to intended purpose and usage.
|
||||
- Reject documentation that is simply an English transaction of the implementation.
|
||||
c. Avoid in-code comments. Instead, try to extract blocks of functionality into functions. This often already eliminates the need for an in-code comment.
|
||||
|
||||
|
||||
12. Include Headers
|
||||
|
||||
Includes should go in increasing order of generality (libsolidity -> libevmasm -> libdevcore -> boost -> STL).
|
||||
The corresponding .h file should be the first include in the respective .cpp file.
|
||||
Insert empty lines between blocks of include files.
|
||||
1. Includes should go in increasing order of generality (`libsolidity` -> `libevmasm` -> `libdevcore` -> `boost` -> `STL`).
|
||||
2. The corresponding `.h` file should be the first include in the respective `.cpp` file.
|
||||
3. Insert empty lines between blocks of include files.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
```cpp
|
||||
#include <libsolidity/codegen/ExpressionCompiler.h>
|
||||
|
||||
#include <libsolidity/ast/AST.h>
|
||||
@ -245,18 +227,17 @@ Example:
|
||||
#include <numeric>
|
||||
```
|
||||
|
||||
See http://stackoverflow.com/questions/614302/c-header-order/614333#614333 for the reason: this makes it easier to find missing includes in header files.
|
||||
See [this issue](http://stackoverflow.com/questions/614302/c-header-order/614333#614333 "C header order") for the reason: this makes it easier to find missing includes in header files.
|
||||
|
||||
## 13. Recommended reading
|
||||
|
||||
13. Recommended reading
|
||||
- Herb Sutter and Bjarne Stroustrup:
|
||||
- [C++ Core Guidelines](https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md)
|
||||
|
||||
Herb Sutter and Bjarne Stroustrup
|
||||
- "C++ Core Guidelines" (https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md)
|
||||
- Herb Sutter and Andrei Alexandrescu:
|
||||
- "C++ Coding Standards: 101 Rules, Guidelines, and Best Practices"
|
||||
|
||||
Herb Sutter and Andrei Alexandrescu
|
||||
- "C++ Coding Standards: 101 Rules, Guidelines, and Best Practices"
|
||||
|
||||
Scott Meyers
|
||||
- "Effective C++: 55 Specific Ways to Improve Your Programs and Designs (3rd Edition)"
|
||||
- "More Effective C++: 35 New Ways to Improve Your Programs and Designs"
|
||||
- "Effective Modern C++: 42 Specific Ways to Improve Your Use of C++11 and C++14"
|
||||
- Scott Meyers:
|
||||
- "Effective C++: 55 Specific Ways to Improve Your Programs and Designs (3rd Edition)"
|
||||
- "More Effective C++: 35 New Ways to Improve Your Programs and Designs"
|
||||
- "Effective Modern C++: 42 Specific Ways to Improve Your Use of C++11 and C++14"
|
||||
|
14
Changelog.md
14
Changelog.md
@ -1,3 +1,16 @@
|
||||
### 0.4.23 (2018-04-19)
|
||||
|
||||
Features:
|
||||
* Build system: Support Ubuntu Bionic.
|
||||
* SMTChecker: Integration with CVC4 SMT solver
|
||||
* Syntax Checker: Warn about functions named "constructor".
|
||||
|
||||
Bugfixes:
|
||||
* Type Checker: Improve error message for failed function overload resolution.
|
||||
* Type Checker: Do not complain about new-style constructor and fallback function to have the same name.
|
||||
* Type Checker: Detect multiple constructor declarations in the new syntax and old syntax.
|
||||
* Type Checker: Explicit conversion of ``bytesXX`` to ``contract`` is properly disallowed.
|
||||
|
||||
### 0.4.22 (2018-04-16)
|
||||
|
||||
Features:
|
||||
@ -25,7 +38,6 @@ Features:
|
||||
* Syntax Tests: Add source locations to syntax test expectations.
|
||||
* Type Checker: Improve documentation and warnings for accessing contract members inherited from ``address``.
|
||||
|
||||
|
||||
Bugfixes:
|
||||
* Code Generator: Allow ``block.blockhash`` without being called.
|
||||
* Code Generator: Do not include internal functions in the runtime bytecode which are only referenced in the constructor.
|
||||
|
@ -14,6 +14,6 @@ Solidity is still under development. So please do not hesitate and open an [issu
|
||||
See the [Solidity documentation](https://solidity.readthedocs.io/en/latest/installing-solidity.html#building-from-source) for build instructions.
|
||||
|
||||
## How to Contribute
|
||||
Please see our contribution guidelines in [the Solidity documentation](https://solidity.readthedocs.io/en/latest/contributing.html).
|
||||
Please see our [contribution guidelines](https://solidity.readthedocs.io/en/latest/contributing.html) in the Solidity documentation.
|
||||
|
||||
Any contributions are welcome!
|
||||
|
@ -1,7 +1,8 @@
|
||||
Checklist for making a release:
|
||||
|
||||
- [ ] Check that all "nextrelease" issues and pull requests are merged to ``develop``.
|
||||
- [ ] Create a commit in ``develop`` that updates the ``Changelog`` to include a release date (run the tests locally to update the bug list).
|
||||
- [ ] Ensure that a Github project exists for the release.
|
||||
- [ ] Check that all issues and pull requests from the Github project to be released are merged to ``develop``.
|
||||
- [ ] Create a commit in ``develop`` that updates the ``Changelog`` to include a release date (run ``./scripts/tests.sh`` to update the bug list). Sort the changelog entries alphabetically and correct any errors you notice.
|
||||
- [ ] Create a pull request and wait for the tests, merge it.
|
||||
- [ ] Create a pull request from ``develop`` to ``release``, wait for the tests, then merge it.
|
||||
- [ ] Make a final check that there are no platform-dependency issues in the ``solc-test-bytecode`` repository.
|
||||
@ -9,7 +10,7 @@ Checklist for making a release:
|
||||
- [ ] Thank voluntary contributors in the Github release page (use ``git shortlog -s -n -e origin/release..origin/develop``).
|
||||
- [ ] Wait for the CI runs on the tag itself (they should push artefacts onto the Github release page).
|
||||
- [ ] Run ``scripts/release_ppa.sh release`` to create the PPA release (you need the relevant openssl key).
|
||||
- [ ] Check that the Docker release was pushed to Docker Hub (this still seems to have problems).
|
||||
- [ ] Check that the Docker release was pushed to Docker Hub (this still seems to have problems, run ``./scripts/docker_deploy_manual.sh release``).
|
||||
- [ ] Update the homebrew realease in https://github.com/ethereum/homebrew-ethereum/blob/master/solidity.rb (version and hash)
|
||||
- [ ] Update the default version on readthedocs.
|
||||
- [ ] Make a release of ``solc-js``: Increment the version number, create a pull request for that, merge it after tests succeeded.
|
||||
|
@ -43,27 +43,6 @@ if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MA
|
||||
# TODO - Track down what breaks if we do NOT do this.
|
||||
add_compile_options(-Wno-unknown-pragmas)
|
||||
|
||||
# To get the code building on FreeBSD and Arch Linux we seem to need the following
|
||||
# warning suppression to work around some issues in Boost headers.
|
||||
#
|
||||
# See the following reports:
|
||||
# https://github.com/ethereum/webthree-umbrella/issues/384
|
||||
# https://github.com/ethereum/webthree-helpers/pull/170
|
||||
#
|
||||
# The issue manifest as warnings-as-errors like the following:
|
||||
#
|
||||
# /usr/local/include/boost/multiprecision/cpp_int.hpp:181:4: error:
|
||||
# right operand of shift expression '(1u << 63u)' is >= than the precision of the left operand
|
||||
#
|
||||
# -fpermissive is a pretty nasty way to address this. It is described as follows:
|
||||
#
|
||||
# Downgrade some diagnostics about nonconformant code from errors to warnings.
|
||||
# Thus, using -fpermissive will allow some nonconforming code to compile.
|
||||
#
|
||||
# NB: Have to use this form for the setting, so that it only applies to C++ builds.
|
||||
# Applying -fpermissive to a C command-line (ie. secp256k1) gives a build error.
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive")
|
||||
|
||||
# Configuration-specific compiler settings.
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g -DETH_DEBUG")
|
||||
set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG")
|
||||
@ -82,18 +61,6 @@ if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MA
|
||||
|
||||
# Additional Clang-specific compiler settings.
|
||||
elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
||||
|
||||
# A couple of extra warnings suppressions which we seemingly
|
||||
# need when building with Clang.
|
||||
#
|
||||
# TODO - Nail down exactly where these warnings are manifesting and
|
||||
# try to suppress them in a more localized way. Notes in this file
|
||||
# indicate that the first is needed for sepc256k1 and that the
|
||||
# second is needed for the (clog, cwarn) macros. These will need
|
||||
# testing on at least OS X and Ubuntu.
|
||||
add_compile_options(-Wno-unused-function)
|
||||
add_compile_options(-Wno-dangling-else)
|
||||
|
||||
if ("${CMAKE_SYSTEM_NAME}" MATCHES "Darwin")
|
||||
# Set stack size to 16MB - by default Apple's clang defines a stack size of 8MB, some tests require more.
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-stack_size -Wl,0x1000000")
|
||||
|
4
cmake/FindCVC4.cmake
Normal file
4
cmake/FindCVC4.cmake
Normal file
@ -0,0 +1,4 @@
|
||||
find_path(CVC4_INCLUDE_DIR cvc4/cvc4.h)
|
||||
find_library(CVC4_LIBRARY NAMES cvc4 )
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(CVC4 DEFAULT_MSG CVC4_LIBRARY CVC4_INCLUDE_DIR)
|
3
cmake/FindGMP.cmake
Normal file
3
cmake/FindGMP.cmake
Normal file
@ -0,0 +1,3 @@
|
||||
find_library(GMP_LIBRARY NAMES gmp )
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(GMP DEFAULT_MSG GMP_LIBRARY)
|
@ -1,4 +1,12 @@
|
||||
[
|
||||
{
|
||||
"name": "OneOfTwoConstructorsSkipped",
|
||||
"summary": "If a contract has both a new-style constructor (using the constructor keyword) and an old-style constructor (a function with the same name as the contract) at the same time, one of them will be ignored.",
|
||||
"description": "If a contract has both a new-style constructor (using the constructor keyword) and an old-style constructor (a function with the same name as the contract) at the same time, one of them will be ignored. There will be a compiler warning about the old-style constructor, so contracts only using new-style constructors are fine.",
|
||||
"introduced": "0.4.22",
|
||||
"fixed": "0.4.23",
|
||||
"severity": "very low"
|
||||
},
|
||||
{
|
||||
"name": "ZeroFunctionSelector",
|
||||
"summary": "It is possible to craft the name of a function such that it is executed instead of the fallback function in very specific circumstances.",
|
||||
|
@ -423,9 +423,15 @@
|
||||
"released": "2018-03-07"
|
||||
},
|
||||
"0.4.22": {
|
||||
"bugs": [],
|
||||
"bugs": [
|
||||
"OneOfTwoConstructorsSkipped"
|
||||
],
|
||||
"released": "2018-04-16"
|
||||
},
|
||||
"0.4.23": {
|
||||
"bugs": [],
|
||||
"released": "2018-04-19"
|
||||
},
|
||||
"0.4.3": {
|
||||
"bugs": [
|
||||
"ZeroFunctionSelector",
|
||||
|
@ -225,9 +225,6 @@ Minor Details
|
||||
=============
|
||||
|
||||
- In ``for (var i = 0; i < arrayName.length; i++) { ... }``, the type of ``i`` will be ``uint8``, because this is the smallest type that is required to hold the value ``0``. If the array has more than 255 elements, the loop will not terminate.
|
||||
- The ``constant`` keyword for functions is currently not enforced by the compiler.
|
||||
Furthermore, it is not enforced by the EVM, so a contract function that "claims"
|
||||
to be constant might still cause changes to the state.
|
||||
- Types that do not occupy the full 32 bytes might contain "dirty higher order bits".
|
||||
This is especially important if you access ``msg.data`` - it poses a malleability risk:
|
||||
You can craft transactions that call a function ``f(uint8 x)`` with a raw byte argument
|
||||
@ -239,6 +236,22 @@ Minor Details
|
||||
Recommendations
|
||||
***************
|
||||
|
||||
Take Warnings Seriously
|
||||
=======================
|
||||
|
||||
If the compiler warns you about something, you should better change it.
|
||||
Even if you do not think that this particular warning has security
|
||||
implications, there might be another issue buried beneath it.
|
||||
Any compiler warning we issue can be silenced by slight changes to the
|
||||
code.
|
||||
|
||||
Also try to enable the "0.5.0" safety features as early as possible
|
||||
by adding ``pragma experimental "v0.5.0";``. Note that in this case,
|
||||
the word ``experimental`` does not mean that the safety features are in any
|
||||
way risky, it is just a way to enable some features that are
|
||||
not yet part of the latest version of Solidity due to backwards
|
||||
compatibility.
|
||||
|
||||
Restrict the Amount of Ether
|
||||
============================
|
||||
|
||||
|
@ -27,6 +27,11 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
static_assert(
|
||||
(JSONCPP_VERSION_MAJOR == 1) && (JSONCPP_VERSION_MINOR == 7) && (JSONCPP_VERSION_PATCH == 7),
|
||||
"Unexpected jsoncpp version: " JSONCPP_VERSION_STRING ". Expecting 1.7.7."
|
||||
);
|
||||
|
||||
namespace dev
|
||||
{
|
||||
|
||||
|
@ -6,10 +6,25 @@ find_package(Z3 QUIET)
|
||||
if (${Z3_FOUND})
|
||||
include_directories(${Z3_INCLUDE_DIR})
|
||||
add_definitions(-DHAVE_Z3)
|
||||
message("Z3 SMT solver found. This enables optional SMT checking.")
|
||||
message("Z3 SMT solver found. This enables optional SMT checking with Z3.")
|
||||
list(REMOVE_ITEM sources "${CMAKE_CURRENT_SOURCE_DIR}/formal/CVC4Interface.cpp")
|
||||
else()
|
||||
message("Z3 SMT solver NOT found. Optional SMT checking will not be available. Please install Z3 if it is desired.")
|
||||
list(REMOVE_ITEM sources "${CMAKE_CURRENT_SOURCE_DIR}/formal/Z3Interface.cpp")
|
||||
find_package(GMP QUIET)
|
||||
find_package(CVC4 QUIET)
|
||||
if (${CVC4_FOUND})
|
||||
if (${GMP_FOUND})
|
||||
include_directories(${CVC4_INCLUDE_DIR})
|
||||
add_definitions(-DHAVE_CVC4)
|
||||
message("CVC4 SMT solver and GMP found. This enables optional SMT checking with CVC4.")
|
||||
else()
|
||||
message("CVC4 SMT solver found but its dependency GMP was NOT found. Optional SMT checking with CVC4 will not be available. Please install GMP if it is desired.")
|
||||
list(REMOVE_ITEM sources "${CMAKE_CURRENT_SOURCE_DIR}/formal/CVC4Interface.cpp")
|
||||
endif()
|
||||
else()
|
||||
message("No SMT solver found (Z3 or CVC4). Optional SMT checking will not be available. Please install Z3 or CVC4 if it is desired.")
|
||||
list(REMOVE_ITEM sources "${CMAKE_CURRENT_SOURCE_DIR}/formal/CVC4Interface.cpp")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_library(solidity ${sources} ${headers})
|
||||
@ -17,4 +32,9 @@ target_link_libraries(solidity PUBLIC evmasm devcore)
|
||||
|
||||
if (${Z3_FOUND})
|
||||
target_link_libraries(solidity PUBLIC ${Z3_LIBRARY})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (${CVC4_FOUND} AND ${GMP_FOUND})
|
||||
target_link_libraries(solidity PUBLIC ${CVC4_LIBRARY})
|
||||
target_link_libraries(solidity PUBLIC ${GMP_LIBRARY})
|
||||
endif()
|
||||
|
@ -237,8 +237,13 @@ bool SyntaxChecker::visit(FunctionDefinition const& _function)
|
||||
if (v050)
|
||||
m_errorReporter.syntaxError(_function.location(), "Functions without implementation cannot have modifiers.");
|
||||
else
|
||||
m_errorReporter.warning( _function.location(), "Modifiers of functions without implementation are ignored." );
|
||||
m_errorReporter.warning(_function.location(), "Modifiers of functions without implementation are ignored." );
|
||||
}
|
||||
if (_function.name() == "constructor")
|
||||
m_errorReporter.warning(_function.location(),
|
||||
"This function is named \"constructor\" but is not the constructor of the contract. "
|
||||
"If you intend this to be a constructor, use \"constructor(...) { ... }\" without the \"function\" keyword to define it."
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -109,39 +109,28 @@ bool TypeChecker::visit(ContractDefinition const& _contract)
|
||||
m_errorReporter.typeError(function->location(), "Constructor must be public or internal.");
|
||||
}
|
||||
|
||||
FunctionDefinition const* fallbackFunction = nullptr;
|
||||
for (FunctionDefinition const* function: _contract.definedFunctions())
|
||||
{
|
||||
if (function->isFallback())
|
||||
{
|
||||
if (fallbackFunction)
|
||||
{
|
||||
m_errorReporter.declarationError(function->location(), "Only one fallback function is allowed.");
|
||||
}
|
||||
else
|
||||
{
|
||||
fallbackFunction = function;
|
||||
if (_contract.isLibrary())
|
||||
m_errorReporter.typeError(fallbackFunction->location(), "Libraries cannot have fallback functions.");
|
||||
if (function->stateMutability() != StateMutability::NonPayable && function->stateMutability() != StateMutability::Payable)
|
||||
m_errorReporter.typeError(
|
||||
function->location(),
|
||||
"Fallback function must be payable or non-payable, but is \"" +
|
||||
stateMutabilityToString(function->stateMutability()) +
|
||||
"\"."
|
||||
);
|
||||
if (!fallbackFunction->parameters().empty())
|
||||
m_errorReporter.typeError(fallbackFunction->parameterList().location(), "Fallback function cannot take parameters.");
|
||||
if (!fallbackFunction->returnParameters().empty())
|
||||
m_errorReporter.typeError(fallbackFunction->returnParameterList()->location(), "Fallback function cannot return values.");
|
||||
if (
|
||||
_contract.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::V050) &&
|
||||
fallbackFunction->visibility() != FunctionDefinition::Visibility::External
|
||||
)
|
||||
m_errorReporter.typeError(fallbackFunction->location(), "Fallback function must be defined as \"external\".");
|
||||
}
|
||||
if (_contract.isLibrary())
|
||||
m_errorReporter.typeError(function->location(), "Libraries cannot have fallback functions.");
|
||||
if (function->stateMutability() != StateMutability::NonPayable && function->stateMutability() != StateMutability::Payable)
|
||||
m_errorReporter.typeError(
|
||||
function->location(),
|
||||
"Fallback function must be payable or non-payable, but is \"" +
|
||||
stateMutabilityToString(function->stateMutability()) +
|
||||
"\"."
|
||||
);
|
||||
if (!function->parameters().empty())
|
||||
m_errorReporter.typeError(function->parameterList().location(), "Fallback function cannot take parameters.");
|
||||
if (!function->returnParameters().empty())
|
||||
m_errorReporter.typeError(function->returnParameterList()->location(), "Fallback function cannot return values.");
|
||||
if (
|
||||
_contract.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::V050) &&
|
||||
function->visibility() != FunctionDefinition::Visibility::External
|
||||
)
|
||||
m_errorReporter.typeError(function->location(), "Fallback function must be defined as \"external\".");
|
||||
}
|
||||
}
|
||||
|
||||
for (auto const& n: _contract.subNodes())
|
||||
if (!visited.count(n.get()))
|
||||
@ -172,25 +161,34 @@ void TypeChecker::checkContractDuplicateFunctions(ContractDefinition const& _con
|
||||
/// Checks that two functions with the same name defined in this contract have different
|
||||
/// argument types and that there is at most one constructor.
|
||||
map<string, vector<FunctionDefinition const*>> functions;
|
||||
FunctionDefinition const* constructor = nullptr;
|
||||
FunctionDefinition const* fallback = nullptr;
|
||||
for (FunctionDefinition const* function: _contract.definedFunctions())
|
||||
functions[function->name()].push_back(function);
|
||||
|
||||
// Constructor
|
||||
if (functions[_contract.name()].size() > 1)
|
||||
{
|
||||
SecondarySourceLocation ssl;
|
||||
auto it = ++functions[_contract.name()].begin();
|
||||
for (; it != functions[_contract.name()].end(); ++it)
|
||||
ssl.append("Another declaration is here:", (*it)->location());
|
||||
|
||||
string msg = "More than one constructor defined.";
|
||||
ssl.limitSize(msg);
|
||||
m_errorReporter.declarationError(
|
||||
functions[_contract.name()].front()->location(),
|
||||
ssl,
|
||||
msg
|
||||
);
|
||||
}
|
||||
if (function->isConstructor())
|
||||
{
|
||||
if (constructor)
|
||||
m_errorReporter.declarationError(
|
||||
function->location(),
|
||||
SecondarySourceLocation().append("Another declaration is here:", constructor->location()),
|
||||
"More than one constructor defined."
|
||||
);
|
||||
constructor = function;
|
||||
}
|
||||
else if (function->isFallback())
|
||||
{
|
||||
if (fallback)
|
||||
m_errorReporter.declarationError(
|
||||
function->location(),
|
||||
SecondarySourceLocation().append("Another declaration is here:", fallback->location()),
|
||||
"Only one fallback function is allowed."
|
||||
);
|
||||
fallback = function;
|
||||
}
|
||||
else
|
||||
{
|
||||
solAssert(!function->name().empty(), "");
|
||||
functions[function->name()].push_back(function);
|
||||
}
|
||||
|
||||
findDuplicateDefinitions(functions, "Function with same name and arguments defined twice.");
|
||||
}
|
||||
@ -1906,7 +1904,8 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
||||
// Retrieve the types of the arguments if this is used to call a function.
|
||||
auto const& argumentTypes = _memberAccess.annotation().argumentTypes;
|
||||
MemberList::MemberMap possibleMembers = exprType->members(m_scope).membersByName(memberName);
|
||||
if (possibleMembers.size() > 1 && argumentTypes)
|
||||
size_t const initialMemberCount = possibleMembers.size();
|
||||
if (initialMemberCount > 1 && argumentTypes)
|
||||
{
|
||||
// do overload resolution
|
||||
for (auto it = possibleMembers.begin(); it != possibleMembers.end();)
|
||||
@ -1920,17 +1919,21 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
||||
}
|
||||
if (possibleMembers.size() == 0)
|
||||
{
|
||||
auto storageType = ReferenceType::copyForLocationIfReference(
|
||||
DataLocation::Storage,
|
||||
exprType
|
||||
);
|
||||
if (!storageType->members(m_scope).membersByName(memberName).empty())
|
||||
m_errorReporter.fatalTypeError(
|
||||
_memberAccess.location(),
|
||||
"Member \"" + memberName + "\" is not available in " +
|
||||
exprType->toString() +
|
||||
" outside of storage."
|
||||
if (initialMemberCount == 0)
|
||||
{
|
||||
// Try to see if the member was removed because it is only available for storage types.
|
||||
auto storageType = ReferenceType::copyForLocationIfReference(
|
||||
DataLocation::Storage,
|
||||
exprType
|
||||
);
|
||||
if (!storageType->members(m_scope).membersByName(memberName).empty())
|
||||
m_errorReporter.fatalTypeError(
|
||||
_memberAccess.location(),
|
||||
"Member \"" + memberName + "\" is not available in " +
|
||||
exprType->toString() +
|
||||
" outside of storage."
|
||||
);
|
||||
}
|
||||
m_errorReporter.fatalTypeError(
|
||||
_memberAccess.location(),
|
||||
"Member \"" + memberName + "\" not found or not visible "
|
||||
|
@ -1299,7 +1299,6 @@ bool FixedBytesType::isExplicitlyConvertibleTo(Type const& _convertTo) const
|
||||
{
|
||||
return _convertTo.category() == Category::Integer ||
|
||||
_convertTo.category() == Category::FixedPoint ||
|
||||
_convertTo.category() == Category::Contract ||
|
||||
_convertTo.category() == category();
|
||||
}
|
||||
|
||||
|
200
libsolidity/formal/CVC4Interface.cpp
Normal file
200
libsolidity/formal/CVC4Interface.cpp
Normal file
@ -0,0 +1,200 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <libsolidity/formal/CVC4Interface.h>
|
||||
|
||||
#include <libsolidity/interface/Exceptions.h>
|
||||
|
||||
#include <libdevcore/CommonIO.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace dev;
|
||||
using namespace dev::solidity::smt;
|
||||
|
||||
CVC4Interface::CVC4Interface():
|
||||
m_solver(&m_context)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
void CVC4Interface::reset()
|
||||
{
|
||||
m_constants.clear();
|
||||
m_functions.clear();
|
||||
m_solver.reset();
|
||||
m_solver.setOption("produce-models", true);
|
||||
}
|
||||
|
||||
void CVC4Interface::push()
|
||||
{
|
||||
m_solver.push();
|
||||
}
|
||||
|
||||
void CVC4Interface::pop()
|
||||
{
|
||||
m_solver.pop();
|
||||
}
|
||||
|
||||
Expression CVC4Interface::newFunction(string _name, Sort _domain, Sort _codomain)
|
||||
{
|
||||
CVC4::Type fType = m_context.mkFunctionType(cvc4Sort(_domain), cvc4Sort(_codomain));
|
||||
m_functions.insert({_name, m_context.mkVar(_name.c_str(), fType)});
|
||||
return SolverInterface::newFunction(move(_name), _domain, _codomain);
|
||||
}
|
||||
|
||||
Expression CVC4Interface::newInteger(string _name)
|
||||
{
|
||||
m_constants.insert({_name, m_context.mkVar(_name.c_str(), m_context.integerType())});
|
||||
return SolverInterface::newInteger(move(_name));
|
||||
}
|
||||
|
||||
Expression CVC4Interface::newBool(string _name)
|
||||
{
|
||||
m_constants.insert({_name, m_context.mkVar(_name.c_str(), m_context.booleanType())});
|
||||
return SolverInterface::newBool(std::move(_name));
|
||||
}
|
||||
|
||||
void CVC4Interface::addAssertion(Expression const& _expr)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_solver.assertFormula(toCVC4Expr(_expr));
|
||||
}
|
||||
catch (CVC4::TypeCheckingException const&)
|
||||
{
|
||||
solAssert(false, "");
|
||||
}
|
||||
catch (CVC4::LogicException const&)
|
||||
{
|
||||
solAssert(false, "");
|
||||
}
|
||||
catch (CVC4::UnsafeInterruptException const&)
|
||||
{
|
||||
solAssert(false, "");
|
||||
}
|
||||
}
|
||||
|
||||
pair<CheckResult, vector<string>> CVC4Interface::check(vector<Expression> const& _expressionsToEvaluate)
|
||||
{
|
||||
CheckResult result;
|
||||
vector<string> values;
|
||||
try
|
||||
{
|
||||
switch (m_solver.checkSat().isSat())
|
||||
{
|
||||
case CVC4::Result::SAT:
|
||||
result = CheckResult::SATISFIABLE;
|
||||
break;
|
||||
case CVC4::Result::UNSAT:
|
||||
result = CheckResult::UNSATISFIABLE;
|
||||
break;
|
||||
case CVC4::Result::SAT_UNKNOWN:
|
||||
result = CheckResult::UNKNOWN;
|
||||
break;
|
||||
default:
|
||||
solAssert(false, "");
|
||||
}
|
||||
|
||||
if (result != CheckResult::UNSATISFIABLE && !_expressionsToEvaluate.empty())
|
||||
{
|
||||
for (Expression const& e: _expressionsToEvaluate)
|
||||
values.push_back(toString(m_solver.getValue(toCVC4Expr(e))));
|
||||
}
|
||||
}
|
||||
catch (CVC4::Exception & e)
|
||||
{
|
||||
result = CheckResult::ERROR;
|
||||
values.clear();
|
||||
}
|
||||
|
||||
return make_pair(result, values);
|
||||
}
|
||||
|
||||
CVC4::Expr CVC4Interface::toCVC4Expr(Expression const& _expr)
|
||||
{
|
||||
if (_expr.arguments.empty() && m_constants.count(_expr.name))
|
||||
return m_constants.at(_expr.name);
|
||||
vector<CVC4::Expr> arguments;
|
||||
for (auto const& arg: _expr.arguments)
|
||||
arguments.push_back(toCVC4Expr(arg));
|
||||
|
||||
string const& n = _expr.name;
|
||||
if (m_functions.count(n))
|
||||
return m_context.mkExpr(CVC4::kind::APPLY_UF, m_functions[n], arguments);
|
||||
else if (m_constants.count(n))
|
||||
{
|
||||
solAssert(arguments.empty(), "");
|
||||
return m_constants.at(n);
|
||||
}
|
||||
else if (arguments.empty())
|
||||
{
|
||||
if (n == "true")
|
||||
return m_context.mkConst(true);
|
||||
else if (n == "false")
|
||||
return m_context.mkConst(false);
|
||||
else
|
||||
// We assume it is an integer...
|
||||
return m_context.mkConst(CVC4::Rational(n));
|
||||
}
|
||||
|
||||
solAssert(_expr.hasCorrectArity(), "");
|
||||
if (n == "ite")
|
||||
return arguments[0].iteExpr(arguments[1], arguments[2]);
|
||||
else if (n == "not")
|
||||
return arguments[0].notExpr();
|
||||
else if (n == "and")
|
||||
return arguments[0].andExpr(arguments[1]);
|
||||
else if (n == "or")
|
||||
return arguments[0].orExpr(arguments[1]);
|
||||
else if (n == "=")
|
||||
return m_context.mkExpr(CVC4::kind::EQUAL, arguments[0], arguments[1]);
|
||||
else if (n == "<")
|
||||
return m_context.mkExpr(CVC4::kind::LT, arguments[0], arguments[1]);
|
||||
else if (n == "<=")
|
||||
return m_context.mkExpr(CVC4::kind::LEQ, arguments[0], arguments[1]);
|
||||
else if (n == ">")
|
||||
return m_context.mkExpr(CVC4::kind::GT, arguments[0], arguments[1]);
|
||||
else if (n == ">=")
|
||||
return m_context.mkExpr(CVC4::kind::GEQ, arguments[0], arguments[1]);
|
||||
else if (n == "+")
|
||||
return m_context.mkExpr(CVC4::kind::PLUS, arguments[0], arguments[1]);
|
||||
else if (n == "-")
|
||||
return m_context.mkExpr(CVC4::kind::MINUS, arguments[0], arguments[1]);
|
||||
else if (n == "*")
|
||||
return m_context.mkExpr(CVC4::kind::MULT, arguments[0], arguments[1]);
|
||||
else if (n == "/")
|
||||
return m_context.mkExpr(CVC4::kind::INTS_DIVISION_TOTAL, arguments[0], arguments[1]);
|
||||
// Cannot reach here.
|
||||
solAssert(false, "");
|
||||
return arguments[0];
|
||||
}
|
||||
|
||||
CVC4::Type CVC4Interface::cvc4Sort(Sort _sort)
|
||||
{
|
||||
switch (_sort)
|
||||
{
|
||||
case Sort::Bool:
|
||||
return m_context.booleanType();
|
||||
case Sort::Int:
|
||||
return m_context.integerType();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
solAssert(false, "");
|
||||
// Cannot be reached.
|
||||
return m_context.integerType();
|
||||
}
|
62
libsolidity/formal/CVC4Interface.h
Normal file
62
libsolidity/formal/CVC4Interface.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libsolidity/formal/SolverInterface.h>
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
#include <cvc4/cvc4.h>
|
||||
|
||||
namespace dev
|
||||
{
|
||||
namespace solidity
|
||||
{
|
||||
namespace smt
|
||||
{
|
||||
|
||||
class CVC4Interface: public SolverInterface, public boost::noncopyable
|
||||
{
|
||||
public:
|
||||
CVC4Interface();
|
||||
|
||||
void reset() override;
|
||||
|
||||
void push() override;
|
||||
void pop() override;
|
||||
|
||||
Expression newFunction(std::string _name, Sort _domain, Sort _codomain) override;
|
||||
Expression newInteger(std::string _name) override;
|
||||
Expression newBool(std::string _name) override;
|
||||
|
||||
void addAssertion(Expression const& _expr) override;
|
||||
std::pair<CheckResult, std::vector<std::string>> check(std::vector<Expression> const& _expressionsToEvaluate) override;
|
||||
|
||||
private:
|
||||
CVC4::Expr toCVC4Expr(Expression const& _expr);
|
||||
CVC4::Type cvc4Sort(smt::Sort _sort);
|
||||
|
||||
CVC4::ExprManager m_context;
|
||||
CVC4::SmtEngine m_solver;
|
||||
std::map<std::string, CVC4::Expr> m_constants;
|
||||
std::map<std::string, CVC4::Expr> m_functions;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -19,6 +19,8 @@
|
||||
|
||||
#ifdef HAVE_Z3
|
||||
#include <libsolidity/formal/Z3Interface.h>
|
||||
#elif HAVE_CVC4
|
||||
#include <libsolidity/formal/CVC4Interface.h>
|
||||
#else
|
||||
#include <libsolidity/formal/SMTLib2Interface.h>
|
||||
#endif
|
||||
@ -39,6 +41,8 @@ using namespace dev::solidity;
|
||||
SMTChecker::SMTChecker(ErrorReporter& _errorReporter, ReadCallback::Callback const& _readFileCallback):
|
||||
#ifdef HAVE_Z3
|
||||
m_interface(make_shared<smt::Z3Interface>()),
|
||||
#elif HAVE_CVC4
|
||||
m_interface(make_shared<smt::CVC4Interface>()),
|
||||
#else
|
||||
m_interface(make_shared<smt::SMTLib2Interface>(_readFileCallback)),
|
||||
#endif
|
||||
@ -464,7 +468,7 @@ void SMTChecker::compareOperation(BinaryOperation const& _op)
|
||||
}
|
||||
else // Bool
|
||||
{
|
||||
solAssert(SSAVariable::isBool(_op.annotation().commonType->category()), "");
|
||||
solUnimplementedAssert(SSAVariable::isBool(_op.annotation().commonType->category()), "Operation not yet supported");
|
||||
value = make_shared<smt::Expression>(
|
||||
op == Token::Equal ? (left == right) :
|
||||
op == Token::NotEqual ? (left != right) :
|
||||
@ -835,7 +839,7 @@ void SMTChecker::createExpr(Expression const& _e)
|
||||
m_expressions.emplace(&_e, m_interface->newBool(uniqueSymbol(_e)));
|
||||
break;
|
||||
default:
|
||||
solAssert(false, "Type not implemented.");
|
||||
solUnimplementedAssert(false, "Type not implemented.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -65,6 +65,26 @@ public:
|
||||
Expression& operator=(Expression const&) = default;
|
||||
Expression& operator=(Expression&&) = default;
|
||||
|
||||
bool hasCorrectArity() const
|
||||
{
|
||||
static std::map<std::string, unsigned> const operatorsArity{
|
||||
{"ite", 3},
|
||||
{"not", 1},
|
||||
{"and", 2},
|
||||
{"or", 2},
|
||||
{"=", 2},
|
||||
{"<", 2},
|
||||
{"<=", 2},
|
||||
{">", 2},
|
||||
{">=", 2},
|
||||
{"+", 2},
|
||||
{"-", 2},
|
||||
{"*", 2},
|
||||
{"/", 2}
|
||||
};
|
||||
return operatorsArity.count(name) && operatorsArity.at(name) == arguments.size();
|
||||
}
|
||||
|
||||
static Expression ite(Expression _condition, Expression _trueValue, Expression _falseValue)
|
||||
{
|
||||
solAssert(_trueValue.sort == _falseValue.sort, "");
|
||||
|
@ -116,21 +116,6 @@ z3::expr Z3Interface::toZ3Expr(Expression const& _expr)
|
||||
for (auto const& arg: _expr.arguments)
|
||||
arguments.push_back(toZ3Expr(arg));
|
||||
|
||||
static map<string, unsigned> arity{
|
||||
{"ite", 3},
|
||||
{"not", 1},
|
||||
{"and", 2},
|
||||
{"or", 2},
|
||||
{"=", 2},
|
||||
{"<", 2},
|
||||
{"<=", 2},
|
||||
{">", 2},
|
||||
{">=", 2},
|
||||
{"+", 2},
|
||||
{"-", 2},
|
||||
{"*", 2},
|
||||
{"/", 2}
|
||||
};
|
||||
string const& n = _expr.name;
|
||||
if (m_functions.count(n))
|
||||
return m_functions.at(n)(arguments);
|
||||
@ -150,7 +135,7 @@ z3::expr Z3Interface::toZ3Expr(Expression const& _expr)
|
||||
return m_context.int_val(n.c_str());
|
||||
}
|
||||
|
||||
solAssert(arity.count(n) && arity.at(n) == arguments.size(), "");
|
||||
solAssert(_expr.hasCorrectArity(), "");
|
||||
if (n == "ite")
|
||||
return z3::ite(arguments[0], arguments[1], arguments[2]);
|
||||
else if (n == "not")
|
||||
|
@ -51,9 +51,6 @@ private:
|
||||
z3::expr toZ3Expr(Expression const& _expr);
|
||||
z3::sort z3Sort(smt::Sort _sort);
|
||||
|
||||
std::string checkSatAndGetValuesCommand(std::vector<Expression> const& _expressionsToEvaluate);
|
||||
std::vector<std::string> parseValues(std::string::const_iterator _start, std::string::const_iterator _end);
|
||||
|
||||
z3::context m_context;
|
||||
z3::solver m_solver;
|
||||
std::map<std::string, z3::expr> m_constants;
|
||||
|
@ -268,43 +268,39 @@ case $(uname -s) in
|
||||
install_z3=""
|
||||
case $(lsb_release -cs) in
|
||||
trusty|qiana|rebecca|rafaela|rosa)
|
||||
#trusty
|
||||
echo "Installing solidity dependencies on Ubuntu Trusty Tahr (14.04)."
|
||||
echo "Or, you may also be running Linux Mint Qiana / Rebecca / Rafaela / Rosa (base: Ubuntu Trusty Tahr (14.04).)"
|
||||
;;
|
||||
utopic)
|
||||
#utopic
|
||||
echo "Installing solidity dependencies on Ubuntu Utopic Unicorn (14.10)."
|
||||
;;
|
||||
vivid)
|
||||
#vivid
|
||||
echo "Installing solidity dependencies on Ubuntu Vivid Vervet (15.04)."
|
||||
;;
|
||||
wily)
|
||||
#wily
|
||||
echo "Installing solidity dependencies on Ubuntu Wily Werewolf (15.10)."
|
||||
;;
|
||||
xenial|sarah|serena|sonya|sylvia)
|
||||
#xenial
|
||||
echo "Installing solidity dependencies on Ubuntu Xenial Xerus (16.04)."
|
||||
echo "Or, you may also be running Linux Mint Sarah / Serena / Sonya / Sylvia (base: Ubuntu Xenial Xerus (16.04).)"
|
||||
install_z3="libz3-dev"
|
||||
;;
|
||||
yakkety)
|
||||
#yakkety
|
||||
echo "Installing solidity dependencies on Ubuntu Yakkety Yak (16.10)."
|
||||
install_z3="libz3-dev"
|
||||
;;
|
||||
zesty)
|
||||
#zesty
|
||||
echo "Installing solidity dependencies on Ubuntu Zesty (17.04)."
|
||||
install_z3="libz3-dev"
|
||||
;;
|
||||
artful)
|
||||
#artful
|
||||
echo "Installing solidity dependencies on Ubuntu Artful (17.10)."
|
||||
install_z3="libz3-dev"
|
||||
;;
|
||||
bionic)
|
||||
echo "Installing solidity dependencies on Ubuntu Bionic (18.04)."
|
||||
install_z3="libz3-dev"
|
||||
;;
|
||||
betsy)
|
||||
#do not try anything for betsy.
|
||||
echo "Linux Mint Betsy is not supported at the moment as it runs off of Debian."
|
||||
@ -319,7 +315,7 @@ case $(uname -s) in
|
||||
echo "ERROR - Unknown or unsupported Ubuntu version (" $(lsb_release -cs) ")"
|
||||
echo "ERROR - This might not work, but we are trying anyway."
|
||||
echo "Please drop us a message at https://gitter.im/ethereum/solidity-dev."
|
||||
echo "We only support Trusty, Utopic, Vivid, Wily, Xenial, Yakkety, Zesty and Artful."
|
||||
echo "We only support Trusty, Utopic, Vivid, Wily, Xenial, Yakkety, Zesty, Artful and Bionic."
|
||||
install_z3="libz3-dev"
|
||||
;;
|
||||
esac
|
||||
|
@ -54,7 +54,7 @@ keyid=703F83D0
|
||||
email=builds@ethereum.org
|
||||
packagename=solc
|
||||
|
||||
for distribution in trusty vivid xenial zesty artful
|
||||
for distribution in trusty vivid xenial zesty artful bionic
|
||||
do
|
||||
cd /tmp/
|
||||
rm -rf $distribution
|
||||
|
@ -42,13 +42,21 @@ else
|
||||
log_directory=""
|
||||
fi
|
||||
|
||||
echo "Running commandline tests..."
|
||||
function printError() { echo "$(tput setaf 1)$1$(tput sgr0)"; }
|
||||
function printTask() { echo "$(tput bold)$(tput setaf 2)$1$(tput sgr0)"; }
|
||||
|
||||
|
||||
printTask "Running commandline tests..."
|
||||
"$REPO_ROOT/test/cmdlineTests.sh" &
|
||||
CMDLINE_PID=$!
|
||||
# Only run in parallel if this is run on CI infrastructure
|
||||
if [ -z "$CI" ]
|
||||
then
|
||||
wait $CMDLINE_PID
|
||||
if ! wait $CMDLINE_PID
|
||||
then
|
||||
printError "Commandline tests FAILED"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
function download_eth()
|
||||
@ -112,7 +120,7 @@ for optimize in "" "--optimize"
|
||||
do
|
||||
for vm in $EVM_VERSIONS
|
||||
do
|
||||
echo "--> Running tests using "$optimize" --evm-version "$vm"..."
|
||||
printTask "--> Running tests using "$optimize" --evm-version "$vm"..."
|
||||
log=""
|
||||
if [ -n "$log_directory" ]
|
||||
then
|
||||
@ -127,7 +135,11 @@ do
|
||||
done
|
||||
done
|
||||
|
||||
wait $CMDLINE_PID
|
||||
if ! wait $CMDLINE_PID
|
||||
then
|
||||
printError "Commandline tests FAILED"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
pkill "$ETH_PID" || true
|
||||
sleep 4
|
||||
|
@ -35,9 +35,9 @@ for v in versions:
|
||||
continue
|
||||
versions[v]['bugs'] += [bug['name']]
|
||||
|
||||
with open(path + '/../docs/bugs_by_version.json', 'r+') as bugs_by_version:
|
||||
new_contents = json.dumps(versions, sort_keys=True, indent=4)
|
||||
with open(path + '/../docs/bugs_by_version.json', 'r') as bugs_by_version:
|
||||
old_contents = bugs_by_version.read()
|
||||
new_contents = json.dumps(versions, sort_keys=True, indent=4)
|
||||
bugs_by_version.seek(0)
|
||||
with open(path + '/../docs/bugs_by_version.json', 'w') as bugs_by_version:
|
||||
bugs_by_version.write(new_contents)
|
||||
sys.exit(old_contents != new_contents)
|
||||
sys.exit(old_contents != new_contents)
|
||||
|
@ -47,13 +47,6 @@ function test_truffle
|
||||
cd "$DIR"
|
||||
npm install
|
||||
find . -name soljson.js -exec cp "$SOLJSON" {} \;
|
||||
if [ "$name" == "Zeppelin" ]; then
|
||||
# Fix some things that look like bugs (only seemed to fail on Node 6 and not Node 8)
|
||||
# FIXME: report upstream or to web3.js?
|
||||
sed -i -e 's/let token = await ERC827TokenMock.new();//;' test/token/ERC827/ERC827Token.js
|
||||
sed -i -e 's/CappedCrowdsale.new(this.startTime, this.endTime, rate, wallet, 0)/CappedCrowdsale.new(this.startTime, this.endTime, rate, wallet, 0, this.token.address)/' test/crowdsale/CappedCrowdsale.test.js
|
||||
sed -i -e 's/RefundableCrowdsale.new(this.startTime, this.endTime, rate, wallet, 0, { from: owner })/RefundableCrowdsale.new(this.startTime, this.endTime, rate, wallet, 0, this.token.address, { from: owner })/' test/crowdsale/RefundableCrowdsale.test.js
|
||||
fi
|
||||
if [ "$name" == "Gnosis" ]; then
|
||||
# Replace fixed-version pragmas in Gnosis (part of Consensys best practice)
|
||||
find contracts test -name '*.sol' -type f -print0 | xargs -0 sed -i -e 's/pragma solidity 0/pragma solidity ^0/'
|
||||
|
@ -243,16 +243,6 @@ BOOST_AUTO_TEST_CASE(assignment_to_struct)
|
||||
CHECK_SUCCESS(text);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(returns_in_constructor)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract test {
|
||||
function test() public returns (uint a) { }
|
||||
}
|
||||
)";
|
||||
CHECK_ERROR(text, TypeError, "Non-empty \"returns\" directive for constructor.");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(forward_function_reference)
|
||||
{
|
||||
char const* text = R"(
|
||||
@ -869,26 +859,6 @@ BOOST_AUTO_TEST_CASE(complex_inheritance)
|
||||
CHECK_SUCCESS(text);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(constructor_visibility)
|
||||
{
|
||||
// The constructor of a base class should not be visible in the derived class
|
||||
char const* text = R"(
|
||||
contract A { function A() public { } }
|
||||
contract B is A { function f() public { A x = A(0); } }
|
||||
)";
|
||||
CHECK_SUCCESS(text);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(overriding_constructor)
|
||||
{
|
||||
// It is fine to "override" constructor of a base class since it is invisible
|
||||
char const* text = R"(
|
||||
contract A { function A() public { } }
|
||||
contract B is A { function A() public returns (uint8 r) {} }
|
||||
)";
|
||||
CHECK_SUCCESS(text);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(missing_base_constructor_arguments)
|
||||
{
|
||||
char const* text = R"(
|
||||
@ -907,35 +877,6 @@ BOOST_AUTO_TEST_CASE(base_constructor_arguments_override)
|
||||
CHECK_SUCCESS(text);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(new_constructor_syntax)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract A { constructor() public {} }
|
||||
)";
|
||||
CHECK_SUCCESS_NO_WARNINGS(text);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(old_constructor_syntax)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract A { function A() public {} }
|
||||
)";
|
||||
CHECK_WARNING(
|
||||
text,
|
||||
"Defining constructors as functions with the same name as the contract is deprecated."
|
||||
);
|
||||
|
||||
text = R"(
|
||||
pragma experimental "v0.5.0";
|
||||
contract A { function A() public {} }
|
||||
)";
|
||||
CHECK_ERROR(
|
||||
text,
|
||||
SyntaxError,
|
||||
"Functions are not allowed to have the same name as the contract."
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(implicit_derived_to_base_conversion)
|
||||
{
|
||||
char const* text = R"(
|
||||
@ -1199,7 +1140,6 @@ BOOST_AUTO_TEST_CASE(fallback_function_twice)
|
||||
}
|
||||
)";
|
||||
CHECK_ERROR_ALLOW_MULTI(text, DeclarationError, (vector<string>{
|
||||
"Function with same name and arguments defined twice.",
|
||||
"Only one fallback function is"
|
||||
}));
|
||||
}
|
||||
@ -2588,17 +2528,6 @@ BOOST_AUTO_TEST_CASE(override_changes_return_types)
|
||||
CHECK_ERROR(sourceCode, TypeError, "Overriding function return types differ");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(multiple_constructors)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract test {
|
||||
function test(uint a) public { }
|
||||
function test() public {}
|
||||
}
|
||||
)";
|
||||
CHECK_ERROR(sourceCode, DeclarationError, "More than one constructor defined");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(equal_overload)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
@ -3064,21 +2993,6 @@ BOOST_AUTO_TEST_CASE(literal_strings)
|
||||
CHECK_SUCCESS(text);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(memory_structs_with_mappings)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract Test {
|
||||
struct S { uint8 a; mapping(uint => uint) b; uint8 c; }
|
||||
S s;
|
||||
function f() public {
|
||||
S memory x;
|
||||
x.b[1];
|
||||
}
|
||||
}
|
||||
)";
|
||||
CHECK_ERROR(text, TypeError, "Member \"b\" is not available in struct Test.S memory outside of storage.");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(string_bytes_conversion)
|
||||
{
|
||||
char const* text = R"(
|
||||
@ -3122,19 +3036,6 @@ BOOST_AUTO_TEST_CASE(library_having_variables)
|
||||
CHECK_ERROR(text, TypeError, "Library cannot have non-constant state variables");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(library_constructor)
|
||||
{
|
||||
char const* text = R"(
|
||||
library Lib {
|
||||
function Lib();
|
||||
}
|
||||
)";
|
||||
CHECK_ERROR_ALLOW_MULTI(text, TypeError, (vector<std::string>{
|
||||
"Constructor cannot be defined in libraries.",
|
||||
"Constructor must be implemented if declared."
|
||||
}));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(valid_library)
|
||||
{
|
||||
char const* text = R"(
|
||||
@ -5030,38 +4931,6 @@ BOOST_AUTO_TEST_CASE(unsatisfied_version)
|
||||
BOOST_CHECK(searchErrorMessage(*sourceAndError.second.front(), "Source file requires different compiler version"));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(invalid_constructor_statemutability)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract test {
|
||||
function test() constant {}
|
||||
}
|
||||
)";
|
||||
CHECK_ERROR(text, TypeError, "Constructor must be payable or non-payable");
|
||||
text = R"(
|
||||
contract test {
|
||||
function test() view {}
|
||||
}
|
||||
)";
|
||||
CHECK_ERROR(text, TypeError, "Constructor must be payable or non-payable");
|
||||
text = R"(
|
||||
contract test {
|
||||
function test() pure {}
|
||||
}
|
||||
)";
|
||||
CHECK_ERROR(text, TypeError, "Constructor must be payable or non-payable");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(external_constructor)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract test {
|
||||
function test() external {}
|
||||
}
|
||||
)";
|
||||
CHECK_ERROR(text, TypeError, "Constructor must be public or internal.");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(invalid_array_as_statement)
|
||||
{
|
||||
char const* text = R"(
|
||||
@ -5608,50 +5477,6 @@ BOOST_AUTO_TEST_CASE(assignment_to_constant)
|
||||
CHECK_ERROR(text, TypeError, "Cannot assign to a constant variable.");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(inconstructible_internal_constructor)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract C {
|
||||
function C() internal {}
|
||||
}
|
||||
contract D {
|
||||
function f() public { var x = new C(); }
|
||||
}
|
||||
)";
|
||||
CHECK_ERROR(text, TypeError, "Contract with internal constructor cannot be created directly.");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(inconstructible_internal_constructor_inverted)
|
||||
{
|
||||
// Previously, the type information for A was not yet available at the point of
|
||||
// "new A".
|
||||
char const* text = R"(
|
||||
contract B {
|
||||
A a;
|
||||
function B() public {
|
||||
a = new A(this);
|
||||
}
|
||||
}
|
||||
contract A {
|
||||
function A(address a) internal {}
|
||||
}
|
||||
)";
|
||||
CHECK_ERROR(text, TypeError, "Contract with internal constructor cannot be created directly.");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(constructible_internal_constructor)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract C {
|
||||
function C() internal {}
|
||||
}
|
||||
contract D is C {
|
||||
function D() public { }
|
||||
}
|
||||
)";
|
||||
CHECK_SUCCESS(text);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(return_structs)
|
||||
{
|
||||
char const* text = R"(
|
||||
@ -5813,19 +5638,6 @@ BOOST_AUTO_TEST_CASE(interface)
|
||||
CHECK_SUCCESS(text);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(interface_constructor)
|
||||
{
|
||||
char const* text = R"(
|
||||
interface I {
|
||||
function I();
|
||||
}
|
||||
)";
|
||||
CHECK_ERROR_ALLOW_MULTI(text, TypeError, (std::vector<std::string>{
|
||||
"Constructor cannot be defined in interfaces",
|
||||
"Constructor must be implemented if declared.",
|
||||
}));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(interface_functions)
|
||||
{
|
||||
char const* text = R"(
|
||||
@ -6907,16 +6719,6 @@ BOOST_AUTO_TEST_CASE(builtin_reject_value)
|
||||
CHECK_ERROR(text, TypeError, "Member \"value\" not found or not visible after argument-dependent lookup");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(constructor_without_implementation)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract C {
|
||||
function C();
|
||||
}
|
||||
)";
|
||||
CHECK_ERROR(text, TypeError, "Constructor must be implemented if declared.");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(large_storage_array_fine)
|
||||
{
|
||||
char const* text = R"(
|
||||
|
@ -0,0 +1,6 @@
|
||||
contract C {
|
||||
constructor() internal {}
|
||||
}
|
||||
contract D is C {
|
||||
constructor() public { }
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
contract C {
|
||||
function C() internal {}
|
||||
}
|
||||
contract D is C {
|
||||
function D() public {}
|
||||
}
|
||||
// ----
|
||||
// Warning: (14-38): Defining constructors as functions with the same name as the contract is deprecated. Use "constructor(...) { ... }" instead.
|
||||
// Warning: (60-82): Defining constructors as functions with the same name as the contract is deprecated. Use "constructor(...) { ... }" instead.
|
@ -0,0 +1 @@
|
||||
contract A { constructor() public {} }
|
@ -0,0 +1,3 @@
|
||||
contract A { function A() public {} }
|
||||
// ----
|
||||
// Warning: (13-35): Defining constructors as functions with the same name as the contract is deprecated. Use "constructor(...) { ... }" instead.
|
@ -0,0 +1,4 @@
|
||||
pragma experimental "v0.5.0";
|
||||
contract A { function A() public {} }
|
||||
// ----
|
||||
// SyntaxError: (43-65): Functions are not allowed to have the same name as the contract. If you intend this to be a constructor, use "constructor(...) { ... }" to define it.
|
@ -0,0 +1,13 @@
|
||||
contract test1 {
|
||||
constructor() constant {}
|
||||
}
|
||||
contract test2 {
|
||||
constructor() view {}
|
||||
}
|
||||
contract test3 {
|
||||
constructor() pure {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (19-44): Constructor must be payable or non-payable, but is "view".
|
||||
// TypeError: (66-87): Constructor must be payable or non-payable, but is "view".
|
||||
// TypeError: (109-130): Constructor must be payable or non-payable, but is "pure".
|
@ -0,0 +1,16 @@
|
||||
contract test1 {
|
||||
function test1() constant {}
|
||||
}
|
||||
contract test2 {
|
||||
function test2() view {}
|
||||
}
|
||||
contract test3 {
|
||||
function test3() pure {}
|
||||
}
|
||||
// ----
|
||||
// Warning: (21-49): Defining constructors as functions with the same name as the contract is deprecated. Use "constructor(...) { ... }" instead.
|
||||
// Warning: (73-97): Defining constructors as functions with the same name as the contract is deprecated. Use "constructor(...) { ... }" instead.
|
||||
// Warning: (121-145): Defining constructors as functions with the same name as the contract is deprecated. Use "constructor(...) { ... }" instead.
|
||||
// TypeError: (21-49): Constructor must be payable or non-payable, but is "view".
|
||||
// TypeError: (73-97): Constructor must be payable or non-payable, but is "view".
|
||||
// TypeError: (121-145): Constructor must be payable or non-payable, but is "pure".
|
@ -0,0 +1,12 @@
|
||||
// The constructor of a base class should not be visible in the derived class
|
||||
contract A { constructor(string) public { } }
|
||||
contract B is A {
|
||||
function f() pure public {
|
||||
A x = A(0); // convert from address
|
||||
string memory y = "ab";
|
||||
A(y); // call as a function is invalid
|
||||
x;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (243-247): Explicit type conversion not allowed from "string memory" to "contract A".
|
@ -0,0 +1,13 @@
|
||||
// The constructor of a base class should not be visible in the derived class
|
||||
contract A { function A(string s) public { } }
|
||||
contract B is A {
|
||||
function f() pure public {
|
||||
A x = A(0); // convert from address
|
||||
string memory y = "ab";
|
||||
A(y); // call as a function is invalid
|
||||
x;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning: (91-122): Defining constructors as functions with the same name as the contract is deprecated. Use "constructor(...) { ... }" instead.
|
||||
// TypeError: (244-248): Explicit type conversion not allowed from "string memory" to "contract A".
|
@ -0,0 +1,5 @@
|
||||
contract C {
|
||||
constructor();
|
||||
}
|
||||
// ----
|
||||
// TypeError: (14-28): Constructor must be implemented if declared.
|
@ -0,0 +1,6 @@
|
||||
contract C {
|
||||
function C();
|
||||
}
|
||||
// ----
|
||||
// Warning: (14-27): Defining constructors as functions with the same name as the contract is deprecated. Use "constructor(...) { ... }" instead.
|
||||
// TypeError: (14-27): Constructor must be implemented if declared.
|
@ -0,0 +1,5 @@
|
||||
contract test {
|
||||
constructor() external {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (17-42): Constructor must be public or internal.
|
@ -0,0 +1,6 @@
|
||||
contract test {
|
||||
function test() external {}
|
||||
}
|
||||
// ----
|
||||
// Warning: (17-44): Defining constructors as functions with the same name as the contract is deprecated. Use "constructor(...) { ... }" instead.
|
||||
// TypeError: (17-44): Constructor must be public or internal.
|
@ -0,0 +1,5 @@
|
||||
contract C {
|
||||
function constructor() public;
|
||||
}
|
||||
// ----
|
||||
// Warning: (17-47): This function is named "constructor" but is not the constructor of the contract. If you intend this to be a constructor, use "constructor(...) { ... }" without the "function" keyword to define it.
|
@ -0,0 +1,13 @@
|
||||
// Previously, the type information for A was not yet available at the point of
|
||||
// "new A".
|
||||
contract B {
|
||||
A a;
|
||||
constructor() public {
|
||||
a = new A(this);
|
||||
}
|
||||
}
|
||||
contract A {
|
||||
constructor(address a) internal {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (141-146): Contract with internal constructor cannot be created directly.
|
@ -0,0 +1,15 @@
|
||||
// Previously, the type information for A was not yet available at the point of
|
||||
// "new A".
|
||||
contract B {
|
||||
A a;
|
||||
function B() public {
|
||||
a = new A(this);
|
||||
}
|
||||
}
|
||||
contract A {
|
||||
function A(address a) internal {}
|
||||
}
|
||||
// ----
|
||||
// Warning: (112-155): Defining constructors as functions with the same name as the contract is deprecated. Use "constructor(...) { ... }" instead.
|
||||
// Warning: (172-205): Defining constructors as functions with the same name as the contract is deprecated. Use "constructor(...) { ... }" instead.
|
||||
// TypeError: (140-145): Contract with internal constructor cannot be created directly.
|
@ -0,0 +1,8 @@
|
||||
contract C {
|
||||
constructor() internal {}
|
||||
}
|
||||
contract D {
|
||||
function f() public { C c = new C(); c; }
|
||||
}
|
||||
// ----
|
||||
// TypeError: (84-89): Contract with internal constructor cannot be created directly.
|
@ -0,0 +1,9 @@
|
||||
contract C {
|
||||
function C() internal {}
|
||||
}
|
||||
contract D {
|
||||
function f() public { C x = new C(); x; }
|
||||
}
|
||||
// ----
|
||||
// Warning: (14-38): Defining constructors as functions with the same name as the contract is deprecated. Use "constructor(...) { ... }" instead.
|
||||
// TypeError: (83-88): Contract with internal constructor cannot be created directly.
|
@ -0,0 +1,7 @@
|
||||
interface I {
|
||||
constructor();
|
||||
}
|
||||
// ----
|
||||
// Warning: (15-29): Functions in interfaces should be declared external.
|
||||
// TypeError: (15-29): Constructor cannot be defined in interfaces.
|
||||
// TypeError: (15-29): Constructor must be implemented if declared.
|
@ -0,0 +1,8 @@
|
||||
interface I {
|
||||
function I();
|
||||
}
|
||||
// ----
|
||||
// Warning: (15-28): Defining constructors as functions with the same name as the contract is deprecated. Use "constructor(...) { ... }" instead.
|
||||
// Warning: (15-28): Functions in interfaces should be declared external.
|
||||
// TypeError: (15-28): Constructor cannot be defined in interfaces.
|
||||
// TypeError: (15-28): Constructor must be implemented if declared.
|
@ -0,0 +1,6 @@
|
||||
library Lib {
|
||||
constructor();
|
||||
}
|
||||
// ----
|
||||
// TypeError: (15-29): Constructor cannot be defined in libraries.
|
||||
// TypeError: (15-29): Constructor must be implemented if declared.
|
@ -0,0 +1,7 @@
|
||||
library Lib {
|
||||
function Lib();
|
||||
}
|
||||
// ----
|
||||
// Warning: (15-30): Defining constructors as functions with the same name as the contract is deprecated. Use "constructor(...) { ... }" instead.
|
||||
// TypeError: (15-30): Constructor cannot be defined in libraries.
|
||||
// TypeError: (15-30): Constructor must be implemented if declared.
|
@ -0,0 +1,6 @@
|
||||
// It is fine to "override" constructor of a base class since it is invisible
|
||||
contract A { function A() public { } }
|
||||
contract B is A { function A() public pure returns (uint8) {} }
|
||||
// ----
|
||||
// Warning: (91-114): Defining constructors as functions with the same name as the contract is deprecated. Use "constructor(...) { ... }" instead.
|
||||
// Warning: (135-178): This declaration shadows an existing declaration.
|
@ -0,0 +1,5 @@
|
||||
contract test {
|
||||
constructor() public returns (uint a) { }
|
||||
}
|
||||
// ----
|
||||
// TypeError: (46-54): Non-empty "returns" directive for constructor.
|
@ -0,0 +1,6 @@
|
||||
contract test {
|
||||
function test() public returns (uint a) { }
|
||||
}
|
||||
// ----
|
||||
// Warning: (17-60): Defining constructors as functions with the same name as the contract is deprecated. Use "constructor(...) { ... }" instead.
|
||||
// TypeError: (48-56): Non-empty "returns" directive for constructor.
|
@ -0,0 +1,7 @@
|
||||
contract test {
|
||||
function test(uint) public { }
|
||||
constructor() public {}
|
||||
}
|
||||
// ----
|
||||
// Warning: (17-47): Defining constructors as functions with the same name as the contract is deprecated. Use "constructor(...) { ... }" instead.
|
||||
// DeclarationError: (49-72): More than one constructor defined.
|
@ -0,0 +1,6 @@
|
||||
contract test {
|
||||
constructor(uint) public { }
|
||||
constructor() public {}
|
||||
}
|
||||
// ----
|
||||
// DeclarationError: (47-70): More than one constructor defined.
|
@ -0,0 +1,8 @@
|
||||
contract test {
|
||||
function test(uint a) public { }
|
||||
function test() public {}
|
||||
}
|
||||
// ----
|
||||
// Warning: (17-49): Defining constructors as functions with the same name as the contract is deprecated. Use "constructor(...) { ... }" instead.
|
||||
// Warning: (51-76): Defining constructors as functions with the same name as the contract is deprecated. Use "constructor(...) { ... }" instead.
|
||||
// DeclarationError: (51-76): More than one constructor defined.
|
@ -0,0 +1,7 @@
|
||||
contract C {
|
||||
function f(uint, uint) {}
|
||||
function f(uint) {}
|
||||
function g() { f(1, 2, 3); }
|
||||
}
|
||||
// ----
|
||||
// TypeError: (80-81): No matching declaration found after argument-dependent lookup.
|
@ -0,0 +1,9 @@
|
||||
library L {
|
||||
function f(uint, uint) {}
|
||||
function f(uint) {}
|
||||
}
|
||||
contract C {
|
||||
function g() { L.f(1, 2, 3); }
|
||||
}
|
||||
// ----
|
||||
// TypeError: (94-97): Member "f" not found or not visible after argument-dependent lookup in type(library L)
|
@ -0,0 +1,10 @@
|
||||
contract Test {
|
||||
struct S { uint8 a; mapping(uint => uint) b; uint8 c; }
|
||||
S s;
|
||||
function f() public {
|
||||
S memory x;
|
||||
x.b[1];
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (118-121): Member "b" is not available in struct Test.S memory outside of storage.
|
@ -0,0 +1,8 @@
|
||||
contract Test {
|
||||
function f() public pure {
|
||||
uint[] memory x;
|
||||
x.push(1);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (77-83): Member "push" is not available in uint256[] memory outside of storage.
|
7
test/libsolidity/syntaxTests/types/bytes_to_contract.sol
Normal file
7
test/libsolidity/syntaxTests/types/bytes_to_contract.sol
Normal file
@ -0,0 +1,7 @@
|
||||
contract C {
|
||||
function f() public pure {
|
||||
C(bytes20(0x1234));
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (64-82): Explicit type conversion not allowed from "bytes20" to "contract C".
|
Loading…
Reference in New Issue
Block a user