diff --git a/Changelog.md b/Changelog.md index b295b7bf445c..c21d61f537ec 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,7 @@ Language Features: * General: Add a builtin that computes the base slot of a storage namespace using the `erc7201` formula from ERC-7201. +* General: Allow ``constant`` keyword for composite types (structs, arrays, function pointers) and as a data location for internal function parameters. Compiler Features: * Commandline Interface: Disallow selecting the deprecated assembly input mode that was only accessible via `--assemble` instead of treating it as equivalent to `--strict-assembly`. diff --git a/docs/contracts/constant-state-variables.rst b/docs/contracts/constant-state-variables.rst index 4e9698735473..b923f5140167 100644 --- a/docs/contracts/constant-state-variables.rst +++ b/docs/contracts/constant-state-variables.rst @@ -28,6 +28,14 @@ can sometimes be cheaper than immutable values. Not all types for constants and immutables are implemented at this time. The only supported types are :ref:`strings ` (only for constants) and :ref:`value types `. +When using the IR pipeline (``--via-ir``), ``constant`` also supports composite types: +structs, fixed-size arrays (including nested), arrays of strings, structs with string fields, +enum arrays, and arrays of internal function pointers. +Dynamic arrays (``uint256[] constant``) are supported with slicing (``arr[s:e]``). + +Additionally, ``constant`` can be used as a data location specifier for parameters of +``internal`` and ``private`` functions, enabling zero-copy passing of constant references. + .. code-block:: solidity // SPDX-License-Identifier: GPL-3.0 diff --git a/docs/grammar/SolidityParser.g4 b/docs/grammar/SolidityParser.g4 index 5ad422913e98..e2fe94381445 100644 --- a/docs/grammar/SolidityParser.g4 +++ b/docs/grammar/SolidityParser.g4 @@ -371,7 +371,7 @@ locals [boolean visibilitySet = false, boolean mutabilitySet = false] * The declaration of a single variable. */ variableDeclaration: type=typeName location=dataLocation? name=identifier; -dataLocation: Memory | Storage | Calldata; +dataLocation: Memory | Storage | Calldata | Constant; /** * Complex expression. diff --git a/libsolidity/analysis/DeclarationTypeChecker.cpp b/libsolidity/analysis/DeclarationTypeChecker.cpp index e2f0cf6e8b00..cc8f29bfb112 100644 --- a/libsolidity/analysis/DeclarationTypeChecker.cpp +++ b/libsolidity/analysis/DeclarationTypeChecker.cpp @@ -418,6 +418,7 @@ void DeclarationTypeChecker::endVisit(VariableDeclaration const& _variable) case Location::Storage: return "\"storage\""; case Location::Transient: return "\"transient\""; case Location::CallData: return "\"calldata\""; + case Location::Constant: return "\"constant\""; case Location::Unspecified: return "none"; } return {}; @@ -514,6 +515,9 @@ void DeclarationTypeChecker::endVisit(VariableDeclaration const& _variable) case Location::Transient: solUnimplemented("Transient data location cannot be used in this kind of variable or parameter declaration."); break; + case Location::Constant: + typeLoc = DataLocation::Constant; + break; case Location::Unspecified: solAssert(!_variable.hasReferenceOrMappingType(), "Data location not properly set."); } @@ -528,10 +532,35 @@ void DeclarationTypeChecker::endVisit(VariableDeclaration const& _variable) if (_variable.isConstant() && !type->isValueType()) { bool allowed = false; + bool isByteArrayOrString = false; if (auto arrayType = dynamic_cast(type)) - allowed = arrayType->isByteArrayOrString(); + { + isByteArrayOrString = arrayType->isByteArrayOrString(); + if (isByteArrayOrString) + allowed = true; + else + allowed = !arrayType->containsNestedMapping(); + } + else if (auto structType = dynamic_cast(type)) + { + bool membersResolved = true; + for (auto const& member: structType->structDefinition().members()) + if (!member->annotation().type) + { + membersResolved = false; + break; + } + allowed = !membersResolved || !structType->containsNestedMapping(); + } + else if (dynamic_cast(type)) + allowed = false; if (!allowed) - m_errorReporter.fatalTypeError(9259_error, _variable.location(), "Only constants of value type and byte array type are implemented."); + m_errorReporter.fatalTypeError(9259_error, _variable.location(), "Constants of this type are not supported. Only value types, arrays, structs, and byte/string types without mappings are allowed."); + if (!isByteArrayOrString) + { + if (auto ref = dynamic_cast(type)) + type = TypeProvider::withLocation(ref, DataLocation::Constant, false); + } } if (!type->isValueType()) diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index c613dd796d98..74e0f824fc71 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -472,6 +472,30 @@ bool TypeChecker::visit(FunctionDefinition const& _function) return false; } +namespace +{ +bool isCompileTimeConstantExpression(Expression const& _expr) +{ + if (*_expr.annotation().isPure) + return true; + if (auto const* ident = dynamic_cast(&_expr)) + { + if (dynamic_cast(ident->annotation().referencedDeclaration)) + if (auto const* fType = dynamic_cast(ident->annotation().type)) + if (fType->kind() == FunctionType::Kind::Internal) + return true; + } + if (auto const* tuple = dynamic_cast(&_expr)) + { + for (auto const& comp: tuple->components()) + if (comp && !isCompileTimeConstantExpression(*comp)) + return false; + return true; + } + return false; +} +} + bool TypeChecker::visit(VariableDeclaration const& _variable) { _variable.typeName().accept(*this); @@ -499,7 +523,7 @@ bool TypeChecker::visit(VariableDeclaration const& _variable) { if (!_variable.value()) m_errorReporter.typeError(4266_error, _variable.location(), "Uninitialized \"constant\" variable."); - else if (!*_variable.value()->annotation().isPure) + else if (!*_variable.value()->annotation().isPure && !isCompileTimeConstantExpression(*_variable.value())) m_errorReporter.typeError( 8349_error, _variable.value()->location(), @@ -3458,8 +3482,8 @@ bool TypeChecker::visit(IndexAccess const& _access) case Type::Category::ArraySlice: { auto const& arrayType = dynamic_cast(*baseType).arrayType(); - if (arrayType.location() != DataLocation::CallData || !arrayType.isDynamicallySized()) - m_errorReporter.typeError(4802_error, _access.location(), "Index access is only implemented for slices of dynamic calldata arrays."); + if ((arrayType.location() != DataLocation::CallData && arrayType.location() != DataLocation::Constant) || !arrayType.isDynamicallySized()) + m_errorReporter.typeError(4802_error, _access.location(), "Index access is only implemented for slices of dynamic calldata or constant arrays."); baseType = &arrayType; [[fallthrough]]; } @@ -3599,8 +3623,11 @@ bool TypeChecker::visit(IndexRangeAccess const& _access) else if (!(arrayType = dynamic_cast(exprType))) m_errorReporter.fatalTypeError(4781_error, _access.location(), "Index range access is only possible for arrays and array slices."); - if (arrayType->location() != DataLocation::CallData || !arrayType->isDynamicallySized()) - m_errorReporter.typeError(1227_error, _access.location(), "Index range access is only supported for dynamic calldata arrays."); + if ( + (arrayType->location() != DataLocation::CallData && arrayType->location() != DataLocation::Constant) || + !arrayType->isDynamicallySized() + ) + m_errorReporter.typeError(1227_error, _access.location(), "Index range access is only supported for dynamic calldata or constant arrays."); else if (arrayType->baseType()->isDynamicallyEncoded()) m_errorReporter.typeError(2148_error, _access.location(), "Index range access is not supported for arrays with dynamically encoded base types."); _access.annotation().type = TypeProvider::arraySlice(*arrayType); diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index b59273b18d5d..f155528b1ca4 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -852,6 +852,8 @@ std::set VariableDeclaration::allowedDataLocation locations.insert(Location::Storage); if (!isTryCatchParameter() && !isConstructorParameter()) locations.insert(Location::CallData); + if (!isConstructorParameter() && isInternalCallableParameter()) + locations.insert(Location::Constant); return locations; } diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index a4e19582b250..6eae2e5e8b54 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -1091,7 +1091,7 @@ class FunctionDefinition: public CallableDeclaration, public StructurallyDocumen class VariableDeclaration: public Declaration, public StructurallyDocumented { public: - enum Location { Unspecified, Storage, Transient, Memory, CallData }; + enum Location { Unspecified, Storage, Transient, Memory, CallData, Constant }; enum class Mutability { Mutable, Immutable, Constant }; static std::string mutabilityToString(Mutability _mutability) { diff --git a/libsolidity/ast/ASTJsonExporter.cpp b/libsolidity/ast/ASTJsonExporter.cpp index 4eaa558713a7..24a7cac3cefc 100644 --- a/libsolidity/ast/ASTJsonExporter.cpp +++ b/libsolidity/ast/ASTJsonExporter.cpp @@ -1086,6 +1086,8 @@ std::string ASTJsonExporter::location(VariableDeclaration::Location _location) return "calldata"; case VariableDeclaration::Location::Transient: return "transient"; + case VariableDeclaration::Location::Constant: + return "constant"; } // To make the compiler happy return {}; diff --git a/libsolidity/ast/ASTJsonImporter.cpp b/libsolidity/ast/ASTJsonImporter.cpp index 2d2b66fd8d08..90207567a750 100644 --- a/libsolidity/ast/ASTJsonImporter.cpp +++ b/libsolidity/ast/ASTJsonImporter.cpp @@ -1218,6 +1218,8 @@ VariableDeclaration::Location ASTJsonImporter::location(Json const& _node) return VariableDeclaration::Location::CallData; else if (storageLocStr == "transient") return VariableDeclaration::Location::Transient; + else if (storageLocStr == "constant") + return VariableDeclaration::Location::Constant; else astAssert(false, "Unknown location declaration"); diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 601788eaf6c9..5c10880726cf 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -1552,6 +1552,8 @@ TypeResult ReferenceType::unaryOperatorResult(Token _operator) const return isPointer() ? nullptr : TypeProvider::emptyTuple(); case DataLocation::Transient: solUnimplemented("Transient data location is only supported for value types."); + case DataLocation::Constant: + return nullptr; } return nullptr; } @@ -1582,6 +1584,8 @@ std::string ReferenceType::stringForReferencePart() const case DataLocation::Transient: solUnimplemented("Transient data location is only supported for value types."); break; + case DataLocation::Constant: + return "constant"; } solAssert(false, ""); return ""; @@ -1604,6 +1608,9 @@ std::string ReferenceType::identifierLocationSuffix() const case DataLocation::CallData: id += "_calldata"; break; + case DataLocation::Constant: + id += "_constant"; + break; } if (isPointer()) id += "_ptr"; @@ -1646,6 +1653,14 @@ BoolResult ArrayType::isImplicitlyConvertibleTo(Type const& _convertTo) const return true; return !isDynamicallySized() && convertTo.length() >= length(); } + else if (convertTo.location() == DataLocation::Constant) + { + if (!baseType()->isImplicitlyConvertibleTo(*convertTo.baseType())) + return false; + if (convertTo.isDynamicallySized()) + return true; + return !isDynamicallySized() && convertTo.length() >= length(); + } else { // Conversion to storage pointer or to memory, we do not copy element-for-element here, so @@ -1769,6 +1784,28 @@ BoolResult ArrayType::validForLocation(DataLocation _loc) const case DataLocation::Transient: solUnimplemented("Transient data location is only supported for value types."); break; + case DataLocation::Constant: + { + bigint size = bigint(length()); + auto type = m_baseType; + while (auto arrayType = dynamic_cast(type)) + { + if (arrayType->isDynamicallySized()) + break; + else + { + size *= arrayType->length(); + type = arrayType->baseType(); + } + } + if (type->isDynamicallySized()) + size *= type->memoryHeadSize(); + else + size *= type->memoryDataSize(); + if (size >= std::numeric_limits::max()) + return BoolResult::err("Type too large for constant data."); + break; + } } return true; } @@ -1852,6 +1889,11 @@ std::vector> ArrayType::makeStackItems() co case DataLocation::Transient: solUnimplemented("Transient data location is only supported for value types."); break; + case DataLocation::Constant: + if (isDynamicallySized() && !isByteArrayOrString()) + return {std::make_tuple("codeOffset", TypeProvider::uint256()), std::make_tuple("length", TypeProvider::uint256())}; + else + return {std::make_tuple("codeOffset", TypeProvider::uint256())}; } solAssert(false, ""); } @@ -2050,7 +2092,7 @@ BoolResult ArraySliceType::isImplicitlyConvertibleTo(Type const& _other) const return (*this) == _other || ( - m_arrayType.dataStoredIn(DataLocation::CallData) && + (m_arrayType.dataStoredIn(DataLocation::CallData) || m_arrayType.dataStoredIn(DataLocation::Constant)) && m_arrayType.isDynamicallySized() && m_arrayType.isImplicitlyConvertibleTo(_other) ); @@ -2609,6 +2651,8 @@ std::vector> StructType::makeStackItems() c case DataLocation::Transient: solUnimplemented("Transient data location is only supported for value types."); break; + case DataLocation::Constant: + return {std::make_tuple("codeOffset", TypeProvider::uint256())}; } solAssert(false, ""); } diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index cddedc0f8c8f..cf558cbbaa7d 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -70,7 +70,7 @@ inline rational makeRational(bigint const& _numerator, bigint const& _denominato return rational(_numerator, _denominator); } -enum class DataLocation { Storage, Transient, CallData, Memory }; +enum class DataLocation { Storage, Transient, CallData, Memory, Constant }; /** diff --git a/libsolidity/codegen/ABIFunctions.cpp b/libsolidity/codegen/ABIFunctions.cpp index 474848760cef..af7881f63f3c 100644 --- a/libsolidity/codegen/ABIFunctions.cpp +++ b/libsolidity/codegen/ABIFunctions.cpp @@ -318,12 +318,13 @@ std::string ABIFunctions::abiEncodingFunction( return abiEncodingFunctionCalldataArrayWithoutCleanup(*fromArray, *toArray, _options); else return abiEncodingFunctionSimpleArray(*fromArray, *toArray, _options); - case DataLocation::Memory: - if (fromArray->isByteArrayOrString()) - return abiEncodingFunctionMemoryByteArray(*fromArray, *toArray, _options); - else - return abiEncodingFunctionSimpleArray(*fromArray, *toArray, _options); - case DataLocation::Storage: + case DataLocation::Constant: + case DataLocation::Memory: + if (fromArray->isByteArrayOrString()) + return abiEncodingFunctionMemoryByteArray(*fromArray, *toArray, _options); + else + return abiEncodingFunctionSimpleArray(*fromArray, *toArray, _options); + case DataLocation::Storage: if (fromArray->baseType()->storageBytes() <= 16) return abiEncodingFunctionCompactStorageArray(*fromArray, *toArray, _options); else @@ -611,6 +612,7 @@ std::string ABIFunctions::abiEncodingFunctionSimpleArray( templ("encodeToMemoryFun", abiEncodeAndReturnUpdatedPosFunction(*_from.baseType(), *_to.baseType(), subOptions)); switch (_from.location()) { + case DataLocation::Constant: case DataLocation::Memory: templ("arrayElementAccess", "mload(srcPtr)"); break; @@ -907,6 +909,7 @@ std::string ABIFunctions::abiEncodingFunctionStruct( } break; } + case DataLocation::Constant: case DataLocation::Memory: { std::string sourceOffset = toCompactHexWithPrefix(_from.memoryOffsetOfMember(member.name)); diff --git a/libsolidity/codegen/ArrayUtils.cpp b/libsolidity/codegen/ArrayUtils.cpp index 80ee9553c0ae..5db1d14b2269 100644 --- a/libsolidity/codegen/ArrayUtils.cpp +++ b/libsolidity/codegen/ArrayUtils.cpp @@ -683,6 +683,9 @@ void ArrayUtils::retrieveLength(ArrayType const& _arrayType, unsigned _stackDept case DataLocation::Transient: solUnimplemented("Transient data location is only supported for value types."); break; + case DataLocation::Constant: + solUnimplemented("Constant composite types require compilation via the IR pipeline (use --via-ir)."); + break; } } } @@ -783,6 +786,9 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType, bool _doBoundsCheck, b case DataLocation::Transient: solUnimplemented("Transient data location is only supported for value types."); break; + case DataLocation::Constant: + solUnimplemented("Constant composite types require compilation via the IR pipeline (use --via-ir)."); + break; } } diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index c7c219cb238e..e52c953f4ffb 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -1027,6 +1027,9 @@ void CompilerUtils::convertType( case DataLocation::Transient: solUnimplemented("Transient data location is only supported for value types."); break; + case DataLocation::Constant: + solUnimplemented("Constant composite types require compilation via the IR pipeline (use --via-ir)."); + break; case DataLocation::Memory: { // Copy the array to a free position in memory, unless it is already in memory. @@ -1174,6 +1177,9 @@ void CompilerUtils::convertType( case DataLocation::Transient: solUnimplemented("Transient data location is only supported for value types."); break; + case DataLocation::Constant: + solUnimplemented("Constant composite types require compilation via the IR pipeline (use --via-ir)."); + break; case DataLocation::Memory: // Copy the array to a free position in memory, unless it is already in memory. switch (typeOnStack.location()) @@ -1216,6 +1222,9 @@ void CompilerUtils::convertType( case DataLocation::Transient: solUnimplemented("Transient data location is only supported for value types."); break; + case DataLocation::Constant: + solUnimplemented("Constant composite types require compilation via the IR pipeline (use --via-ir)."); + break; case DataLocation::CallData: { if (typeOnStack.isDynamicallyEncoded()) diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index dc46fa2794e7..a4bb920e474f 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -2143,6 +2143,9 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) case DataLocation::Transient: solUnimplemented("Transient data location is only supported for value types."); break; + case DataLocation::Constant: + solUnimplemented("Constant composite types require compilation via the IR pipeline (use --via-ir)."); + break; case DataLocation::Memory: m_context << Instruction::MLOAD; break; @@ -2293,6 +2296,9 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess) case DataLocation::Transient: solUnimplemented("Transient data location is only supported for value types."); break; + case DataLocation::Constant: + solUnimplemented("Constant composite types require compilation via the IR pipeline (use --via-ir)."); + break; case DataLocation::Memory: ArrayUtils(m_context).accessIndex(arrayType); setLValue(_indexAccess, *_indexAccess.annotation().type, !arrayType.isByteArrayOrString()); diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index f014207951ce..81cb23b94051 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -1318,8 +1318,10 @@ std::string YulUtilFunctions::arrayLengthFunction(ArrayType const& _type) { std::string functionName = "array_length_" + _type.identifier(); return m_functionCollector.createFunction(functionName, [&]() { + bool dynOnStack = (_type.location() == DataLocation::CallData || + (_type.location() == DataLocation::Constant && !_type.isByteArrayOrString())) && _type.isDynamicallySized(); Whiskers w(R"( - function (value, len) -> length { + function (value, len) -> length { length := mload(value) @@ -1330,9 +1332,9 @@ std::string YulUtilFunctions::arrayLengthFunction(ArrayType const& _type) length := (length) - + length := len - + length := @@ -1342,9 +1344,10 @@ std::string YulUtilFunctions::arrayLengthFunction(ArrayType const& _type) w("dynamic", _type.isDynamicallySized()); if (!_type.isDynamicallySized()) w("length", toCompactHexWithPrefix(_type.length())); - w("memory", _type.location() == DataLocation::Memory); + w("memory", _type.location() == DataLocation::Memory || + (_type.location() == DataLocation::Constant && _type.isByteArrayOrString())); w("storage", _type.location() == DataLocation::Storage); - w("calldata", _type.location() == DataLocation::CallData); + w("dynOnStack", dynOnStack); if (_type.location() == DataLocation::Storage) { w("byteArray", _type.isByteArrayOrString()); @@ -2025,7 +2028,7 @@ std::string YulUtilFunctions::copyArrayToStorageFunction(ArrayType const& _fromT bool fromCalldata = _fromType.dataStoredIn(DataLocation::CallData); templ("isFromDynamicCalldata", _fromType.isDynamicallySized() && fromCalldata); templ("fromStorage", _fromType.dataStoredIn(DataLocation::Storage)); - bool fromMemory = _fromType.dataStoredIn(DataLocation::Memory); + bool fromMemory = _fromType.dataStoredIn(DataLocation::Memory) || _fromType.dataStoredIn(DataLocation::Constant); templ("fromMemory", fromMemory); templ("fromCalldata", fromCalldata); templ("srcDataLocation", arrayDataAreaFunction(_fromType)); @@ -2119,7 +2122,7 @@ std::string YulUtilFunctions::copyByteArrayToStorageFunction(ArrayType const& _f bool fromStorage = _fromType.dataStoredIn(DataLocation::Storage); templ("fromStorage", fromStorage); bool fromCalldata = _fromType.dataStoredIn(DataLocation::CallData); - templ("fromMemory", _fromType.dataStoredIn(DataLocation::Memory)); + templ("fromMemory", _fromType.dataStoredIn(DataLocation::Memory) || _fromType.dataStoredIn(DataLocation::Constant)); templ("fromCalldata", fromCalldata); templ("arrayLength", arrayLengthFunction(_fromType)); templ("panic", panicFunction(PanicCode::ResourceError)); @@ -2413,7 +2416,7 @@ std::string YulUtilFunctions::arrayDataAreaFunction(ArrayType const& _type) )") ("functionName", functionName) ("dynamic", _type.isDynamicallySized()) - ("memory", _type.location() == DataLocation::Memory) + ("memory", _type.location() == DataLocation::Memory || _type.location() == DataLocation::Constant) ("storage", _type.location() == DataLocation::Storage) .render(); }); @@ -2583,6 +2586,7 @@ std::string YulUtilFunctions::nextArrayElementFunction(ArrayType const& _type) templ("functionName", functionName); switch (_type.location()) { + case DataLocation::Constant: case DataLocation::Memory: templ("advance", "0x20"); break; @@ -3470,12 +3474,12 @@ std::string YulUtilFunctions::conversionFunction(Type const& _from, Type const& (fromType.arrayType().isByteArrayOrString() && targetType.isByteArrayOrString()) ); solAssert( - fromType.arrayType().dataStoredIn(DataLocation::CallData) && + (fromType.arrayType().dataStoredIn(DataLocation::CallData) || fromType.arrayType().dataStoredIn(DataLocation::Constant)) && fromType.arrayType().isDynamicallySized() && !fromType.arrayType().baseType()->isDynamicallyEncoded() ); - if (!targetType.dataStoredIn(DataLocation::CallData)) + if (!targetType.dataStoredIn(DataLocation::CallData) && !targetType.dataStoredIn(DataLocation::Constant)) return arrayConversionFunction(fromType.arrayType(), targetType); std::string const functionName = @@ -3597,6 +3601,12 @@ std::string YulUtilFunctions::conversionFunction(Type const& _from, Type const& if (fromStructType.location() == toStructType.location() && toStructType.isPointer()) body = "converted := value"; + else if ( + (fromStructType.location() == DataLocation::Constant && toStructType.location() == DataLocation::Memory) || + (fromStructType.location() == DataLocation::Memory && toStructType.location() == DataLocation::Constant) || + (fromStructType.location() == DataLocation::Constant && toStructType.location() == DataLocation::Constant) + ) + body = "converted := value"; else { solUnimplementedAssert(toStructType.location() == DataLocation::Memory); @@ -3741,7 +3751,7 @@ std::string YulUtilFunctions::bytesToFixedBytesConversionFunction(ArrayType cons templ("fromCalldata", fromCalldata); templ("arrayLen", arrayLengthFunction(_from)); templ("fixedBytesLen", std::to_string(_to.numBytes())); - templ("fromMemory", _from.dataStoredIn(DataLocation::Memory)); + templ("fromMemory", _from.dataStoredIn(DataLocation::Memory) || _from.dataStoredIn(DataLocation::Constant)); templ("fromStorage", _from.dataStoredIn(DataLocation::Storage)); templ("dataArea", arrayDataAreaFunction(_from)); if (fromCalldata) @@ -3827,7 +3837,7 @@ std::string YulUtilFunctions::copyStructToStorageFunction(StructType const& _fro )"); bool fromCalldata = _from.location() == DataLocation::CallData; t("fromCalldata", fromCalldata); - bool fromMemory = _from.location() == DataLocation::Memory; + bool fromMemory = _from.location() == DataLocation::Memory || _from.location() == DataLocation::Constant; t("fromMemory", fromMemory); bool fromStorage = _from.location() == DataLocation::Storage; t("fromStorage", fromStorage); @@ -3896,27 +3906,35 @@ std::string YulUtilFunctions::arrayConversionFunction(ArrayType const& _from, Ar _to.identifier(); return m_functionCollector.createFunction(functionName, [&]() { + auto isDynOnStack = [](ArrayType const& t) { + return t.isDynamicallySized() && + (t.dataStoredIn(DataLocation::CallData) || + (t.dataStoredIn(DataLocation::Constant) && !t.isByteArrayOrString())); + }; Whiskers templ(R"( - function (value, length) -> converted , outLength { + function (value, length) -> converted, outLength { - + outLength := - + } )"); templ("functionName", functionName); - templ("fromCalldataDynamic", _from.dataStoredIn(DataLocation::CallData) && _from.isDynamicallySized()); - templ("toCalldataDynamic", _to.dataStoredIn(DataLocation::CallData) && _to.isDynamicallySized()); + templ("fromDynOnStack", isDynOnStack(_from)); + templ("toDynOnStack", isDynOnStack(_to)); templ("length", _from.isDynamicallySized() ? "length" : _from.length().str()); if ( _from == _to || (_from.dataStoredIn(DataLocation::Memory) && _to.dataStoredIn(DataLocation::Memory)) || (_from.dataStoredIn(DataLocation::CallData) && _to.dataStoredIn(DataLocation::CallData)) || + (_from.dataStoredIn(DataLocation::Constant) && _to.dataStoredIn(DataLocation::Constant)) || + (_from.dataStoredIn(DataLocation::Constant) && _to.dataStoredIn(DataLocation::Memory)) || + (_from.dataStoredIn(DataLocation::Memory) && _to.dataStoredIn(DataLocation::Constant)) || _to.dataStoredIn(DataLocation::Storage) ) templ("body", "converted := value"); - else if (_to.dataStoredIn(DataLocation::Memory)) + else if (_to.dataStoredIn(DataLocation::Memory) || _to.dataStoredIn(DataLocation::Constant)) templ( "body", Whiskers(R"( diff --git a/libsolidity/codegen/YulUtilFunctions.h b/libsolidity/codegen/YulUtilFunctions.h index a5e547935523..fc64c3ca8bbd 100644 --- a/libsolidity/codegen/YulUtilFunctions.h +++ b/libsolidity/codegen/YulUtilFunctions.h @@ -326,6 +326,10 @@ class YulUtilFunctions /// signature: (arrayOffset, arrayLength, sliceStart, sliceEnd) -> offset, length std::string calldataArrayIndexRangeAccess(ArrayType const& _type); + /// @returns the name of a function that performs index range access on a memory/constant array + /// signature: (memPtr, sliceStart, sliceEnd) -> offset, length + std::string memoryArrayIndexRangeAccess(ArrayType const& _type); + /// @returns the name of a function that follows a calldata tail while performing /// bounds checks. /// signature: (baseRef, tailPointer) -> offset[, length] diff --git a/libsolidity/codegen/ir/Common.cpp b/libsolidity/codegen/ir/Common.cpp index 9300c7848570..3348f165bd17 100644 --- a/libsolidity/codegen/ir/Common.cpp +++ b/libsolidity/codegen/ir/Common.cpp @@ -109,6 +109,12 @@ std::string IRNames::constantValueFunction(VariableDeclaration const& _constant) return "constant_" + _constant.name() + "_" + std::to_string(_constant.id()); } +std::string IRNames::constantDataObjectName(VariableDeclaration const& _constant) +{ + solAssert(_constant.isConstant(), ""); + return "cdo_" + _constant.name() + "_" + std::to_string(_constant.id()); +} + std::string IRNames::localVariable(VariableDeclaration const& _declaration) { return "var_" + _declaration.name() + '_' + std::to_string(_declaration.id()); diff --git a/libsolidity/codegen/ir/Common.h b/libsolidity/codegen/ir/Common.h index cf5bc69c7bea..843ddcc358a4 100644 --- a/libsolidity/codegen/ir/Common.h +++ b/libsolidity/codegen/ir/Common.h @@ -60,6 +60,7 @@ struct IRNames static std::string constructor(ContractDefinition const& _contract); static std::string libraryAddressImmutable(); static std::string constantValueFunction(VariableDeclaration const& _constant); + static std::string constantDataObjectName(VariableDeclaration const& _constant); static std::string localVariable(VariableDeclaration const& _declaration); static std::string localVariable(Expression const& _expression); /// @returns the variable name that can be used to inspect the success or failure of an external diff --git a/libsolidity/codegen/ir/IRGenerationContext.h b/libsolidity/codegen/ir/IRGenerationContext.h index 1a995734d28d..640aa24db2bc 100644 --- a/libsolidity/codegen/ir/IRGenerationContext.h +++ b/libsolidity/codegen/ir/IRGenerationContext.h @@ -154,6 +154,9 @@ class IRGenerationContext util::UniqueVector const& subObjectsCreated() const { return m_subObjects; } void addSubObject(ContractDefinition const* _contractDefinition) { m_subObjects.pushBack(_contractDefinition); } + void registerConstantData(std::string _name, bytes _data) { m_constantDataObjects.emplace_back(std::move(_name), std::move(_data)); } + std::vector> const& constantDataObjects() const { return m_constantDataObjects; } + bool memoryUnsafeInlineAssemblySeen() const { return m_memoryUnsafeInlineAssemblySeen; } void setMemoryUnsafeInlineAssemblySeen() { m_memoryUnsafeInlineAssemblySeen = true; } @@ -221,6 +224,8 @@ class IRGenerationContext util::UniqueVector m_subObjects; + std::vector> m_constantDataObjects; + langutil::DebugInfoSelection m_debugInfoSelection = {}; langutil::CharStreamProvider const* m_soliditySourceProvider = nullptr; }; diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index 27f7bedce225..da06dd08aa74 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -151,6 +151,7 @@ std::string IRGenerator::generate( } + data "" hex"" } @@ -240,6 +241,12 @@ std::string IRGenerator::generate( t("deployedSubObjects", subObjectSources(m_context.subObjectsCreated())); t("metadataName", yul::Object::metadataName()); t("cborMetadata", util::toHex(_cborMetadata)); + { + std::string cdoBlocks; + for (auto const& [name, data]: m_context.constantDataObjects()) + cdoBlocks += "data \"" + name + "\" hex\"" + util::toHex(data) + "\"\n"; + t("constantDataBlocks", cdoBlocks); + } t("useSrcMapDeployed", formatUseSrcMap(m_context)); diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index d5cb27b6e1df..023b8923a331 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -336,27 +336,172 @@ IRVariable IRGeneratorForStatements::evaluateExpression(Expression const& _expre } } +namespace +{ +bool isTypeFlat(Type const& _type) +{ + if (_type.isValueType()) + return true; + if (auto const* arrayType = dynamic_cast(&_type)) + { + if (arrayType->isDynamicallySized() || arrayType->isByteArrayOrString()) + return false; + return arrayType->baseType()->isValueType(); + } + if (auto const* structType = dynamic_cast(&_type)) + { + for (auto const& member: structType->structDefinition().members()) + { + Type const* memberType = member->annotation().type; + if (!memberType || !memberType->isValueType()) + return false; + } + return true; + } + return false; +} + +bool serializeExpression(Expression const& _expr, Type const& _targetType, bytes& _out) +{ + if (auto const* literal = dynamic_cast(&_expr)) + { + if (literal->annotation().type->category() == Type::Category::RationalNumber) + { + auto const& rationalType = dynamic_cast(*literal->annotation().type); + u256 value = rationalType.literalValue(literal); + if (_targetType.isValueType()) + { + bytes word(32, 0); + for (int i = 31; i >= 0; --i) + { + word[static_cast(i)] = static_cast(value & 0xff); + value >>= 8; + } + _out += word; + return true; + } + } + return false; + } + if (auto const* tuple = dynamic_cast(&_expr)) + { + if (!tuple->isInlineArray()) + return false; + auto const* arrayType = dynamic_cast(&_targetType); + if (!arrayType || arrayType->isDynamicallySized()) + return false; + auto const& components = tuple->components(); + for (size_t i = 0; i < components.size(); ++i) + { + if (!components[i]) + return false; + if (!serializeExpression(*components[i], *arrayType->baseType(), _out)) + return false; + } + return true; + } + if (auto const* funcCall = dynamic_cast(&_expr)) + { + if (auto const* structType = dynamic_cast(&_targetType)) + { + auto const& members = structType->structDefinition().members(); + auto const& args = funcCall->sortedArguments(); + if (args.size() != members.size()) + return false; + for (size_t i = 0; i < args.size(); ++i) + { + Type const* memberType = members[i]->annotation().type; + if (!memberType || !serializeExpression(*args[i], *memberType, _out)) + return false; + } + return true; + } + if (funcCall->arguments().size() == 1) + return serializeExpression(*funcCall->arguments().front(), _targetType, _out); + return false; + } + if (auto const* ident = dynamic_cast(&_expr)) + { + if (auto const* varDecl = dynamic_cast(ident->annotation().referencedDeclaration)) + { + if (varDecl->isConstant() && varDecl->value()) + return serializeExpression(*varDecl->value(), _targetType, _out); + } + } + return false; +} + +std::optional serializeConstant(VariableDeclaration const& _constant) +{ + Type const* type = _constant.type(); + if (!type || !isTypeFlat(*type)) + return std::nullopt; + if (!_constant.value()) + return std::nullopt; + bytes result; + if (serializeExpression(*_constant.value(), *type, result)) + return result; + return std::nullopt; +} +} + std::string IRGeneratorForStatements::constantValueFunction(VariableDeclaration const& _constant) { try { std::string functionName = IRNames::constantValueFunction(_constant); return m_context.functionCollector().createFunction(functionName, [&] { + Type const& constantType = *_constant.type(); + + if (auto const* arrType = dynamic_cast(&constantType); !constantType.isValueType() && (!arrType || !arrType->isByteArrayOrString())) + if (auto serialized = serializeConstant(_constant)) + { + std::string dataName = IRNames::constantDataObjectName(_constant); + size_t dataSize = serialized->size(); + m_context.registerConstantData(dataName, std::move(*serialized)); + + Whiskers templ(R"( + + function () -> { + := () + datacopy(, dataoffset(""), datasize("")) + } + )"); + templ("sourceLocationComment", dispenseLocationComment(_constant, m_context)); + templ("functionName", functionName); + IRVariable retVar("ret", constantType); + templ("ret", retVar.commaSeparatedList()); + templ("retFirst", retVar.stackSlots().front()); + templ("allocationFunction", m_utils.allocationFunction()); + templ("dataSize", std::to_string(dataSize)); + templ("dataName", dataName); + return templ.render(); + } + + IRGeneratorForStatements generator(m_context, m_utils, m_optimiserSettings); + solAssert(_constant.value()); + IRVariable result = generator.evaluateExpression(*_constant.value(), constantType); + IRVariable retVar("ret", constantType); + + std::string assignments; + auto retSlots = retVar.stackSlots(); + auto valSlots = result.stackSlots(); + solAssert(retSlots.size() == valSlots.size()); + for (size_t i = 0; i < retSlots.size(); ++i) + assignments += retSlots[i] + " := " + valSlots[i] + "\n"; + Whiskers templ(R"( function () -> { - := + } )"); templ("sourceLocationComment", dispenseLocationComment(_constant, m_context)); templ("functionName", functionName); - IRGeneratorForStatements generator(m_context, m_utils, m_optimiserSettings); - solAssert(_constant.value()); - Type const& constantType = *_constant.type(); - templ("value", generator.evaluateExpression(*_constant.value(), constantType).commaSeparatedList()); templ("code", generator.code()); - templ("ret", IRVariable("ret", constantType).commaSeparatedList()); + templ("ret", retVar.commaSeparatedList()); + templ("assignments", assignments); return templ.render(); }); @@ -2130,6 +2275,17 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) ")\n"; break; } + case DataLocation::Constant: + { + std::string pos = m_context.newYulVariable(); + appendCode() << "let " << pos << " := " << + ("add(" + expression.part("codeOffset").name() + ", " + structType.memoryOffsetOfMember(member).str() + ")\n"); + setLValue(_memberAccess, IRLValue{ + type(_memberAccess), + IRLValue::Memory{pos} + }); + break; + } default: solAssert(false, "Illegal data location for struct."); } @@ -2367,7 +2523,7 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess) dynamic_cast(baseType).arrayType(); if (baseType.category() == Type::Category::ArraySlice) - solAssert(arrayType.dataStoredIn(DataLocation::CallData) && arrayType.isDynamicallySized()); + solAssert((arrayType.dataStoredIn(DataLocation::CallData) || arrayType.dataStoredIn(DataLocation::Constant)) && arrayType.isDynamicallySized()); solAssert(_indexAccess.indexExpression(), "Index expression expected."); @@ -2398,6 +2554,40 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess) case DataLocation::Transient: solUnimplemented("Transient data location is only supported for value types."); break; + case DataLocation::Constant: + { + std::string const indexExpression = expressionAsType( + *_indexAccess.indexExpression(), + *TypeProvider::uint256() + ); + + if (baseType.category() == Type::Category::ArraySlice || arrayType.isDynamicallySized()) + { + std::string const baseRef = (baseType.category() == Type::Category::ArraySlice) + ? IRVariable(_indexAccess.baseExpression()).part("offset").name() + : IRVariable(_indexAccess.baseExpression()).part("codeOffset").name(); + std::string const arrLength = IRVariable(_indexAccess.baseExpression()).part("length").name(); + appendCode() << "if iszero(lt(" << indexExpression << ", " << arrLength << ")) { " << m_utils.panicFunction(PanicCode::ArrayOutOfBounds) << "() }\n"; + std::string const memAddress = "add(" + baseRef + ", mul(" + indexExpression + ", 0x20))"; + setLValue(_indexAccess, IRLValue{ + *arrayType.baseType(), + IRLValue::Memory{memAddress, arrayType.isByteArrayOrString()} + }); + } + else + { + std::string const indexAccessFunction = m_utils.memoryArrayIndexAccessFunction( + dynamic_cast(*TypeProvider::withLocation(&arrayType, DataLocation::Memory, false)) + ); + std::string const baseRef = IRVariable(_indexAccess.baseExpression()).part("codeOffset").name(); + std::string const memAddress = indexAccessFunction + "(" + baseRef + ", " + indexExpression + ")"; + setLValue(_indexAccess, IRLValue{ + *arrayType.baseType(), + IRLValue::Memory{memAddress, arrayType.isByteArrayOrString()} + }); + } + break; + } case DataLocation::Memory: { std::string const indexAccessFunction = m_utils.memoryArrayIndexAccessFunction(arrayType); @@ -2513,8 +2703,44 @@ void IRGeneratorForStatements::endVisit(IndexRangeAccess const& _indexRangeAcces sliceEnd.name() << ")\n"; break; } + case DataLocation::Constant: + { + solAssert(baseType.isDynamicallySized()); + IRVariable sliceStart{m_context.newYulVariable(), *TypeProvider::uint256()}; + if (_indexRangeAccess.startExpression()) + define(sliceStart, IRVariable{*_indexRangeAccess.startExpression()}); + else + define(sliceStart) << u256(0) << "\n"; + + IRVariable sliceEnd{m_context.newYulVariable(), *TypeProvider::uint256()}; + if (_indexRangeAccess.endExpression()) + define(sliceEnd, IRVariable{*_indexRangeAccess.endExpression()}); + else + define(sliceEnd, IRVariable{_indexRangeAccess.baseExpression()}.part("length")); + + std::string baseOffset = (baseType.category() == Type::Category::ArraySlice) + ? IRVariable{_indexRangeAccess.baseExpression()}.part("offset").name() + : IRVariable{_indexRangeAccess.baseExpression()}.part("codeOffset").name(); + std::string baseLength = IRVariable{_indexRangeAccess.baseExpression()}.part("length").name(); + + appendCode() << Whiskers(R"( + if gt(, ) { () } + if gt(, ) { () } + )") + ("start", sliceStart.name()) + ("end", sliceEnd.name()) + ("length", baseLength) + ("revertStartAfterEnd", m_utils.revertReasonIfDebugFunction("Slice starts after end")) + ("revertGreaterThanLength", m_utils.revertReasonIfDebugFunction("Slice is greater than length")) + .render(); + + IRVariable range{_indexRangeAccess}; + define(range.part("offset")) << "add(" << baseOffset << ", mul(" << sliceStart.name() << ", 0x20))\n"; + define(range.part("length")) << "sub(" << sliceEnd.name() << ", " << sliceStart.name() << ")\n"; + break; + } default: - solUnimplemented("Index range accesses is implemented only on calldata arrays."); + solUnimplemented("Index range accesses is implemented only on calldata or constant arrays."); } } @@ -3236,6 +3462,8 @@ void IRGeneratorForStatements::writeToLValue(IRLValue const& _lvalue, IRVariable solAssert(valueReferenceType); if (valueReferenceType->dataStoredIn(DataLocation::Memory)) appendCode() << "mstore(" + _memory.address + ", " + _value.part("mpos").name() + ")\n"; + else if (valueReferenceType->dataStoredIn(DataLocation::Constant)) + appendCode() << "mstore(" + _memory.address + ", " + _value.part("codeOffset").name() + ")\n"; else appendCode() << "mstore(" + _memory.address + ", " + m_utils.conversionFunction(_value.type(), _lvalue.type) + "(" + _value.commaSeparatedList() + "))\n"; } diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index 77b70267397c..6a9c8d11fb19 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -920,7 +920,7 @@ ASTPointer Parser::parseVariableDeclaration( isIndexed = true; } - else if (token == Token::Constant || token == Token::Immutable) + else if (token == Token::Immutable || (token == Token::Constant && !_options.allowLocationSpecifier)) { if (mutability != VariableDeclaration::Mutability::Mutable) parserError( @@ -933,7 +933,7 @@ ASTPointer Parser::parseVariableDeclaration( else if (token == Token::Immutable) mutability = VariableDeclaration::Mutability::Immutable; } - else if (_options.allowLocationSpecifier && TokenTraits::isLocationSpecifier(token)) + else if (_options.allowLocationSpecifier && (TokenTraits::isLocationSpecifier(token) || token == Token::Constant)) { if (location != VariableDeclaration::Location::Unspecified) parserError(3548_error, "Location already specified."); @@ -950,6 +950,9 @@ ASTPointer Parser::parseVariableDeclaration( case Token::CallData: location = VariableDeclaration::Location::CallData; break; + case Token::Constant: + location = VariableDeclaration::Location::Constant; + break; default: solAssert(false, "Unknown data location."); } diff --git a/scripts/test_antlr_grammar.sh b/scripts/test_antlr_grammar.sh index c8e008c06d4b..f570765f6bf9 100755 --- a/scripts/test_antlr_grammar.sh +++ b/scripts/test_antlr_grammar.sh @@ -87,7 +87,10 @@ done < <( grep -v -E 'license/license_hidden_unicode.sol' | grep -v -E 'license/license_unicode.sol' | # Skipping tests with 'something.address' as 'address' as the grammar fails on those - grep -v -E 'inlineAssembly/external_function_pointer_address.*.sol' + grep -v -E 'inlineAssembly/external_function_pointer_address.*.sol' | + # Skipping a test with 'uint constant local' because ANTLR accepts 'constant' + # as a data location while the Solidity parser only allows it for function parameters. + grep -v -E 'parsing/local_const_variable.sol' ) YUL_FILES=() diff --git a/test/libsolidity/ASTJSON/constant_data_location.json b/test/libsolidity/ASTJSON/constant_data_location.json new file mode 100644 index 000000000000..43cf9f9a9d66 --- /dev/null +++ b/test/libsolidity/ASTJSON/constant_data_location.json @@ -0,0 +1,550 @@ +{ + "absolutePath": "a", + "exportedSymbols": { + "C": [ + 39 + ] + }, + "id": 40, + "nodeType": "SourceUnit", + "nodes": [ + { + "abstract": false, + "baseContracts": [], + "canonicalName": "C", + "contractDependencies": [], + "contractKind": "contract", + "fullyImplemented": true, + "id": 39, + "linearizedBaseContracts": [ + 39 + ], + "name": "C", + "nameLocation": "9:1:1", + "nodeType": "ContractDefinition", + "nodes": [ + { + "canonicalName": "C.Config", + "id": 5, + "members": [ + { + "constant": false, + "id": 2, + "mutability": "mutable", + "name": "fee", + "nameLocation": "41:3:1", + "nodeType": "VariableDeclaration", + "scope": 5, + "src": "33:11:1", + "stateVariable": false, + "storageLocation": "default", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + }, + "typeName": { + "id": 1, + "name": "uint256", + "nodeType": "ElementaryTypeName", + "src": "33:7:1", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + }, + "visibility": "internal" + }, + { + "constant": false, + "id": 4, + "mutability": "mutable", + "name": "admin", + "nameLocation": "54:5:1", + "nodeType": "VariableDeclaration", + "scope": 5, + "src": "46:13:1", + "stateVariable": false, + "storageLocation": "default", + "typeDescriptions": { + "typeIdentifier": "t_address", + "typeString": "address" + }, + "typeName": { + "id": 3, + "name": "address", + "nodeType": "ElementaryTypeName", + "src": "46:7:1", + "stateMutability": "nonpayable", + "typeDescriptions": { + "typeIdentifier": "t_address", + "typeString": "address" + } + }, + "visibility": "internal" + } + ], + "name": "Config", + "nameLocation": "24:6:1", + "nodeType": "StructDefinition", + "scope": 39, + "src": "17:45:1", + "visibility": "public" + }, + { + "constant": true, + "id": 15, + "mutability": "constant", + "name": "cfg", + "nameLocation": "83:3:1", + "nodeType": "VariableDeclaration", + "scope": 39, + "src": "67:49:1", + "stateVariable": true, + "storageLocation": "default", + "typeDescriptions": { + "typeIdentifier": "t_struct$_Config_$5_constant_ptr", + "typeString": "struct C.Config" + }, + "typeName": { + "id": 7, + "nodeType": "UserDefinedTypeName", + "pathNode": { + "id": 6, + "name": "Config", + "nameLocations": [ + "67:6:1" + ], + "nodeType": "IdentifierPath", + "referencedDeclaration": 5, + "src": "67:6:1" + }, + "referencedDeclaration": 5, + "src": "67:6:1", + "typeDescriptions": { + "typeIdentifier": "t_struct$_Config_$5_storage_ptr", + "typeString": "struct C.Config" + } + }, + "value": { + "arguments": [ + { + "hexValue": "3432", + "id": 9, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "number", + "lValueRequested": false, + "nodeType": "Literal", + "src": "96:2:1", + "typeDescriptions": { + "typeIdentifier": "t_rational_42_by_1", + "typeString": "int_const 42" + }, + "value": "42" + }, + { + "arguments": [ + { + "hexValue": "307831323334", + "id": 12, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "number", + "lValueRequested": false, + "nodeType": "Literal", + "src": "108:6:1", + "typeDescriptions": { + "typeIdentifier": "t_rational_4660_by_1", + "typeString": "int_const 4660" + }, + "value": "0x1234" + } + ], + "expression": { + "argumentTypes": [ + { + "typeIdentifier": "t_rational_4660_by_1", + "typeString": "int_const 4660" + } + ], + "id": 11, + "isConstant": false, + "isLValue": false, + "isPure": true, + "lValueRequested": false, + "nodeType": "ElementaryTypeNameExpression", + "src": "100:7:1", + "typeDescriptions": { + "typeIdentifier": "t_type$_t_address_$", + "typeString": "type(address)" + }, + "typeName": { + "id": 10, + "name": "address", + "nodeType": "ElementaryTypeName", + "src": "100:7:1", + "typeDescriptions": {} + } + }, + "id": 13, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "typeConversion", + "lValueRequested": false, + "nameLocations": [], + "names": [], + "nodeType": "FunctionCall", + "src": "100:15:1", + "tryCall": false, + "typeDescriptions": { + "typeIdentifier": "t_address", + "typeString": "address" + } + } + ], + "expression": { + "argumentTypes": [ + { + "typeIdentifier": "t_rational_42_by_1", + "typeString": "int_const 42" + }, + { + "typeIdentifier": "t_address", + "typeString": "address" + } + ], + "id": 8, + "name": "Config", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 5, + "src": "89:6:1", + "typeDescriptions": { + "typeIdentifier": "t_type$_t_struct$_Config_$5_storage_ptr_$", + "typeString": "type(struct C.Config storage pointer)" + } + }, + "id": 14, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "structConstructorCall", + "lValueRequested": false, + "nameLocations": [], + "names": [], + "nodeType": "FunctionCall", + "src": "89:27:1", + "tryCall": false, + "typeDescriptions": { + "typeIdentifier": "t_struct$_Config_$5_memory_ptr", + "typeString": "struct C.Config memory" + } + }, + "visibility": "internal" + }, + { + "constant": true, + "id": 26, + "mutability": "constant", + "name": "arr", + "nameLocation": "142:3:1", + "nodeType": "VariableDeclaration", + "scope": 39, + "src": "122:44:1", + "stateVariable": true, + "storageLocation": "default", + "typeDescriptions": { + "typeIdentifier": "t_array$_t_uint256_$3_constant_ptr", + "typeString": "uint256[3]" + }, + "typeName": { + "baseType": { + "id": 16, + "name": "uint256", + "nodeType": "ElementaryTypeName", + "src": "122:7:1", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + }, + "id": 18, + "length": { + "hexValue": "33", + "id": 17, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "number", + "lValueRequested": false, + "nodeType": "Literal", + "src": "130:1:1", + "typeDescriptions": { + "typeIdentifier": "t_rational_3_by_1", + "typeString": "int_const 3" + }, + "value": "3" + }, + "nodeType": "ArrayTypeName", + "src": "122:10:1", + "typeDescriptions": { + "typeIdentifier": "t_array$_t_uint256_$3_storage_ptr", + "typeString": "uint256[3]" + } + }, + "value": { + "components": [ + { + "arguments": [ + { + "hexValue": "31", + "id": 21, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "number", + "lValueRequested": false, + "nodeType": "Literal", + "src": "157:1:1", + "typeDescriptions": { + "typeIdentifier": "t_rational_1_by_1", + "typeString": "int_const 1" + }, + "value": "1" + } + ], + "expression": { + "argumentTypes": [ + { + "typeIdentifier": "t_rational_1_by_1", + "typeString": "int_const 1" + } + ], + "id": 20, + "isConstant": false, + "isLValue": false, + "isPure": true, + "lValueRequested": false, + "nodeType": "ElementaryTypeNameExpression", + "src": "149:7:1", + "typeDescriptions": { + "typeIdentifier": "t_type$_t_uint256_$", + "typeString": "type(uint256)" + }, + "typeName": { + "id": 19, + "name": "uint256", + "nodeType": "ElementaryTypeName", + "src": "149:7:1", + "typeDescriptions": {} + } + }, + "id": 22, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "typeConversion", + "lValueRequested": false, + "nameLocations": [], + "names": [], + "nodeType": "FunctionCall", + "src": "149:10:1", + "tryCall": false, + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + }, + { + "hexValue": "32", + "id": 23, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "number", + "lValueRequested": false, + "nodeType": "Literal", + "src": "161:1:1", + "typeDescriptions": { + "typeIdentifier": "t_rational_2_by_1", + "typeString": "int_const 2" + }, + "value": "2" + }, + { + "hexValue": "33", + "id": 24, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "number", + "lValueRequested": false, + "nodeType": "Literal", + "src": "164:1:1", + "typeDescriptions": { + "typeIdentifier": "t_rational_3_by_1", + "typeString": "int_const 3" + }, + "value": "3" + } + ], + "id": 25, + "isConstant": false, + "isInlineArray": true, + "isLValue": false, + "isPure": true, + "lValueRequested": false, + "nodeType": "TupleExpression", + "src": "148:18:1", + "typeDescriptions": { + "typeIdentifier": "t_array$_t_uint256_$3_memory_ptr", + "typeString": "uint256[3] memory" + } + }, + "visibility": "internal" + }, + { + "body": { + "id": 37, + "nodeType": "Block", + "src": "234:17:1", + "statements": [ + { + "expression": { + "expression": { + "id": 34, + "name": "c", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 29, + "src": "243:1:1", + "typeDescriptions": { + "typeIdentifier": "t_struct$_Config_$5_constant_ptr", + "typeString": "struct C.Config constant" + } + }, + "id": 35, + "isConstant": false, + "isLValue": true, + "isPure": false, + "lValueRequested": false, + "memberLocation": "245:3:1", + "memberName": "fee", + "nodeType": "MemberAccess", + "referencedDeclaration": 2, + "src": "243:5:1", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + }, + "functionReturnParameters": 33, + "id": 36, + "nodeType": "Return", + "src": "236:12:1" + } + ] + }, + "id": 38, + "implemented": true, + "kind": "function", + "modifiers": [], + "name": "f", + "nameLocation": "181:1:1", + "nodeType": "FunctionDefinition", + "parameters": { + "id": 30, + "nodeType": "ParameterList", + "parameters": [ + { + "constant": false, + "id": 29, + "mutability": "mutable", + "name": "c", + "nameLocation": "199:1:1", + "nodeType": "VariableDeclaration", + "scope": 38, + "src": "183:17:1", + "stateVariable": false, + "storageLocation": "constant", + "typeDescriptions": { + "typeIdentifier": "t_struct$_Config_$5_constant_ptr", + "typeString": "struct C.Config" + }, + "typeName": { + "id": 28, + "nodeType": "UserDefinedTypeName", + "pathNode": { + "id": 27, + "name": "Config", + "nameLocations": [ + "183:6:1" + ], + "nodeType": "IdentifierPath", + "referencedDeclaration": 5, + "src": "183:6:1" + }, + "referencedDeclaration": 5, + "src": "183:6:1", + "typeDescriptions": { + "typeIdentifier": "t_struct$_Config_$5_storage_ptr", + "typeString": "struct C.Config" + } + }, + "visibility": "internal" + } + ], + "src": "182:19:1" + }, + "returnParameters": { + "id": 33, + "nodeType": "ParameterList", + "parameters": [ + { + "constant": false, + "id": 32, + "mutability": "mutable", + "name": "", + "nameLocation": "-1:-1:-1", + "nodeType": "VariableDeclaration", + "scope": 38, + "src": "225:7:1", + "stateVariable": false, + "storageLocation": "default", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + }, + "typeName": { + "id": 31, + "name": "uint256", + "nodeType": "ElementaryTypeName", + "src": "225:7:1", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + }, + "visibility": "internal" + } + ], + "src": "224:9:1" + }, + "scope": 39, + "src": "172:79:1", + "stateMutability": "pure", + "virtual": false, + "visibility": "internal" + } + ], + "scope": 40, + "src": "0:253:1", + "usedErrors": [], + "usedEvents": [] + } + ], + "src": "0:254:1" +} diff --git a/test/libsolidity/ASTJSON/constant_data_location.sol b/test/libsolidity/ASTJSON/constant_data_location.sol new file mode 100644 index 000000000000..dfcff7da6362 --- /dev/null +++ b/test/libsolidity/ASTJSON/constant_data_location.sol @@ -0,0 +1,9 @@ +contract C +{ + struct Config { uint256 fee; address admin; } + Config constant cfg = Config(42, address(0x1234)); + uint256[3] constant arr = [uint256(1), 2, 3]; + function f(Config constant c) internal pure returns (uint256) { return c.fee; } +} + +// ---- diff --git a/test/libsolidity/semanticTests/constants/constant_array_of_structs.sol b/test/libsolidity/semanticTests/constants/constant_array_of_structs.sol new file mode 100644 index 000000000000..ecd19fcda451 --- /dev/null +++ b/test/libsolidity/semanticTests/constants/constant_array_of_structs.sol @@ -0,0 +1,16 @@ +contract C { + struct Point { uint256 x; uint256 y; } + Point[3] constant POINTS = [Point(10, 20), Point(30, 40), Point(50, 60)]; + + function getX(uint256 i) public pure returns (uint256) { return POINTS[i].x; } + function getY(uint256 i) public pure returns (uint256) { return POINTS[i].y; } +} +// ==== +// compileViaYul: true +// ---- +// getX(uint256): 0 -> 10 +// getY(uint256): 0 -> 20 +// getX(uint256): 1 -> 30 +// getY(uint256): 1 -> 40 +// getX(uint256): 2 -> 50 +// getY(uint256): 2 -> 60 diff --git a/test/libsolidity/semanticTests/constants/constant_array_slicing.sol b/test/libsolidity/semanticTests/constants/constant_array_slicing.sol new file mode 100644 index 000000000000..802301c04152 --- /dev/null +++ b/test/libsolidity/semanticTests/constants/constant_array_slicing.sol @@ -0,0 +1,42 @@ +contract C { + uint256[] constant DATA = [uint256(10), 20, 30, 40, 50]; + + function len() public pure returns (uint256) { + return DATA.length; + } + function get(uint256 i) public pure returns (uint256) { + return DATA[i]; + } + function sliceIdx(uint256 s, uint256 e, uint256 i) public pure returns (uint256) { + return DATA[s:e][i]; + } + function sliceStartOnly(uint256 s, uint256 i) public pure returns (uint256) { + return DATA[s:][i]; + } + function sliceEndOnly(uint256 e, uint256 i) public pure returns (uint256) { + return DATA[:e][i]; + } + function nestedSlice(uint256 s, uint256 e, uint256 ss, uint256 ee, uint256 i) public pure returns (uint256) { + return DATA[s:e][ss:ee][i]; + } +} +// ==== +// compileViaYul: true +// ---- +// len() -> 5 +// get(uint256): 0 -> 10 +// get(uint256): 4 -> 50 +// get(uint256): 5 -> FAILURE, hex"4e487b71", 0x32 +// sliceIdx(uint256,uint256,uint256): 1, 4, 0 -> 20 +// sliceIdx(uint256,uint256,uint256): 1, 4, 2 -> 40 +// sliceIdx(uint256,uint256,uint256): 0, 5, 4 -> 50 +// sliceIdx(uint256,uint256,uint256): 2, 2, 0 -> FAILURE, hex"4e487b71", 0x32 +// sliceIdx(uint256,uint256,uint256): 0, 6, 0 -> FAILURE +// sliceIdx(uint256,uint256,uint256): 3, 2, 0 -> FAILURE +// sliceStartOnly(uint256,uint256): 2, 0 -> 30 +// sliceStartOnly(uint256,uint256): 2, 2 -> 50 +// sliceStartOnly(uint256,uint256): 6, 0 -> FAILURE +// sliceEndOnly(uint256,uint256): 3, 0 -> 10 +// sliceEndOnly(uint256,uint256): 3, 2 -> 30 +// sliceEndOnly(uint256,uint256): 6, 0 -> FAILURE +// nestedSlice(uint256,uint256,uint256,uint256,uint256): 1, 4, 1, 2, 0 -> 30 diff --git a/test/libsolidity/semanticTests/constants/constant_enum_array.sol b/test/libsolidity/semanticTests/constants/constant_enum_array.sol new file mode 100644 index 000000000000..a0afb6c22eaa --- /dev/null +++ b/test/libsolidity/semanticTests/constants/constant_enum_array.sol @@ -0,0 +1,13 @@ +contract C { + enum Color { Red, Green, Blue } + + Color[3] constant colors = [Color.Red, Color.Green, Color.Blue]; + + function get(uint256 i) public pure returns (Color) { return colors[i]; } +} +// ==== +// compileViaYul: true +// ---- +// get(uint256): 0 -> 0 +// get(uint256): 1 -> 1 +// get(uint256): 2 -> 2 diff --git a/test/libsolidity/semanticTests/constants/constant_function_pointers.sol b/test/libsolidity/semanticTests/constants/constant_function_pointers.sol new file mode 100644 index 000000000000..313b280e6429 --- /dev/null +++ b/test/libsolidity/semanticTests/constants/constant_function_pointers.sol @@ -0,0 +1,21 @@ +contract C { + function add1(uint256 x) internal pure returns (uint256) { return x + 1; } + function mul2(uint256 x) internal pure returns (uint256) { return x * 2; } + function sub1(uint256 x) internal pure returns (uint256) { return x - 1; } + + function(uint256) internal pure returns (uint256)[3] constant ops = [add1, mul2, sub1]; + + function execAdd1(uint256 val) public pure returns (uint256) { return ops[0](val); } + function execMul2(uint256 val) public pure returns (uint256) { return ops[1](val); } + function execSub1(uint256 val) public pure returns (uint256) { return ops[2](val); } + function execDynamic(uint256 op, uint256 val) public pure returns (uint256) { return ops[op](val); } +} +// ==== +// compileViaYul: true +// ---- +// execAdd1(uint256): 10 -> 11 +// execMul2(uint256): 10 -> 20 +// execSub1(uint256): 10 -> 9 +// execDynamic(uint256,uint256): 0, 100 -> 101 +// execDynamic(uint256,uint256): 1, 100 -> 200 +// execDynamic(uint256,uint256): 2, 100 -> 99 diff --git a/test/libsolidity/semanticTests/constants/constant_nested_array.sol b/test/libsolidity/semanticTests/constants/constant_nested_array.sol new file mode 100644 index 000000000000..444f872e4a59 --- /dev/null +++ b/test/libsolidity/semanticTests/constants/constant_nested_array.sol @@ -0,0 +1,16 @@ +contract C { + uint256[2][3] constant MATRIX = [[uint256(1), 2], [uint256(3), 4], [uint256(5), 6]]; + + function get(uint256 i, uint256 j) public pure returns (uint256) { + return MATRIX[i][j]; + } +} +// ==== +// compileViaYul: true +// ---- +// get(uint256,uint256): 0, 0 -> 1 +// get(uint256,uint256): 0, 1 -> 2 +// get(uint256,uint256): 1, 0 -> 3 +// get(uint256,uint256): 1, 1 -> 4 +// get(uint256,uint256): 2, 0 -> 5 +// get(uint256,uint256): 2, 1 -> 6 diff --git a/test/libsolidity/semanticTests/constants/constant_nested_struct.sol b/test/libsolidity/semanticTests/constants/constant_nested_struct.sol new file mode 100644 index 000000000000..6d459f29ade3 --- /dev/null +++ b/test/libsolidity/semanticTests/constants/constant_nested_struct.sol @@ -0,0 +1,16 @@ +contract C { + struct Inner { uint256 a; uint256 b; } + struct Outer { Inner inner; uint256 c; } + + Outer constant nested = Outer(Inner(10, 20), 30); + + function getInnerA() public pure returns (uint256) { return nested.inner.a; } + function getInnerB() public pure returns (uint256) { return nested.inner.b; } + function getC() public pure returns (uint256) { return nested.c; } +} +// ==== +// compileViaYul: true +// ---- +// getInnerA() -> 10 +// getInnerB() -> 20 +// getC() -> 30 diff --git a/test/libsolidity/semanticTests/constants/constant_parameter_passing.sol b/test/libsolidity/semanticTests/constants/constant_parameter_passing.sol new file mode 100644 index 000000000000..816dd07ce066 --- /dev/null +++ b/test/libsolidity/semanticTests/constants/constant_parameter_passing.sol @@ -0,0 +1,20 @@ +contract C { + struct Config { uint256 fee; address admin; } + Config constant CFG = Config(42, address(0xdead)); + uint256[3] constant ARR = [uint256(1), 2, 3]; + + function readFee(Config constant cfg) internal pure returns (uint256) { + return cfg.fee; + } + function sumArr(uint256[3] constant a) internal pure returns (uint256) { + return a[0] + a[1] + a[2]; + } + + function testConfig() public pure returns (uint256) { return readFee(CFG); } + function testArr() public pure returns (uint256) { return sumArr(ARR); } +} +// ==== +// compileViaYul: true +// ---- +// testConfig() -> 42 +// testArr() -> 6 diff --git a/test/libsolidity/semanticTests/constants/constant_static_array.sol b/test/libsolidity/semanticTests/constants/constant_static_array.sol new file mode 100644 index 000000000000..d44b34795895 --- /dev/null +++ b/test/libsolidity/semanticTests/constants/constant_static_array.sol @@ -0,0 +1,18 @@ +contract C { + uint256[3] constant arr = [uint256(1), 2, 3]; + + function get0() public pure returns (uint256) { return arr[0]; } + function get1() public pure returns (uint256) { return arr[1]; } + function get2() public pure returns (uint256) { return arr[2]; } + function copyToMemory() public pure returns (uint256, uint256, uint256) { + uint256[3] memory m = arr; + return (m[0], m[1], m[2]); + } +} +// ==== +// compileViaYul: true +// ---- +// get0() -> 1 +// get1() -> 2 +// get2() -> 3 +// copyToMemory() -> 1, 2, 3 diff --git a/test/libsolidity/semanticTests/constants/constant_string_array.sol b/test/libsolidity/semanticTests/constants/constant_string_array.sol new file mode 100644 index 000000000000..751fd81b5903 --- /dev/null +++ b/test/libsolidity/semanticTests/constants/constant_string_array.sol @@ -0,0 +1,13 @@ +contract C { + string[3] constant NAMES = ["alice", "bob", "charlie"]; + + function get0() public pure returns (string memory) { return NAMES[0]; } + function get1() public pure returns (string memory) { return NAMES[1]; } + function get2() public pure returns (string memory) { return NAMES[2]; } +} +// ==== +// compileViaYul: true +// ---- +// get0() -> 0x20, 5, "alice" +// get1() -> 0x20, 3, "bob" +// get2() -> 0x20, 7, "charlie" diff --git a/test/libsolidity/semanticTests/constants/constant_struct.sol b/test/libsolidity/semanticTests/constants/constant_struct.sol new file mode 100644 index 000000000000..6cc71fc3ac4e --- /dev/null +++ b/test/libsolidity/semanticTests/constants/constant_struct.sol @@ -0,0 +1,19 @@ +contract C { + struct Config { + uint256 fee; + address router; + bytes32 tag; + } + + Config constant cfg = Config(42, address(0x1234), bytes32("test")); + + function getFee() public pure returns (uint256) { return cfg.fee; } + function getRouter() public pure returns (address) { return cfg.router; } + function getTag() public pure returns (bytes32) { return cfg.tag; } +} +// ==== +// compileViaYul: true +// ---- +// getFee() -> 42 +// getRouter() -> 0x0000000000000000000000000000000000001234 +// getTag() -> 0x7465737400000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/semanticTests/constants/constant_struct_with_array.sol b/test/libsolidity/semanticTests/constants/constant_struct_with_array.sol new file mode 100644 index 000000000000..8093a9e53797 --- /dev/null +++ b/test/libsolidity/semanticTests/constants/constant_struct_with_array.sol @@ -0,0 +1,17 @@ +contract C { + struct Config { + uint256[3] fees; + address admin; + } + Config constant CFG = Config([uint256(100), 200, 300], address(0xdead)); + + function getFee(uint256 i) public pure returns (uint256) { return CFG.fees[i]; } + function getAdmin() public pure returns (address) { return CFG.admin; } +} +// ==== +// compileViaYul: true +// ---- +// getFee(uint256): 0 -> 100 +// getFee(uint256): 1 -> 200 +// getFee(uint256): 2 -> 300 +// getAdmin() -> 0x000000000000000000000000000000000000dead diff --git a/test/libsolidity/semanticTests/constants/constant_struct_with_string.sol b/test/libsolidity/semanticTests/constants/constant_struct_with_string.sol new file mode 100644 index 000000000000..e25a363cf5a5 --- /dev/null +++ b/test/libsolidity/semanticTests/constants/constant_struct_with_string.sol @@ -0,0 +1,15 @@ +contract C { + struct Profile { + string name; + uint256 age; + } + Profile constant PROF = Profile("alice", 30); + + function getName() public pure returns (string memory) { return PROF.name; } + function getAge() public pure returns (uint256) { return PROF.age; } +} +// ==== +// compileViaYul: true +// ---- +// getName() -> 0x20, 5, "alice" +// getAge() -> 30 diff --git a/test/libsolidity/syntaxTests/array/concat/bytes_concat_wrong_type_misc_literals_and_expressions.sol b/test/libsolidity/syntaxTests/array/concat/bytes_concat_wrong_type_misc_literals_and_expressions.sol index 8d5374e84462..72c5bb236a88 100644 --- a/test/libsolidity/syntaxTests/array/concat/bytes_concat_wrong_type_misc_literals_and_expressions.sol +++ b/test/libsolidity/syntaxTests/array/concat/bytes_concat_wrong_type_misc_literals_and_expressions.sol @@ -33,8 +33,8 @@ contract C { } // ---- // TypeError 9640: (697-779): Explicit type conversion not allowed from "bytes32" to "bytes memory". -// TypeError 1227: (697-782): Index range access is only supported for dynamic calldata arrays. -// TypeError 1227: (864-870): Index range access is only supported for dynamic calldata arrays. +// TypeError 1227: (697-782): Index range access is only supported for dynamic calldata or constant arrays. +// TypeError 1227: (864-870): Index range access is only supported for dynamic calldata or constant arrays. // TypeError 8015: (133-138): Invalid type for argument in the bytes.concat function call. bytes or fixed bytes type is required, but bool provided. // TypeError 8015: (152-153): Invalid type for argument in the bytes.concat function call. bytes or fixed bytes type is required, but int_const 1 provided. // TypeError 8015: (167-171): Invalid type for argument in the bytes.concat function call. bytes or fixed bytes type is required, but int_const 10000000000 provided. diff --git a/test/libsolidity/syntaxTests/array/length/array_length_cannot_be_constant_function_parameter.sol b/test/libsolidity/syntaxTests/array/length/array_length_cannot_be_constant_function_parameter.sol index cc979668ccab..5c4b39fc1b26 100644 --- a/test/libsolidity/syntaxTests/array/length/array_length_cannot_be_constant_function_parameter.sol +++ b/test/libsolidity/syntaxTests/array/length/array_length_cannot_be_constant_function_parameter.sol @@ -4,6 +4,6 @@ contract C { } } // ---- -// DeclarationError 1788: (28-45): The "constant" keyword can only be used for state variables or variables at file level. +// TypeError 6651: (28-45): Data location can only be specified for array, struct or mapping types, but "constant" was given. // TypeError 5462: (69-72): Invalid array length, expected integer literal or constant expression. // TypeError 6651: (64-75): Data location must be "storage", "memory" or "calldata" for variable, but none was given. diff --git a/test/libsolidity/syntaxTests/array/slice/bytes_memory.sol b/test/libsolidity/syntaxTests/array/slice/bytes_memory.sol index c75f27c63fc2..3b43f32b4b80 100644 --- a/test/libsolidity/syntaxTests/array/slice/bytes_memory.sol +++ b/test/libsolidity/syntaxTests/array/slice/bytes_memory.sol @@ -4,4 +4,4 @@ contract C { } } // ---- -// TypeError 1227: (66-72): Index range access is only supported for dynamic calldata arrays. +// TypeError 1227: (66-72): Index range access is only supported for dynamic calldata or constant arrays. diff --git a/test/libsolidity/syntaxTests/array/slice/bytes_storage.sol b/test/libsolidity/syntaxTests/array/slice/bytes_storage.sol index a42193d618de..c5a044558a62 100644 --- a/test/libsolidity/syntaxTests/array/slice/bytes_storage.sol +++ b/test/libsolidity/syntaxTests/array/slice/bytes_storage.sol @@ -5,4 +5,4 @@ contract C { } } // ---- -// TypeError 1227: (65-71): Index range access is only supported for dynamic calldata arrays. +// TypeError 1227: (65-71): Index range access is only supported for dynamic calldata or constant arrays. diff --git a/test/libsolidity/syntaxTests/array/slice/calldata_static.sol b/test/libsolidity/syntaxTests/array/slice/calldata_static.sol index c78e2a12e16c..b413abe38b43 100644 --- a/test/libsolidity/syntaxTests/array/slice/calldata_static.sol +++ b/test/libsolidity/syntaxTests/array/slice/calldata_static.sol @@ -4,4 +4,4 @@ contract C { } } // ---- -// TypeError 1227: (76-82): Index range access is only supported for dynamic calldata arrays. +// TypeError 1227: (76-82): Index range access is only supported for dynamic calldata or constant arrays. diff --git a/test/libsolidity/syntaxTests/array/slice/memory_dynamic.sol b/test/libsolidity/syntaxTests/array/slice/memory_dynamic.sol index 0a881ef62363..37f3928ce621 100644 --- a/test/libsolidity/syntaxTests/array/slice/memory_dynamic.sol +++ b/test/libsolidity/syntaxTests/array/slice/memory_dynamic.sol @@ -4,4 +4,4 @@ contract C { } } // ---- -// TypeError 1227: (70-76): Index range access is only supported for dynamic calldata arrays. +// TypeError 1227: (70-76): Index range access is only supported for dynamic calldata or constant arrays. diff --git a/test/libsolidity/syntaxTests/array/slice/memory_static.sol b/test/libsolidity/syntaxTests/array/slice/memory_static.sol index 89f49ed963af..8612839ccfe7 100644 --- a/test/libsolidity/syntaxTests/array/slice/memory_static.sol +++ b/test/libsolidity/syntaxTests/array/slice/memory_static.sol @@ -4,4 +4,4 @@ contract C { } } // ---- -// TypeError 1227: (72-78): Index range access is only supported for dynamic calldata arrays. +// TypeError 1227: (72-78): Index range access is only supported for dynamic calldata or constant arrays. diff --git a/test/libsolidity/syntaxTests/array/slice/slice_memory_bytes.sol b/test/libsolidity/syntaxTests/array/slice/slice_memory_bytes.sol index 6b93721fc401..cbb46a8f47d0 100644 --- a/test/libsolidity/syntaxTests/array/slice/slice_memory_bytes.sol +++ b/test/libsolidity/syntaxTests/array/slice/slice_memory_bytes.sol @@ -5,4 +5,4 @@ contract C { } } // ---- -// TypeError 1227: (76-82): Index range access is only supported for dynamic calldata arrays. +// TypeError 1227: (76-82): Index range access is only supported for dynamic calldata or constant arrays. diff --git a/test/libsolidity/syntaxTests/array/slice/slice_memory_string.sol b/test/libsolidity/syntaxTests/array/slice/slice_memory_string.sol index cfb1da8b52a4..00f8ce1de5a8 100644 --- a/test/libsolidity/syntaxTests/array/slice/slice_memory_string.sol +++ b/test/libsolidity/syntaxTests/array/slice/slice_memory_string.sol @@ -5,4 +5,4 @@ contract C { } } // ---- -// TypeError 1227: (77-83): Index range access is only supported for dynamic calldata arrays. +// TypeError 1227: (77-83): Index range access is only supported for dynamic calldata or constant arrays. diff --git a/test/libsolidity/syntaxTests/array/slice/storage_dynamic.sol b/test/libsolidity/syntaxTests/array/slice/storage_dynamic.sol index 270209550197..3c07f4f388e3 100644 --- a/test/libsolidity/syntaxTests/array/slice/storage_dynamic.sol +++ b/test/libsolidity/syntaxTests/array/slice/storage_dynamic.sol @@ -5,4 +5,4 @@ contract C { } } // ---- -// TypeError 1227: (69-75): Index range access is only supported for dynamic calldata arrays. +// TypeError 1227: (69-75): Index range access is only supported for dynamic calldata or constant arrays. diff --git a/test/libsolidity/syntaxTests/array/slice/storage_static.sol b/test/libsolidity/syntaxTests/array/slice/storage_static.sol index 415276c18f5d..4e4e72fe4722 100644 --- a/test/libsolidity/syntaxTests/array/slice/storage_static.sol +++ b/test/libsolidity/syntaxTests/array/slice/storage_static.sol @@ -5,4 +5,4 @@ contract C { } } // ---- -// TypeError 1227: (71-77): Index range access is only supported for dynamic calldata arrays. +// TypeError 1227: (71-77): Index range access is only supported for dynamic calldata or constant arrays. diff --git a/test/libsolidity/syntaxTests/constantEvaluator/type_reference.sol b/test/libsolidity/syntaxTests/constantEvaluator/type_reference.sol index 086d89151262..585c005f6229 100644 --- a/test/libsolidity/syntaxTests/constantEvaluator/type_reference.sol +++ b/test/libsolidity/syntaxTests/constantEvaluator/type_reference.sol @@ -1,4 +1,3 @@ int[L] constant L = 6; // ---- // TypeError 5462: (4-5): Invalid array length, expected integer literal or constant expression. -// TypeError 9259: (0-21): Only constants of value type and byte array type are implemented. diff --git a/test/libsolidity/syntaxTests/constantEvaluator/type_reference_in_contract.sol b/test/libsolidity/syntaxTests/constantEvaluator/type_reference_in_contract.sol index dfb81378b43f..9073f6ac16eb 100644 --- a/test/libsolidity/syntaxTests/constantEvaluator/type_reference_in_contract.sol +++ b/test/libsolidity/syntaxTests/constantEvaluator/type_reference_in_contract.sol @@ -3,4 +3,3 @@ contract C { } // ---- // TypeError 5462: (21-22): Invalid array length, expected integer literal or constant expression. -// TypeError 9259: (17-38): Only constants of value type and byte array type are implemented. diff --git a/test/libsolidity/syntaxTests/constants/mapping_constant.sol b/test/libsolidity/syntaxTests/constants/mapping_constant.sol index e6b5b124a9de..c306cf467542 100644 --- a/test/libsolidity/syntaxTests/constants/mapping_constant.sol +++ b/test/libsolidity/syntaxTests/constants/mapping_constant.sol @@ -1,3 +1,3 @@ mapping(uint => uint) constant b = b; // ---- -// TypeError 9259: (0-36): Only constants of value type and byte array type are implemented. +// TypeError 9259: (0-36): Constants of this type are not supported. Only value types, arrays, structs, and byte/string types without mappings are allowed. diff --git a/test/libsolidity/syntaxTests/constants/struct_constant.sol b/test/libsolidity/syntaxTests/constants/struct_constant.sol index 9195dac0c85b..e59c9574be4c 100644 --- a/test/libsolidity/syntaxTests/constants/struct_constant.sol +++ b/test/libsolidity/syntaxTests/constants/struct_constant.sol @@ -1,4 +1,4 @@ struct S { uint x; } S constant s; // ---- -// TypeError 9259: (21-33): Only constants of value type and byte array type are implemented. +// TypeError 4266: (21-33): Uninitialized "constant" variable. diff --git a/test/libsolidity/syntaxTests/dataLocations/internalFunction/function_argument_location_specifier_test_internal_transient.sol b/test/libsolidity/syntaxTests/dataLocations/internalFunction/function_argument_location_specifier_test_internal_transient.sol index 4a5b6f999d86..f3fa05a2b3ea 100644 --- a/test/libsolidity/syntaxTests/dataLocations/internalFunction/function_argument_location_specifier_test_internal_transient.sol +++ b/test/libsolidity/syntaxTests/dataLocations/internalFunction/function_argument_location_specifier_test_internal_transient.sol @@ -2,4 +2,4 @@ contract test { function f(bytes transient) internal {} } // ---- -// TypeError 6651: (31-46): Data location must be "storage", "memory" or "calldata" for parameter in function, but none was given. +// TypeError 6651: (31-46): Data location must be "storage", "memory", "calldata" or "constant" for parameter in function, but none was given. diff --git a/test/libsolidity/syntaxTests/dataLocations/internalFunction/internal_function_parameters_no_data_location.sol b/test/libsolidity/syntaxTests/dataLocations/internalFunction/internal_function_parameters_no_data_location.sol index 64df444d6494..8ccac57b0396 100644 --- a/test/libsolidity/syntaxTests/dataLocations/internalFunction/internal_function_parameters_no_data_location.sol +++ b/test/libsolidity/syntaxTests/dataLocations/internalFunction/internal_function_parameters_no_data_location.sol @@ -2,4 +2,4 @@ contract C { function g(uint[]) internal pure {} } // ---- -// TypeError 6651: (28-34): Data location must be "storage", "memory" or "calldata" for parameter in function, but none was given. +// TypeError 6651: (28-34): Data location must be "storage", "memory", "calldata" or "constant" for parameter in function, but none was given. diff --git a/test/libsolidity/syntaxTests/dataLocations/internalFunction/internal_function_return_parameters_no_data_location.sol b/test/libsolidity/syntaxTests/dataLocations/internalFunction/internal_function_return_parameters_no_data_location.sol index d8d6ab2a5dd7..752089e0324d 100644 --- a/test/libsolidity/syntaxTests/dataLocations/internalFunction/internal_function_return_parameters_no_data_location.sol +++ b/test/libsolidity/syntaxTests/dataLocations/internalFunction/internal_function_return_parameters_no_data_location.sol @@ -2,4 +2,4 @@ contract C { function g() internal pure returns(uint[]) {} } // ---- -// TypeError 6651: (52-58): Data location must be "storage", "memory" or "calldata" for return parameter in function, but none was given. +// TypeError 6651: (52-58): Data location must be "storage", "memory", "calldata" or "constant" for return parameter in function, but none was given. diff --git a/test/libsolidity/syntaxTests/dataLocations/libraries/library_function_with_data_location_transient.sol b/test/libsolidity/syntaxTests/dataLocations/libraries/library_function_with_data_location_transient.sol index 75253342c4e0..234a80c50749 100644 --- a/test/libsolidity/syntaxTests/dataLocations/libraries/library_function_with_data_location_transient.sol +++ b/test/libsolidity/syntaxTests/dataLocations/libraries/library_function_with_data_location_transient.sol @@ -9,10 +9,10 @@ library L { function i2() external pure returns (uint[] transient) { } } // ---- -// TypeError 6651: (28-44): Data location must be "storage", "memory" or "calldata" for parameter in function, but none was given. -// TypeError 6651: (103-119): Data location must be "storage", "memory" or "calldata" for return parameter in function, but none was given. -// TypeError 6651: (141-157): Data location must be "storage", "memory" or "calldata" for parameter in function, but none was given. -// TypeError 6651: (218-234): Data location must be "storage", "memory" or "calldata" for return parameter in function, but none was given. +// TypeError 6651: (28-44): Data location must be "storage", "memory", "calldata" or "constant" for parameter in function, but none was given. +// TypeError 6651: (103-119): Data location must be "storage", "memory", "calldata" or "constant" for return parameter in function, but none was given. +// TypeError 6651: (141-157): Data location must be "storage", "memory", "calldata" or "constant" for parameter in function, but none was given. +// TypeError 6651: (218-234): Data location must be "storage", "memory", "calldata" or "constant" for return parameter in function, but none was given. // TypeError 6651: (256-272): Data location must be "storage", "memory" or "calldata" for parameter in function, but none was given. // TypeError 6651: (329-345): Data location must be "storage", "memory" or "calldata" for return parameter in function, but none was given. // TypeError 6651: (367-383): Data location must be "storage", "memory" or "calldata" for parameter in external function, but none was given. diff --git a/test/libsolidity/syntaxTests/dataLocations/libraries/library_internal_function_no_data_location.sol b/test/libsolidity/syntaxTests/dataLocations/libraries/library_internal_function_no_data_location.sol index 97c246203dd1..7e2e05df47db 100644 --- a/test/libsolidity/syntaxTests/dataLocations/libraries/library_internal_function_no_data_location.sol +++ b/test/libsolidity/syntaxTests/dataLocations/libraries/library_internal_function_no_data_location.sol @@ -10,11 +10,11 @@ library L { function jp(mapping(uint => uint)) internal pure {} } // ---- -// TypeError 6651: (77-84): Data location must be "storage", "memory" or "calldata" for return parameter in function, but none was given. -// TypeError 6651: (129-135): Data location must be "storage", "memory" or "calldata" for return parameter in function, but none was given. -// TypeError 6651: (180-181): Data location must be "storage", "memory" or "calldata" for return parameter in function, but none was given. -// TypeError 6651: (226-247): Data location must be "storage", "memory" or "calldata" for return parameter in function, but none was given. -// TypeError 6651: (268-275): Data location must be "storage", "memory" or "calldata" for parameter in function, but none was given. -// TypeError 6651: (310-316): Data location must be "storage", "memory" or "calldata" for parameter in function, but none was given. -// TypeError 6651: (351-352): Data location must be "storage", "memory" or "calldata" for parameter in function, but none was given. -// TypeError 6651: (387-408): Data location must be "storage", "memory" or "calldata" for parameter in function, but none was given. +// TypeError 6651: (77-84): Data location must be "storage", "memory", "calldata" or "constant" for return parameter in function, but none was given. +// TypeError 6651: (129-135): Data location must be "storage", "memory", "calldata" or "constant" for return parameter in function, but none was given. +// TypeError 6651: (180-181): Data location must be "storage", "memory", "calldata" or "constant" for return parameter in function, but none was given. +// TypeError 6651: (226-247): Data location must be "storage", "memory", "calldata" or "constant" for return parameter in function, but none was given. +// TypeError 6651: (268-275): Data location must be "storage", "memory", "calldata" or "constant" for parameter in function, but none was given. +// TypeError 6651: (310-316): Data location must be "storage", "memory", "calldata" or "constant" for parameter in function, but none was given. +// TypeError 6651: (351-352): Data location must be "storage", "memory", "calldata" or "constant" for parameter in function, but none was given. +// TypeError 6651: (387-408): Data location must be "storage", "memory", "calldata" or "constant" for parameter in function, but none was given. diff --git a/test/libsolidity/syntaxTests/dataLocations/libraries/library_private_function_no_data_location.sol b/test/libsolidity/syntaxTests/dataLocations/libraries/library_private_function_no_data_location.sol index 277eafd5bde8..8c0eac5b8bfe 100644 --- a/test/libsolidity/syntaxTests/dataLocations/libraries/library_private_function_no_data_location.sol +++ b/test/libsolidity/syntaxTests/dataLocations/libraries/library_private_function_no_data_location.sol @@ -10,11 +10,11 @@ library L { function jp(mapping(uint => uint)) private pure {} } // ---- -// TypeError 6651: (76-83): Data location must be "storage", "memory" or "calldata" for return parameter in function, but none was given. -// TypeError 6651: (127-133): Data location must be "storage", "memory" or "calldata" for return parameter in function, but none was given. -// TypeError 6651: (177-178): Data location must be "storage", "memory" or "calldata" for return parameter in function, but none was given. -// TypeError 6651: (222-243): Data location must be "storage", "memory" or "calldata" for return parameter in function, but none was given. -// TypeError 6651: (264-271): Data location must be "storage", "memory" or "calldata" for parameter in function, but none was given. -// TypeError 6651: (305-311): Data location must be "storage", "memory" or "calldata" for parameter in function, but none was given. -// TypeError 6651: (345-346): Data location must be "storage", "memory" or "calldata" for parameter in function, but none was given. -// TypeError 6651: (380-401): Data location must be "storage", "memory" or "calldata" for parameter in function, but none was given. +// TypeError 6651: (76-83): Data location must be "storage", "memory", "calldata" or "constant" for return parameter in function, but none was given. +// TypeError 6651: (127-133): Data location must be "storage", "memory", "calldata" or "constant" for return parameter in function, but none was given. +// TypeError 6651: (177-178): Data location must be "storage", "memory", "calldata" or "constant" for return parameter in function, but none was given. +// TypeError 6651: (222-243): Data location must be "storage", "memory", "calldata" or "constant" for return parameter in function, but none was given. +// TypeError 6651: (264-271): Data location must be "storage", "memory", "calldata" or "constant" for parameter in function, but none was given. +// TypeError 6651: (305-311): Data location must be "storage", "memory", "calldata" or "constant" for parameter in function, but none was given. +// TypeError 6651: (345-346): Data location must be "storage", "memory", "calldata" or "constant" for parameter in function, but none was given. +// TypeError 6651: (380-401): Data location must be "storage", "memory", "calldata" or "constant" for parameter in function, but none was given. diff --git a/test/libsolidity/syntaxTests/dataLocations/libraries/library_public_function_no_data_location.sol b/test/libsolidity/syntaxTests/dataLocations/libraries/library_public_function_no_data_location.sol index 9f01d2cab402..b6739eaccb23 100644 --- a/test/libsolidity/syntaxTests/dataLocations/libraries/library_public_function_no_data_location.sol +++ b/test/libsolidity/syntaxTests/dataLocations/libraries/library_public_function_no_data_location.sol @@ -9,11 +9,11 @@ library L { function ip(S) private pure {} function jp(mapping(uint => uint)) private pure {}} // ---- -// TypeError 6651: (76-83): Data location must be "storage", "memory" or "calldata" for return parameter in function, but none was given. -// TypeError 6651: (127-133): Data location must be "storage", "memory" or "calldata" for return parameter in function, but none was given. -// TypeError 6651: (177-178): Data location must be "storage", "memory" or "calldata" for return parameter in function, but none was given. -// TypeError 6651: (222-243): Data location must be "storage", "memory" or "calldata" for return parameter in function, but none was given. -// TypeError 6651: (264-271): Data location must be "storage", "memory" or "calldata" for parameter in function, but none was given. -// TypeError 6651: (305-311): Data location must be "storage", "memory" or "calldata" for parameter in function, but none was given. -// TypeError 6651: (345-346): Data location must be "storage", "memory" or "calldata" for parameter in function, but none was given. -// TypeError 6651: (380-401): Data location must be "storage", "memory" or "calldata" for parameter in function, but none was given. +// TypeError 6651: (76-83): Data location must be "storage", "memory", "calldata" or "constant" for return parameter in function, but none was given. +// TypeError 6651: (127-133): Data location must be "storage", "memory", "calldata" or "constant" for return parameter in function, but none was given. +// TypeError 6651: (177-178): Data location must be "storage", "memory", "calldata" or "constant" for return parameter in function, but none was given. +// TypeError 6651: (222-243): Data location must be "storage", "memory", "calldata" or "constant" for return parameter in function, but none was given. +// TypeError 6651: (264-271): Data location must be "storage", "memory", "calldata" or "constant" for parameter in function, but none was given. +// TypeError 6651: (305-311): Data location must be "storage", "memory", "calldata" or "constant" for parameter in function, but none was given. +// TypeError 6651: (345-346): Data location must be "storage", "memory", "calldata" or "constant" for parameter in function, but none was given. +// TypeError 6651: (380-401): Data location must be "storage", "memory", "calldata" or "constant" for parameter in function, but none was given. diff --git a/test/libsolidity/syntaxTests/dataLocations/libraryInternalFunction/function_argument_location_specifier_test_internal_transient.sol b/test/libsolidity/syntaxTests/dataLocations/libraryInternalFunction/function_argument_location_specifier_test_internal_transient.sol index d66fa7fadd2d..0b53c8b2c238 100644 --- a/test/libsolidity/syntaxTests/dataLocations/libraryInternalFunction/function_argument_location_specifier_test_internal_transient.sol +++ b/test/libsolidity/syntaxTests/dataLocations/libraryInternalFunction/function_argument_location_specifier_test_internal_transient.sol @@ -2,4 +2,4 @@ library test { function f(bytes transient) internal pure {} } // ---- -// TypeError 6651: (30-45): Data location must be "storage", "memory" or "calldata" for parameter in function, but none was given. +// TypeError 6651: (30-45): Data location must be "storage", "memory", "calldata" or "constant" for parameter in function, but none was given. diff --git a/test/libsolidity/syntaxTests/dataLocations/privateFunction/private_function_parameters_location_transient.sol b/test/libsolidity/syntaxTests/dataLocations/privateFunction/private_function_parameters_location_transient.sol index 750aa4fee522..8db58649e6f2 100644 --- a/test/libsolidity/syntaxTests/dataLocations/privateFunction/private_function_parameters_location_transient.sol +++ b/test/libsolidity/syntaxTests/dataLocations/privateFunction/private_function_parameters_location_transient.sol @@ -2,4 +2,4 @@ contract C { function f(uint[] transient) private pure {} } // ---- -// TypeError 6651: (28-44): Data location must be "storage", "memory" or "calldata" for parameter in function, but none was given. +// TypeError 6651: (28-44): Data location must be "storage", "memory", "calldata" or "constant" for parameter in function, but none was given. diff --git a/test/libsolidity/syntaxTests/dataLocations/privateFunction/private_function_parameters_no_data_location.sol b/test/libsolidity/syntaxTests/dataLocations/privateFunction/private_function_parameters_no_data_location.sol index 5af253dfcabc..46c83cbc4d3a 100644 --- a/test/libsolidity/syntaxTests/dataLocations/privateFunction/private_function_parameters_no_data_location.sol +++ b/test/libsolidity/syntaxTests/dataLocations/privateFunction/private_function_parameters_no_data_location.sol @@ -2,4 +2,4 @@ contract C { function f(uint[]) private pure {} } // ---- -// TypeError 6651: (28-34): Data location must be "storage", "memory" or "calldata" for parameter in function, but none was given. +// TypeError 6651: (28-34): Data location must be "storage", "memory", "calldata" or "constant" for parameter in function, but none was given. diff --git a/test/libsolidity/syntaxTests/dataLocations/privateFunction/private_function_return_parameters_location_transient.sol b/test/libsolidity/syntaxTests/dataLocations/privateFunction/private_function_return_parameters_location_transient.sol index d1bf8762480f..a0835b793ea9 100644 --- a/test/libsolidity/syntaxTests/dataLocations/privateFunction/private_function_return_parameters_location_transient.sol +++ b/test/libsolidity/syntaxTests/dataLocations/privateFunction/private_function_return_parameters_location_transient.sol @@ -2,4 +2,4 @@ contract C { function f() private pure returns (uint[] transient) {} } // ---- -// TypeError 6651: (52-68): Data location must be "storage", "memory" or "calldata" for return parameter in function, but none was given. +// TypeError 6651: (52-68): Data location must be "storage", "memory", "calldata" or "constant" for return parameter in function, but none was given. diff --git a/test/libsolidity/syntaxTests/dataLocations/privateFunction/private_function_return_parameters_no_data_location.sol b/test/libsolidity/syntaxTests/dataLocations/privateFunction/private_function_return_parameters_no_data_location.sol index 5026360ebe0b..c277a1c6e20c 100644 --- a/test/libsolidity/syntaxTests/dataLocations/privateFunction/private_function_return_parameters_no_data_location.sol +++ b/test/libsolidity/syntaxTests/dataLocations/privateFunction/private_function_return_parameters_no_data_location.sol @@ -2,4 +2,4 @@ contract C { function f() private pure returns(uint[]) {} } // ---- -// TypeError 6651: (51-57): Data location must be "storage", "memory" or "calldata" for return parameter in function, but none was given. +// TypeError 6651: (51-57): Data location must be "storage", "memory", "calldata" or "constant" for return parameter in function, but none was given. diff --git a/test/libsolidity/syntaxTests/iceRegressionTests/const_struct_with_mapping.sol b/test/libsolidity/syntaxTests/iceRegressionTests/const_struct_with_mapping.sol index 2983b0e71e28..8fea9a1b0576 100644 --- a/test/libsolidity/syntaxTests/iceRegressionTests/const_struct_with_mapping.sol +++ b/test/libsolidity/syntaxTests/iceRegressionTests/const_struct_with_mapping.sol @@ -5,4 +5,4 @@ contract C { S public constant e = 0x1212121212121212121212121212121212121212; } // ---- -// TypeError 9259: (71-135): Only constants of value type and byte array type are implemented. +// TypeError 9259: (71-135): Constants of this type are not supported. Only value types, arrays, structs, and byte/string types without mappings are allowed. diff --git a/test/libsolidity/syntaxTests/modifiers/invalid_parameter_mutability.sol b/test/libsolidity/syntaxTests/modifiers/invalid_parameter_mutability.sol index f23861ebf49d..b99448fa862d 100644 --- a/test/libsolidity/syntaxTests/modifiers/invalid_parameter_mutability.sol +++ b/test/libsolidity/syntaxTests/modifiers/invalid_parameter_mutability.sol @@ -3,5 +3,5 @@ contract A { modifier mod2(uint immutable a) { _; } } // ---- -// DeclarationError 1788: (31-46): The "constant" keyword can only be used for state variables or variables at file level. -// DeclarationError 8297: (73-89): The "immutable" keyword can only be used for state variables. \ No newline at end of file +// TypeError 6651: (31-46): Data location can only be specified for array, struct or mapping types, but "constant" was given. +// DeclarationError 8297: (73-89): The "immutable" keyword can only be used for state variables. diff --git a/test/libsolidity/syntaxTests/modifiers/transient_parameter.sol b/test/libsolidity/syntaxTests/modifiers/transient_parameter.sol index be90ca54dc39..34b4634e63fe 100644 --- a/test/libsolidity/syntaxTests/modifiers/transient_parameter.sol +++ b/test/libsolidity/syntaxTests/modifiers/transient_parameter.sol @@ -2,4 +2,4 @@ contract A { modifier mod2(uint[] transient) { _; } } // ---- -// TypeError 6651: (31-47): Data location must be "storage", "memory" or "calldata" for parameter in function, but none was given. +// TypeError 6651: (31-47): Data location must be "storage", "memory", "calldata" or "constant" for parameter in function, but none was given. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/105_constant_input_parameter.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/105_constant_input_parameter.sol index e2ef8518d2ca..920cc0c03792 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/105_constant_input_parameter.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/105_constant_input_parameter.sol @@ -2,5 +2,4 @@ contract test { function f(uint[] memory constant a) public { } } // ---- -// DeclarationError 1788: (31-55): The "constant" keyword can only be used for state variables or variables at file level. -// TypeError 9259: (31-55): Only constants of value type and byte array type are implemented. +// ParserError 3548: (45-53): Location already specified. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/171_assignment_to_const_array_vars.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/171_assignment_to_const_array_vars.sol index 590cec5a30c8..355e595e994f 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/171_assignment_to_const_array_vars.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/171_assignment_to_const_array_vars.sol @@ -2,4 +2,3 @@ contract C { uint[3] constant x = [uint(1), 2, 3]; } // ---- -// TypeError 9259: (17-53): Only constants of value type and byte array type are implemented. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/173_constant_struct.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/173_constant_struct.sol index 6b5e7a13c281..1a742cbaea19 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/173_constant_struct.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/173_constant_struct.sol @@ -3,4 +3,3 @@ contract C { S constant x = S(5, new uint[](4)); } // ---- -// TypeError 9259: (52-86): Only constants of value type and byte array type are implemented. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/constant_forward_reference_struct.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/constant_forward_reference_struct.sol index d845e735ce93..f69d8ca037f2 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/constant_forward_reference_struct.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/constant_forward_reference_struct.sol @@ -1,4 +1,4 @@ S constant x; struct S { int y; } // ---- -// TypeError 9259: (0-12): Only constants of value type and byte array type are implemented. +// TypeError 4266: (0-12): Uninitialized "constant" variable. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/constant_mapping.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/constant_mapping.sol index 803cdad53507..845739625f66 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/constant_mapping.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/constant_mapping.sol @@ -2,4 +2,4 @@ contract C { mapping(uint => uint) constant x; } // ---- -// TypeError 9259: (17-49): Only constants of value type and byte array type are implemented. +// TypeError 9259: (17-49): Constants of this type are not supported. Only value types, arrays, structs, and byte/string types without mappings are allowed. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/constant_nested_mapping.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/constant_nested_mapping.sol index 2fed9d63114e..62cffdb7cc65 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/constant_nested_mapping.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/constant_nested_mapping.sol @@ -5,4 +5,4 @@ contract C { S public constant c; } // ---- -// TypeError 9259: (71-90): Only constants of value type and byte array type are implemented. +// TypeError 9259: (71-90): Constants of this type are not supported. Only value types, arrays, structs, and byte/string types without mappings are allowed. diff --git a/test/libsolidity/syntaxTests/parsing/invalid_function_parameter_and_return_var_mutability.sol b/test/libsolidity/syntaxTests/parsing/invalid_function_parameter_and_return_var_mutability.sol index 602414192584..fd0d628dc060 100644 --- a/test/libsolidity/syntaxTests/parsing/invalid_function_parameter_and_return_var_mutability.sol +++ b/test/libsolidity/syntaxTests/parsing/invalid_function_parameter_and_return_var_mutability.sol @@ -5,5 +5,5 @@ contract test { // ---- // DeclarationError 8297: (32-48): The "immutable" keyword can only be used for state variables. // DeclarationError 8297: (66-80): The "immutable" keyword can only be used for state variables. -// DeclarationError 1788: (102-117): The "constant" keyword can only be used for state variables or variables at file level. -// DeclarationError 1788: (135-148): The "constant" keyword can only be used for state variables or variables at file level. +// TypeError 6651: (102-117): Data location can only be specified for array, struct or mapping types, but "constant" was given. +// TypeError 6651: (135-148): Data location can only be specified for array, struct or mapping types, but "constant" was given. diff --git a/test/libsolidity/syntaxTests/parsing/location_specifiers_for_params.sol b/test/libsolidity/syntaxTests/parsing/location_specifiers_for_params.sol index c5761a944e14..75891c7b89b5 100644 --- a/test/libsolidity/syntaxTests/parsing/location_specifiers_for_params.sol +++ b/test/libsolidity/syntaxTests/parsing/location_specifiers_for_params.sol @@ -2,5 +2,4 @@ contract Foo { function f(uint[] storage constant x, uint[] memory y) internal { } } // ---- -// DeclarationError 1788: (30-55): The "constant" keyword can only be used for state variables or variables at file level. -// TypeError 9259: (30-55): Only constants of value type and byte array type are implemented. +// ParserError 3548: (45-53): Location already specified. diff --git a/test/libsolidity/syntaxTests/parsing/location_specifiers_for_params_multi.sol b/test/libsolidity/syntaxTests/parsing/location_specifiers_for_params_multi.sol index 8d1985cd6f65..d299cbac375c 100644 --- a/test/libsolidity/syntaxTests/parsing/location_specifiers_for_params_multi.sol +++ b/test/libsolidity/syntaxTests/parsing/location_specifiers_for_params_multi.sol @@ -10,6 +10,7 @@ contract Foo { } // ---- // ParserError 3548: (45-51): Location already specified. +// ParserError 3548: (52-60): Location already specified. // ParserError 3548: (78-86): Location already specified. // ParserError 3548: (134-141): Location already specified. // ParserError 3548: (189-197): Location already specified. diff --git a/test/libsolidity/syntaxTests/string/concat/string_concat_wrong_type_misc_literals_and_expressions.sol b/test/libsolidity/syntaxTests/string/concat/string_concat_wrong_type_misc_literals_and_expressions.sol index f8e62b49e40b..cd0f58afe798 100644 --- a/test/libsolidity/syntaxTests/string/concat/string_concat_wrong_type_misc_literals_and_expressions.sol +++ b/test/libsolidity/syntaxTests/string/concat/string_concat_wrong_type_misc_literals_and_expressions.sol @@ -33,8 +33,8 @@ contract C { } // ---- // TypeError 9640: (698-780): Explicit type conversion not allowed from "bytes32" to "bytes memory". -// TypeError 1227: (698-783): Index range access is only supported for dynamic calldata arrays. -// TypeError 1227: (865-871): Index range access is only supported for dynamic calldata arrays. +// TypeError 1227: (698-783): Index range access is only supported for dynamic calldata or constant arrays. +// TypeError 1227: (865-871): Index range access is only supported for dynamic calldata or constant arrays. // TypeError 9977: (134-139): Invalid type for argument in the string.concat function call. string type is required, but t_bool provided. // TypeError 9977: (153-154): Invalid type for argument in the string.concat function call. string type is required, but t_rational_1_by_1 provided. // TypeError 9977: (168-172): Invalid type for argument in the string.concat function call. string type is required, but t_rational_10000000000_by_1 provided. diff --git a/test/libsolidity/syntaxTests/tryCatch/invalid_returns_vars_and_catch_parameter_mutability.sol b/test/libsolidity/syntaxTests/tryCatch/invalid_returns_vars_and_catch_parameter_mutability.sol index bbc267f8995d..7aab3c9546cf 100644 --- a/test/libsolidity/syntaxTests/tryCatch/invalid_returns_vars_and_catch_parameter_mutability.sol +++ b/test/libsolidity/syntaxTests/tryCatch/invalid_returns_vars_and_catch_parameter_mutability.sol @@ -22,9 +22,5 @@ contract C { } } // ---- -// DeclarationError 1788: (90-105): The "constant" keyword can only be used for state variables or variables at file level. -// DeclarationError 8297: (107-123): The "immutable" keyword can only be used for state variables. -// DeclarationError 8297: (149-174): The "immutable" keyword can only be used for state variables. -// DeclarationError 8297: (269-293): The "immutable" keyword can only be used for state variables. -// DeclarationError 1788: (393-417): The "constant" keyword can only be used for state variables or variables at file level. -// DeclarationError 1788: (512-535): The "constant" keyword can only be used for state variables or variables at file level. +// ParserError 3548: (407-415): Location already specified. +// ParserError 3548: (525-533): Location already specified.