Merge pull request #9024 from ethereum/namableTypes

Disallow non-namable types for inline arrays.
This commit is contained in:
chriseth 2020-05-27 09:21:07 +02:00 committed by GitHub
commit f066050ec0
7 changed files with 51 additions and 0 deletions

View File

@ -13,6 +13,7 @@ Compiler Features:
Bugfixes:
* Optimizer: Fixed a bug in BlockDeDuplicator.
* Type Checker: Disallow assignments to storage variables of type ``mapping``.
* Type Checker: Disallow inline arrays of non-nameable types.
* Type Checker: Fix internal compiler error when accessing members of array slices.
* NatSpec: DocString block is terminated when encountering an empty line.
* Scanner: Fix bug when two empty NatSpec comments lead to scanning past EOL.

View File

@ -1509,6 +1509,12 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
{
if (!inlineArrayType)
m_errorReporter.fatalTypeError(6378_error, _tuple.location(), "Unable to deduce common type for array elements.");
else if (!inlineArrayType->nameable())
m_errorReporter.fatalTypeError(
9656_error,
_tuple.location(),
"Unable to deduce nameable type for array elements. Try adding explicit type conversion for the first element."
);
else if (!inlineArrayType->canLiveOutsideStorage())
m_errorReporter.fatalTypeError(1545_error, _tuple.location(), "Type " + inlineArrayType->toString() + " is only valid in storage.");

View File

@ -3029,6 +3029,17 @@ unsigned FunctionType::storageBytes() const
solAssert(false, "Storage size of non-storable function type requested.");
}
bool FunctionType::nameable() const
{
return
(m_kind == Kind::Internal || m_kind == Kind::External) &&
!m_bound &&
!m_arbitraryParameters &&
!m_gasSet &&
!m_valueSet &&
!m_saltSet;
}
vector<tuple<string, TypePointer>> FunctionType::makeStackItems() const
{
vector<tuple<string, TypePointer>> slots;

View File

@ -263,6 +263,10 @@ public:
/// Returns true if the type can be stored as a value (as opposed to a reference) on the stack,
/// i.e. it behaves differently in lvalue context and in value context.
virtual bool isValueType() const { return false; }
/// @returns true if this type can be used for variables. It returns false for
/// types like magic types, literals and function types with a kind that is not
/// internal or external.
virtual bool nameable() const { return false; }
/// @returns a list of named and typed stack items that determine the layout of this type on the stack.
/// A stack item either has an empty name and type ``nullptr`` referring to a single stack slot, or
/// has a non-empty name and a valid type referring to the stack layout of that type.
@ -402,6 +406,7 @@ public:
unsigned storageBytes() const override { return 160 / 8; }
bool leftAligned() const override { return false; }
bool isValueType() const override { return true; }
bool nameable() const override { return true; }
MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
@ -446,6 +451,7 @@ public:
unsigned storageBytes() const override { return m_bits / 8; }
bool leftAligned() const override { return false; }
bool isValueType() const override { return true; }
bool nameable() const override { return true; }
std::string toString(bool _short) const override;
@ -492,6 +498,7 @@ public:
unsigned storageBytes() const override { return m_totalBits / 8; }
bool leftAligned() const override { return false; }
bool isValueType() const override { return true; }
bool nameable() const override { return true; }
std::string toString(bool _short) const override;
@ -639,6 +646,7 @@ public:
unsigned storageBytes() const override { return m_bytes; }
bool leftAligned() const override { return true; }
bool isValueType() const override { return true; }
bool nameable() const override { return true; }
std::string toString(bool) const override { return "bytes" + util::toString(m_bytes); }
MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
@ -666,6 +674,7 @@ public:
unsigned storageBytes() const override { return 1; }
bool leftAligned() const override { return false; }
bool isValueType() const override { return true; }
bool nameable() const override { return true; }
std::string toString(bool) const override { return "bool"; }
u256 literalValue(Literal const* _literal) const override;
@ -773,6 +782,7 @@ public:
bool isDynamicallyEncoded() const override;
u256 storageSize() const override;
bool canLiveOutsideStorage() const override { return m_baseType->canLiveOutsideStorage(); }
bool nameable() const override { return true; }
std::string toString(bool _short) const override;
std::string canonicalName() const override;
std::string signatureInExternalFunction(bool _structsByName) const override;
@ -875,6 +885,7 @@ public:
bool leftAligned() const override { solAssert(!isSuper(), ""); return false; }
bool canLiveOutsideStorage() const override { return !isSuper(); }
bool isValueType() const override { return !isSuper(); }
bool nameable() const override { return !isSuper(); }
std::string toString(bool _short) const override;
std::string canonicalName() const override;
@ -935,6 +946,7 @@ public:
u256 memoryDataSize() const override;
u256 storageSize() const override;
bool canLiveOutsideStorage() const override { return true; }
bool nameable() const override { return true; }
std::string toString(bool _short) const override;
MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
@ -997,6 +1009,7 @@ public:
std::string toString(bool _short) const override;
std::string canonicalName() const override;
bool isValueType() const override { return true; }
bool nameable() const override { return true; }
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
TypePointer encodingType() const override;
@ -1202,6 +1215,7 @@ public:
bool leftAligned() const override;
unsigned storageBytes() const override;
bool isValueType() const override { return true; }
bool nameable() const override;
bool canLiveOutsideStorage() const override { return m_kind == Kind::Internal || m_kind == Kind::External; }
bool hasSimpleZeroValueInMemory() const override { return false; }
MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
@ -1339,6 +1353,7 @@ public:
bool dataStoredIn(DataLocation _location) const override { return _location == DataLocation::Storage; }
/// Cannot be stored in memory, but just in case.
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
bool nameable() const override { return true; }
Type const* keyType() const { return m_keyType; }
Type const* valueType() const { return m_valueType; }

View File

@ -1022,6 +1022,10 @@ void CompilerUtils::convertType(
case Type::Category::ArraySlice:
{
auto& typeOnStack = dynamic_cast<ArraySliceType const&>(_typeOnStack);
solUnimplementedAssert(
_targetType.dataStoredIn(DataLocation::CallData),
"Conversion from calldata slices to memory not yet implemented."
);
solAssert(_targetType == typeOnStack.arrayType(), "");
solUnimplementedAssert(
typeOnStack.arrayType().location() == DataLocation::CallData &&

View File

@ -0,0 +1,7 @@
contract C {
function f() public {
[msg];
}
}
// ----
// TypeError: (47-52): Unable to deduce nameable type for array elements. Try adding explicit type conversion for the first element.

View File

@ -0,0 +1,7 @@
contract C {
function f() public {
[type(C)];
}
}
// ----
// TypeError: (47-56): Unable to deduce nameable type for array elements. Try adding explicit type conversion for the first element.