Disallow specifying call options multiple times.

This commit is contained in:
chriseth 2020-11-02 14:10:37 +01:00
parent ce50f05fc1
commit b287a6e995
6 changed files with 30 additions and 16 deletions

View File

@ -4,6 +4,7 @@ Breaking Changes:
* Assembler: The artificial ASSIGNIMMUTABLE opcode and the corresponding builtin in the "EVM with object access" dialect of Yul take the base offset of the code to modify as additional argument. * Assembler: The artificial ASSIGNIMMUTABLE opcode and the corresponding builtin in the "EVM with object access" dialect of Yul take the base offset of the code to modify as additional argument.
* Code Generator: All arithmetic is checked by default. These checks can be disabled using ``unchecked { ... }``. * Code Generator: All arithmetic is checked by default. These checks can be disabled using ``unchecked { ... }``.
* General: Remove global functions ``log0``, ``log1``, ``log2``, ``log3`` and ``log4``. * General: Remove global functions ``log0``, ``log1``, ``log2``, ``log3`` and ``log4``.
* Type Checker: Function call options can only be given once.
* Type System: Unary negation can only be used on signed integers, not on unsigned integers. * Type System: Unary negation can only be used on signed integers, not on unsigned integers.
* Type System: Disallow explicit conversions from negative literals and literals larger than ``type(uint160).max`` to ``address`` type. * Type System: Disallow explicit conversions from negative literals and literals larger than ``type(uint160).max`` to ``address`` type.
* Parser: Exponentiation is right associative. ``a**b**c`` is parsed as ``a**(b**c)``. * Parser: Exponentiation is right associative. ``a**b**c`` is parsed as ``a**(b**c)``.

View File

@ -40,6 +40,8 @@ New Restrictions
The previous behaviour was likely ambiguous. The previous behaviour was likely ambiguous.
* Function call options can only be given once, i.e. ``c.f{gas: 10000}{value: 1}()`` is invalid and has to be changed to ``c.f{gas: 10000, value: 1}()``.
* The global functions ``log0``, ``log1``, ``log2``, ``log3`` and ``log4`` have been removed. * The global functions ``log0``, ``log1``, ``log2``, ``log3`` and ``log4`` have been removed.
These are low-level functions that were largely unused. Their behaviour can be accessed from inline assembly. These are low-level functions that were largely unused. Their behaviour can be accessed from inline assembly.

View File

@ -2425,14 +2425,24 @@ bool TypeChecker::visit(FunctionCallOptions const& _functionCallOptions)
return false; return false;
} }
auto setCheckOption = [&](bool& _option, string const&& _name, bool _alreadySet = false) if (
expressionFunctionType->valueSet() ||
expressionFunctionType->gasSet() ||
expressionFunctionType->saltSet()
)
m_errorReporter.typeError(
1645_error,
_functionCallOptions.location(),
"Function call options have already been set, you have to combine them into a single "
"{...}-option."
);
auto setCheckOption = [&](bool& _option, string const& _name)
{ {
if (_option || _alreadySet) if (_option)
m_errorReporter.typeError( m_errorReporter.typeError(
9886_error, 9886_error,
_functionCallOptions.location(), _functionCallOptions.location(),
_alreadySet ?
"Option \"" + std::move(_name) + "\" has already been set." :
"Duplicate option \"" + std::move(_name) + "\"." "Duplicate option \"" + std::move(_name) + "\"."
); );
@ -2446,7 +2456,7 @@ bool TypeChecker::visit(FunctionCallOptions const& _functionCallOptions)
{ {
if (kind == FunctionType::Kind::Creation) if (kind == FunctionType::Kind::Creation)
{ {
setCheckOption(setSalt, "salt", expressionFunctionType->saltSet()); setCheckOption(setSalt, "salt");
expectType(*_functionCallOptions.options()[i], *TypeProvider::fixedBytes(32)); expectType(*_functionCallOptions.options()[i], *TypeProvider::fixedBytes(32));
} }
else else
@ -2484,7 +2494,7 @@ bool TypeChecker::visit(FunctionCallOptions const& _functionCallOptions)
{ {
expectType(*_functionCallOptions.options()[i], *TypeProvider::uint256()); expectType(*_functionCallOptions.options()[i], *TypeProvider::uint256());
setCheckOption(setValue, "value", expressionFunctionType->valueSet()); setCheckOption(setValue, "value");
} }
} }
else if (name == "gas") else if (name == "gas")
@ -2499,7 +2509,7 @@ bool TypeChecker::visit(FunctionCallOptions const& _functionCallOptions)
{ {
expectType(*_functionCallOptions.options()[i], *TypeProvider::uint256()); expectType(*_functionCallOptions.options()[i], *TypeProvider::uint256());
setCheckOption(setGas, "gas", expressionFunctionType->gasSet()); setCheckOption(setGas, "gas");
} }
} }
else else

View File

@ -5,8 +5,9 @@ contract C {
v = this.f{value: 10}(2); v = this.f{value: 10}(2);
x = this.f{gas: 1000}(2, 3); x = this.f{gas: 1000}(2, 3);
y = this.f{gas: 1000, value: 10}(2, 3); y = this.f{gas: 1000, value: 10}(2, 3);
z = this.f{gas: 1000}{value: 10}(2, 3); z = this.f{value: 10, gas: 1000}(2, 3);
} }
function bal() external returns (uint) { return address(this).balance; }
receive() external payable {} receive() external payable {}
} }
// ==== // ====
@ -14,3 +15,4 @@ contract C {
// ---- // ----
// (), 1 ether // (), 1 ether
// call() -> 1, 2, 2, 2 // call() -> 1, 2, 2, 2
// bal() -> 1000000000000000000

View File

@ -12,8 +12,8 @@ contract B
contract A { contract A {
function f() public payable returns (uint, uint, uint) { function f() public payable returns (uint, uint, uint) {
B x = new B{salt: "abc", value: 3}(7); B x = new B{salt: "abc", value: 3}(7);
B y = new B{value: 3}{salt: "abc"}(8); B y = new B{value: 3, salt: "abc"}(8);
B z = new B{value: 3, salt: "abc"}(9); B z = new B{salt: "abc", value: 3}(9);
return (x.getBalance(), y.getBalance(), z.getBalance()); return (x.getBalance(), y.getBalance(), z.getBalance());
} }
} }

View File

@ -11,9 +11,8 @@ contract C {
// ==== // ====
// EVMVersion: >=constantinople // EVMVersion: >=constantinople
// ---- // ----
// TypeError 9886: (78-110): Option "gas" has already been set. // TypeError 1645: (78-110): Function call options have already been set, you have to combine them into a single {...}-option.
// TypeError 9886: (120-154): Option "gas" has already been set. // TypeError 1645: (120-154): Function call options have already been set, you have to combine them into a single {...}-option.
// TypeError 9886: (164-198): Option "value" has already been set. // TypeError 1645: (164-198): Function call options have already been set, you have to combine them into a single {...}-option.
// TypeError 9886: (208-249): Option "value" has already been set. // TypeError 1645: (208-249): Function call options have already been set, you have to combine them into a single {...}-option.
// TypeError 9886: (208-249): Option "gas" has already been set. // TypeError 1645: (259-286): Function call options have already been set, you have to combine them into a single {...}-option.
// TypeError 9886: (259-286): Option "salt" has already been set.