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.
* 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``.
* 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: 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)``.

View File

@ -40,6 +40,8 @@ New Restrictions
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.
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;
}
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(
9886_error,
_functionCallOptions.location(),
_alreadySet ?
"Option \"" + std::move(_name) + "\" has already been set." :
"Duplicate option \"" + std::move(_name) + "\"."
);
@ -2446,7 +2456,7 @@ bool TypeChecker::visit(FunctionCallOptions const& _functionCallOptions)
{
if (kind == FunctionType::Kind::Creation)
{
setCheckOption(setSalt, "salt", expressionFunctionType->saltSet());
setCheckOption(setSalt, "salt");
expectType(*_functionCallOptions.options()[i], *TypeProvider::fixedBytes(32));
}
else
@ -2484,7 +2494,7 @@ bool TypeChecker::visit(FunctionCallOptions const& _functionCallOptions)
{
expectType(*_functionCallOptions.options()[i], *TypeProvider::uint256());
setCheckOption(setValue, "value", expressionFunctionType->valueSet());
setCheckOption(setValue, "value");
}
}
else if (name == "gas")
@ -2499,7 +2509,7 @@ bool TypeChecker::visit(FunctionCallOptions const& _functionCallOptions)
{
expectType(*_functionCallOptions.options()[i], *TypeProvider::uint256());
setCheckOption(setGas, "gas", expressionFunctionType->gasSet());
setCheckOption(setGas, "gas");
}
}
else

View File

@ -5,8 +5,9 @@ contract C {
v = this.f{value: 10}(2);
x = this.f{gas: 1000}(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 {}
}
// ====
@ -14,3 +15,4 @@ contract C {
// ----
// (), 1 ether
// call() -> 1, 2, 2, 2
// bal() -> 1000000000000000000

View File

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

View File

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