diff --git a/Changelog.md b/Changelog.md index b2f6a8b46..756497738 100644 --- a/Changelog.md +++ b/Changelog.md @@ -8,6 +8,7 @@ Breaking Changes: * 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. + * Type System: Disallow enums with more than 256 members. * Parser: Exponentiation is right associative. ``a**b**c`` is parsed as ``a**(b**c)``. * Code Generator: Use ``revert`` with error signature ``Panic(uint256)`` and error codes instead of invalid opcode on failing assertions. * Type System: Explicit conversions from literals to integer type is as strict as implicit conversions. diff --git a/docs/080-breaking-changes.rst b/docs/080-breaking-changes.rst index 0d981fbe5..dd453b787 100644 --- a/docs/080-breaking-changes.rst +++ b/docs/080-breaking-changes.rst @@ -54,3 +54,7 @@ New Restrictions * 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. + +* ``enum`` definitions cannot contain more than 256 members. + + This will make it safe to assume that the underlying type in the ABI is always ``uint8``. diff --git a/docs/abi-spec.rst b/docs/abi-spec.rst index f6bb208dc..5164bd694 100644 --- a/docs/abi-spec.rst +++ b/docs/abi-spec.rst @@ -109,14 +109,15 @@ them. +-------------------------------+-----------------------------------------------------------------------------+ |:ref:`contract` |``address`` | +-------------------------------+-----------------------------------------------------------------------------+ -|:ref:`enum` |smallest ``uint`` type that is large enough to hold all values | -| | | -| |For example, an ``enum`` of 256 values or less is mapped to ``uint8`` and | -| |an ``enum`` of 256 values is mapped to ``uint16``. | +|:ref:`enum` |``uint8`` | +-------------------------------+-----------------------------------------------------------------------------+ |:ref:`struct` |``tuple`` | +-------------------------------+-----------------------------------------------------------------------------+ +.. warning:: + Before version ``0.8.0`` enums could have more than 256 members and were represented by the + smallest integer type just big enough to hold the value of any member. + Design Criteria for the Encoding ================================ diff --git a/docs/types/value-types.rst b/docs/types/value-types.rst index 9d17276bb..db5c683ed 100644 --- a/docs/types/value-types.rst +++ b/docs/types/value-types.rst @@ -565,6 +565,7 @@ to and from all integer types but implicit conversion is not allowed. The expli from integer checks at runtime that the value lies inside the range of the enum and causes a :ref:`Panic error` otherwise. Enums require at least one member, and its default value when declared is the first member. +Enums cannot have more than 256 members. The data representation is the same as for enums in C: The options are represented by subsequent unsigned integer values starting from ``0``. @@ -586,9 +587,7 @@ subsequent unsigned integer values starting from ``0``. // Since enum types are not part of the ABI, the signature of "getChoice" // will automatically be changed to "getChoice() returns (uint8)" - // for all matters external to Solidity. The integer type used is just - // large enough to hold all enum values, i.e. if you have more than 256 values, - // `uint16` will be used and so on. + // for all matters external to Solidity. function getChoice() public view returns (ActionChoices) { return choice; } diff --git a/libsolidity/analysis/DeclarationTypeChecker.cpp b/libsolidity/analysis/DeclarationTypeChecker.cpp index 344610769..14ed89a41 100644 --- a/libsolidity/analysis/DeclarationTypeChecker.cpp +++ b/libsolidity/analysis/DeclarationTypeChecker.cpp @@ -62,6 +62,18 @@ bool DeclarationTypeChecker::visit(ElementaryTypeName const& _typeName) return true; } +bool DeclarationTypeChecker::visit(EnumDefinition const& _enum) +{ + if (_enum.members().size() > 256) + m_errorReporter.declarationError( + 1611_error, + _enum.location(), + "Enum with more than 256 members is not allowed." + ); + + return false; +} + bool DeclarationTypeChecker::visit(StructDefinition const& _struct) { if (_struct.annotation().recursive.has_value()) diff --git a/libsolidity/analysis/DeclarationTypeChecker.h b/libsolidity/analysis/DeclarationTypeChecker.h index 42ea149e9..c0437a643 100644 --- a/libsolidity/analysis/DeclarationTypeChecker.h +++ b/libsolidity/analysis/DeclarationTypeChecker.h @@ -59,6 +59,7 @@ private: void endVisit(Mapping const& _mapping) override; void endVisit(ArrayTypeName const& _typeName) override; void endVisit(VariableDeclaration const& _variable) override; + bool visit(EnumDefinition const& _enum) override; bool visit(StructDefinition const& _struct) override; bool visit(UsingForDirective const& _usingForDirective) override; bool visit(InheritanceSpecifier const& _inheritanceSpecifier) override; diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index 79eeb015a..70275cda7 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -672,7 +672,7 @@ ASTPointer Parser::parseEnumDefinition() fatalParserError(1612_error, "Expected identifier after ','"); } if (members.empty()) - parserError(3147_error, "enum with no members is not allowed."); + parserError(3147_error, "Enum with no members is not allowed."); nodeFactory.markEndPosition(); expectToken(Token::RBrace); diff --git a/test/libsolidity/semanticTests/enums/enum_with_256_members.sol b/test/libsolidity/semanticTests/enums/enum_with_256_members.sol new file mode 100644 index 000000000..dbb21c47f --- /dev/null +++ b/test/libsolidity/semanticTests/enums/enum_with_256_members.sol @@ -0,0 +1,61 @@ +pragma experimental ABIEncoderV2; + +enum E { + E000, E001, E002, E003, E004, E005, E006, E007, E008, E009, + E010, E011, E012, E013, E014, E015, E016, E017, E018, E019, + E020, E021, E022, E023, E024, E025, E026, E027, E028, E029, + E030, E031, E032, E033, E034, E035, E036, E037, E038, E039, + E040, E041, E042, E043, E044, E045, E046, E047, E048, E049, + E050, E051, E052, E053, E054, E055, E056, E057, E058, E059, + E060, E061, E062, E063, E064, E065, E066, E067, E068, E069, + E070, E071, E072, E073, E074, E075, E076, E077, E078, E079, + E080, E081, E082, E083, E084, E085, E086, E087, E088, E089, + E090, E091, E092, E093, E094, E095, E096, E097, E098, E099, + E100, E101, E102, E103, E104, E105, E106, E107, E108, E109, + E110, E111, E112, E113, E114, E115, E116, E117, E118, E119, + E120, E121, E122, E123, E124, E125, E126, E127, E128, E129, + E130, E131, E132, E133, E134, E135, E136, E137, E138, E139, + E140, E141, E142, E143, E144, E145, E146, E147, E148, E149, + E150, E151, E152, E153, E154, E155, E156, E157, E158, E159, + E160, E161, E162, E163, E164, E165, E166, E167, E168, E169, + E170, E171, E172, E173, E174, E175, E176, E177, E178, E179, + E180, E181, E182, E183, E184, E185, E186, E187, E188, E189, + E190, E191, E192, E193, E194, E195, E196, E197, E198, E199, + E200, E201, E202, E203, E204, E205, E206, E207, E208, E209, + E210, E211, E212, E213, E214, E215, E216, E217, E218, E219, + E220, E221, E222, E223, E224, E225, E226, E227, E228, E229, + E230, E231, E232, E233, E234, E235, E236, E237, E238, E239, + E240, E241, E242, E243, E244, E245, E246, E247, E248, E249, + E250, E251, E252, E253, E254, E255 +} + +contract C { + function getMinMax() public returns (E, E) { + return (E.E000, E.E255); + } + + function intToEnum(uint8 _i) public returns (E) { + return E(_i); + } + + function enumToInt(E _e) public returns (uint8) { + return uint8(_e); + } + + function decodeEnum(bytes memory data) public returns (E) { + (E e) = abi.decode(data, (E)); + return e; + } +} +// ==== +// compileViaYul: also +// ---- +// getMinMax() -> 0, 255 +// intToEnum(uint8): 0 -> 0 +// intToEnum(uint8): 255 -> 255 +// enumToInt(uint8): 0 -> 0 +// enumToInt(uint8): 255 -> 255 +// enumToInt(uint8): 256 -> FAILURE +// decodeEnum(bytes): 0x20, 32, 0 -> 0 +// decodeEnum(bytes): 0x20, 32, 255 -> 255 +// decodeEnum(bytes): 0x20, 32, 256 -> FAILURE diff --git a/test/libsolidity/syntaxTests/enums/enum_with_too_many_members.sol b/test/libsolidity/syntaxTests/enums/enum_with_too_many_members.sol new file mode 100644 index 000000000..c4eced557 --- /dev/null +++ b/test/libsolidity/syntaxTests/enums/enum_with_too_many_members.sol @@ -0,0 +1,30 @@ +enum E { + E000, E001, E002, E003, E004, E005, E006, E007, E008, E009, + E010, E011, E012, E013, E014, E015, E016, E017, E018, E019, + E020, E021, E022, E023, E024, E025, E026, E027, E028, E029, + E030, E031, E032, E033, E034, E035, E036, E037, E038, E039, + E040, E041, E042, E043, E044, E045, E046, E047, E048, E049, + E050, E051, E052, E053, E054, E055, E056, E057, E058, E059, + E060, E061, E062, E063, E064, E065, E066, E067, E068, E069, + E070, E071, E072, E073, E074, E075, E076, E077, E078, E079, + E080, E081, E082, E083, E084, E085, E086, E087, E088, E089, + E090, E091, E092, E093, E094, E095, E096, E097, E098, E099, + E100, E101, E102, E103, E104, E105, E106, E107, E108, E109, + E110, E111, E112, E113, E114, E115, E116, E117, E118, E119, + E120, E121, E122, E123, E124, E125, E126, E127, E128, E129, + E130, E131, E132, E133, E134, E135, E136, E137, E138, E139, + E140, E141, E142, E143, E144, E145, E146, E147, E148, E149, + E150, E151, E152, E153, E154, E155, E156, E157, E158, E159, + E160, E161, E162, E163, E164, E165, E166, E167, E168, E169, + E170, E171, E172, E173, E174, E175, E176, E177, E178, E179, + E180, E181, E182, E183, E184, E185, E186, E187, E188, E189, + E190, E191, E192, E193, E194, E195, E196, E197, E198, E199, + E200, E201, E202, E203, E204, E205, E206, E207, E208, E209, + E210, E211, E212, E213, E214, E215, E216, E217, E218, E219, + E220, E221, E222, E223, E224, E225, E226, E227, E228, E229, + E230, E231, E232, E233, E234, E235, E236, E237, E238, E239, + E240, E241, E242, E243, E244, E245, E246, E247, E248, E249, + E250, E251, E252, E253, E254, E255, E256 +} +// ---- +// DeclarationError 1611: (0-1655): Enum with more than 256 members is not allowed. diff --git a/test/libsolidity/syntaxTests/parsing/empty_enum.sol b/test/libsolidity/syntaxTests/parsing/empty_enum.sol index 36c05fd4b..1dc04d914 100644 --- a/test/libsolidity/syntaxTests/parsing/empty_enum.sol +++ b/test/libsolidity/syntaxTests/parsing/empty_enum.sol @@ -2,4 +2,4 @@ contract c { enum foo { } } // ---- -// ParserError 3147: (25-26): enum with no members is not allowed. +// ParserError 3147: (25-26): Enum with no members is not allowed.