From e4b31e723003a2d98554c2d17b5f72885c8b96a5 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 26 May 2020 15:08:57 +0200 Subject: [PATCH 1/3] Introduce named concept for types. --- libsolidity/ast/Types.cpp | 11 +++++++++++ libsolidity/ast/Types.h | 15 +++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index d2f6c3898..fbb119e42 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -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> FunctionType::makeStackItems() const { vector> slots; diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 4c6885b82..609f2e9ed 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -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; } From d0b6de580fb1c84d7dde616e71addf99ac07ec3d Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 26 May 2020 15:20:54 +0200 Subject: [PATCH 2/3] Disallow non-namable types for inline arrays. --- Changelog.md | 1 + libsolidity/analysis/TypeChecker.cpp | 6 ++++++ .../inline_arrays/unnamed_types_in_inline_array_1.sol | 7 +++++++ .../inline_arrays/unnamed_types_in_inline_array_2.sol | 7 +++++++ 4 files changed, 21 insertions(+) create mode 100644 test/libsolidity/syntaxTests/inline_arrays/unnamed_types_in_inline_array_1.sol create mode 100644 test/libsolidity/syntaxTests/inline_arrays/unnamed_types_in_inline_array_2.sol diff --git a/Changelog.md b/Changelog.md index 381d9eaae..ad568e6ae 100644 --- a/Changelog.md +++ b/Changelog.md @@ -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. diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 86961bfda..47178fb46 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -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."); diff --git a/test/libsolidity/syntaxTests/inline_arrays/unnamed_types_in_inline_array_1.sol b/test/libsolidity/syntaxTests/inline_arrays/unnamed_types_in_inline_array_1.sol new file mode 100644 index 000000000..a62803445 --- /dev/null +++ b/test/libsolidity/syntaxTests/inline_arrays/unnamed_types_in_inline_array_1.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/inline_arrays/unnamed_types_in_inline_array_2.sol b/test/libsolidity/syntaxTests/inline_arrays/unnamed_types_in_inline_array_2.sol new file mode 100644 index 000000000..a93e09242 --- /dev/null +++ b/test/libsolidity/syntaxTests/inline_arrays/unnamed_types_in_inline_array_2.sol @@ -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. From 309f0fbc8a6c2e13d5e67e8c4d72404a4e8ca1e3 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 26 May 2020 15:35:29 +0200 Subject: [PATCH 3/3] Unimplemented assert for conversion from calldata slices to memory. --- libsolidity/codegen/CompilerUtils.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index 225a9fe8e..2735c2fce 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -1022,6 +1022,10 @@ void CompilerUtils::convertType( case Type::Category::ArraySlice: { auto& typeOnStack = dynamic_cast(_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 &&