More strict override check for data locations.

This commit is contained in:
chriseth
2022-05-17 13:02:12 +02:00
parent bef348aa6a
commit dfa0bcf760
13 changed files with 165 additions and 11 deletions
@@ -39,7 +39,7 @@ namespace
{
template <class T, class B>
bool hasEqualParameters(T const& _a, B const& _b)
bool hasEqualExternalCallableParameters(T const& _a, B const& _b)
{
return FunctionType(_a).asExternallyCallableFunction(false)->hasEqualParameterTypes(
*FunctionType(_b).asExternallyCallableFunction(false)
@@ -204,7 +204,7 @@ void ContractLevelChecker::findDuplicateDefinitions(map<string, vector<T>> const
SecondarySourceLocation ssl;
for (size_t j = i + 1; j < overloads.size(); ++j)
if (hasEqualParameters(*overloads[i], *overloads[j]))
if (hasEqualExternalCallableParameters(*overloads[i], *overloads[j]))
{
solAssert(
(
+47 -5
View File
@@ -313,7 +313,7 @@ Token OverrideProxy::functionKind() const
}, m_item);
}
FunctionType const* OverrideProxy::functionType() const
FunctionType const* OverrideProxy::externalFunctionType() const
{
return std::visit(GenericVisitor{
[&](FunctionDefinition const* _item) { return FunctionType(*_item).asExternallyCallableFunction(false); },
@@ -322,6 +322,15 @@ FunctionType const* OverrideProxy::functionType() const
}, m_item);
}
FunctionType const* OverrideProxy::originalFunctionType() const
{
return std::visit(GenericVisitor{
[&](FunctionDefinition const* _item) { return TypeProvider::function(*_item); },
[&](VariableDeclaration const*) -> FunctionType const* { solAssert(false, "Requested specific function type of variable."); return nullptr; },
[&](ModifierDefinition const*) -> FunctionType const* { solAssert(false, "Requested specific function type of modifier."); return nullptr; }
}, m_item);
}
ModifierType const* OverrideProxy::modifierType() const
{
return std::visit(GenericVisitor{
@@ -413,7 +422,7 @@ OverrideProxy::OverrideComparator const& OverrideProxy::overrideComparator() con
[&](FunctionDefinition const* _function)
{
vector<string> paramTypes;
for (Type const* t: functionType()->parameterTypes())
for (Type const* t: externalFunctionType()->parameterTypes())
paramTypes.emplace_back(t->richIdentifier());
return OverrideComparator{
_function->name(),
@@ -424,7 +433,7 @@ OverrideProxy::OverrideComparator const& OverrideProxy::overrideComparator() con
[&](VariableDeclaration const* _var)
{
vector<string> paramTypes;
for (Type const* t: functionType()->parameterTypes())
for (Type const* t: externalFunctionType()->parameterTypes())
paramTypes.emplace_back(t->richIdentifier());
return OverrideComparator{
_var->name(),
@@ -589,14 +598,17 @@ void OverrideChecker::checkOverride(OverrideProxy const& _overriding, OverridePr
if (_super.isFunction())
{
FunctionType const* functionType = _overriding.functionType();
FunctionType const* superType = _super.functionType();
FunctionType const* functionType = _overriding.externalFunctionType();
FunctionType const* superType = _super.externalFunctionType();
bool returnTypesDifferAlready = false;
if (_overriding.functionKind() != Token::Fallback)
{
solAssert(functionType->hasEqualParameterTypes(*superType), "Override doesn't have equal parameters!");
if (!functionType->hasEqualReturnTypes(*superType))
{
returnTypesDifferAlready = true;
overrideError(
_overriding,
_super,
@@ -604,6 +616,36 @@ void OverrideChecker::checkOverride(OverrideProxy const& _overriding, OverridePr
"Overriding " + _overriding.astNodeName() + " return types differ.",
"Overridden " + _overriding.astNodeName() + " is here:"
);
}
}
// The override proxy considers calldata and memory the same data location.
// Here we do a more specific check:
// Data locations of parameters and return variables have to match
// unless we have a public function overriding an external one.
if (
_overriding.isFunction() &&
!returnTypesDifferAlready &&
_super.visibility() != Visibility::External &&
_overriding.functionKind() != Token::Fallback
)
{
if (!_overriding.originalFunctionType()->hasEqualParameterTypes(*_super.originalFunctionType()))
overrideError(
_overriding,
_super,
7723_error,
"Data locations of parameters have to be the same when overriding non-external functions, but they differ.",
"Overridden " + _overriding.astNodeName() + " is here:"
);
if (!_overriding.originalFunctionType()->hasEqualReturnTypes(*_super.originalFunctionType()))
overrideError(
_overriding,
_super,
1443_error,
"Data locations of return variables have to be the same when overriding non-external functions, but they differ.",
"Overridden " + _overriding.astNodeName() + " is here:"
);
}
// Stricter mutability is always okay except when super is Payable
+5 -1
View File
@@ -84,7 +84,10 @@ public:
/// @returns receive / fallback / function (only the latter for modifiers and variables);
langutil::Token functionKind() const;
FunctionType const* functionType() const;
/// @returns the externally callable function type
FunctionType const* externalFunctionType() const;
/// @returns the (unmodified) function type
FunctionType const* originalFunctionType() const;
ModifierType const* modifierType() const;
Declaration const* declaration() const;
@@ -101,6 +104,7 @@ public:
/**
* Struct to help comparing override items about whether they override each other.
* Compares functions based on their "externally callable" type.
* Does not produce a total order.
*/
struct OverrideComparator