Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
Amxx committed Mar 21, 2024
1 parent afda698 commit 890cbef
Show file tree
Hide file tree
Showing 24 changed files with 696 additions and 375 deletions.
3 changes: 2 additions & 1 deletion liblangutil/Token.h
Expand Up @@ -182,6 +182,7 @@ namespace solidity::langutil
K(Return, "return", 0) \
K(Returns, "returns", 0) \
K(Storage, "storage", 0) \
K(Transient, "transient", 0) \
K(CallData, "calldata", 0) \
K(Struct, "struct", 0) \
K(Throw, "throw", 0) \
Expand Down Expand Up @@ -316,7 +317,7 @@ namespace TokenTraits
constexpr bool isShiftOp(Token op) { return (Token::SHL <= op) && (op <= Token::SHR); }
constexpr bool isVariableVisibilitySpecifier(Token op) { return op == Token::Public || op == Token::Private || op == Token::Internal; }
constexpr bool isVisibilitySpecifier(Token op) { return isVariableVisibilitySpecifier(op) || op == Token::External; }
constexpr bool isLocationSpecifier(Token op) { return op == Token::Memory || op == Token::Storage || op == Token::CallData; }
constexpr bool isLocationSpecifier(Token op) { return op == Token::Memory || op == Token::Storage || op == Token::Transient || op == Token::CallData; }

constexpr bool isStateMutabilitySpecifier(Token op)
{
Expand Down
2 changes: 2 additions & 0 deletions libsolidity/CMakeLists.txt
Expand Up @@ -82,6 +82,8 @@ set(sources
codegen/ContractCompiler.h
codegen/ExpressionCompiler.cpp
codegen/ExpressionCompiler.h
codegen/InstructionsUtils.cpp
codegen/InstructionsUtils.h
codegen/LValue.cpp
codegen/LValue.h
codegen/MultiUseYulFunctionCollector.h
Expand Down
17 changes: 15 additions & 2 deletions libsolidity/analysis/DeclarationTypeChecker.cpp
Expand Up @@ -407,6 +407,7 @@ void DeclarationTypeChecker::endVisit(VariableDeclaration const& _variable)
{
case Location::Memory: return "\"memory\"";
case Location::Storage: return "\"storage\"";
case Location::TransientStorage: return "\"transient\"";
case Location::CallData: return "\"calldata\"";
case Location::Unspecified: return "none";
}
Expand Down Expand Up @@ -456,8 +457,17 @@ void DeclarationTypeChecker::endVisit(VariableDeclaration const& _variable)
}
else if (_variable.isStateVariable())
{
solAssert(varLoc == Location::Unspecified, "");
typeLoc = (_variable.isConstant() || _variable.immutable()) ? DataLocation::Memory : DataLocation::Storage;
switch(varLoc)
{
case Location::Unspecified:
typeLoc = (_variable.isConstant() || _variable.immutable()) ? DataLocation::Memory : DataLocation::Storage;
break;
case Location::TransientStorage:
typeLoc = DataLocation::TransientStorage;
break;
default:
solAssert(false, "");
}
}
else if (
dynamic_cast<StructDefinition const*>(_variable.scope()) ||
Expand All @@ -474,6 +484,9 @@ void DeclarationTypeChecker::endVisit(VariableDeclaration const& _variable)
case Location::Storage:
typeLoc = DataLocation::Storage;
break;
case Location::TransientStorage:
typeLoc = DataLocation::TransientStorage;
break;
case Location::CallData:
typeLoc = DataLocation::CallData;
break;
Expand Down
21 changes: 10 additions & 11 deletions libsolidity/analysis/TypeChecker.cpp
Expand Up @@ -126,10 +126,10 @@ void TypeChecker::checkDoubleStorageAssignment(Assignment const& _assignment)
{
if (ReferenceType const* ref = dynamic_cast<ReferenceType const*>(componentType))
{
if (ref && ref->dataStoredIn(DataLocation::Storage) && !ref->isPointer())
if (ref && ref->dataStoredInAnyOf({ DataLocation::Storage, DataLocation::TransientStorage }) && !ref->isPointer())
{
toStorageCopies++;
if (_rhs.components()[index]->dataStoredIn(DataLocation::Storage))
if (_rhs.components()[index]->dataStoredInAnyOf({ DataLocation::Storage, DataLocation::TransientStorage }))
storageToStorageCopies++;
}
}
Expand All @@ -143,7 +143,7 @@ void TypeChecker::checkDoubleStorageAssignment(Assignment const& _assignment)
if (callType.kind() == FunctionType::Kind::ArrayPush)
{
ArrayType const& arrayType = dynamic_cast<ArrayType const&>(*callType.selfType());
if (arrayType.isByteArray() && arrayType.dataStoredIn(DataLocation::Storage))
if (arrayType.isByteArray() && arrayType.dataStoredInAnyOf({ DataLocation::Storage, DataLocation::TransientStorage }))
{
++storageByteAccesses;
++storageByteArrayPushes;
Expand All @@ -153,7 +153,7 @@ void TypeChecker::checkDoubleStorageAssignment(Assignment const& _assignment)
else if (IndexAccess const* indexAccess = dynamic_cast<IndexAccess const*>(resolveOuterUnaryTuples(lhsResolved->components().at(index).get())))
{
if (ArrayType const* arrayType = dynamic_cast<ArrayType const*>(type(indexAccess->baseExpression())))
if (arrayType->isByteArray() && arrayType->dataStoredIn(DataLocation::Storage))
if (arrayType->isByteArray() && arrayType->dataStoredInAnyOf({ DataLocation::Storage, DataLocation::TransientStorage }))
++storageByteAccesses;
}
}
Expand Down Expand Up @@ -260,8 +260,7 @@ TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall c
if (actualType->category() == Type::Category::Address)
actualType = TypeProvider::payableAddress();
solAssert(
!actualType->dataStoredIn(DataLocation::CallData) &&
!actualType->dataStoredIn(DataLocation::Storage),
!actualType->dataStoredInAnyOf({ DataLocation::CallData, DataLocation::Storage, DataLocation::TransientStorage }),
""
);
if (!actualType->fullEncodingType(false, _abiEncoderV2, false))
Expand Down Expand Up @@ -674,7 +673,7 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
BoolResult result = referenceType->validForLocation(referenceType->location());
if (result)
{
bool isLibraryStorageParameter = (_variable.isLibraryFunctionParameter() && referenceType->location() == DataLocation::Storage);
bool isLibraryStorageParameter = (_variable.isLibraryFunctionParameter() && referenceType->dataStoredInAnyOf({ DataLocation::Storage, DataLocation::TransientStorage }));
// We skip the calldata check for abstract contract constructors.
bool isAbstractConstructorParam = _variable.isConstructorParameter() && m_currentContract && m_currentContract->abstract();
bool callDataCheckRequired =
Expand Down Expand Up @@ -921,7 +920,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
{
std::string const& suffix = identifierInfo.suffix;
solAssert((std::set<std::string>{"offset", "slot", "length", "selector", "address"}).count(suffix), "");
if (!var->isConstant() && (var->isStateVariable() || var->type()->dataStoredIn(DataLocation::Storage)))
if (!var->isConstant() && (var->isStateVariable() || var->type()->dataStoredInAnyOf({ DataLocation::Storage, DataLocation::TransientStorage })))
{
if (suffix != "slot" && suffix != "offset")
{
Expand Down Expand Up @@ -981,7 +980,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
);
return false;
}
else if (var->type()->dataStoredIn(DataLocation::Storage))
else if (var->type()->dataStoredInAnyOf({ DataLocation::Storage, DataLocation::TransientStorage }))
{
m_errorReporter.typeError(9068_error, nativeLocationOf(_identifier), "You have to use the \".slot\" or \".offset\" suffix to access storage reference variables.");
return false;
Expand Down Expand Up @@ -1987,13 +1986,13 @@ Type const* TypeChecker::typeCheckTypeConversionAndRetrieveReturnType(
{
if (auto resultArrayType = dynamic_cast<ArrayType const*>(resultType))
solAssert(
argArrayType->location() != DataLocation::Storage ||
!argArrayType->dataStoredInAnyOf({ DataLocation::CallData, DataLocation::Storage, DataLocation::TransientStorage }) ||
(
(
resultArrayType->isPointer() ||
(argArrayType->isByteArrayOrString() && resultArrayType->isByteArrayOrString())
) &&
resultArrayType->location() == DataLocation::Storage
resultArrayType->location() == argArrayType->location()
),
"Invalid explicit conversion to storage type."
);
Expand Down
8 changes: 4 additions & 4 deletions libsolidity/analysis/ViewPureChecker.cpp
Expand Up @@ -415,14 +415,14 @@ void ViewPureChecker::endVisit(MemberAccess const& _memberAccess)
}
case Type::Category::Struct:
{
if (_memberAccess.expression().annotation().type->dataStoredIn(DataLocation::Storage))
if (_memberAccess.expression().annotation().type->dataStoredInAnyOf({ DataLocation::Storage, DataLocation::TransientStorage }))
mutability = writes ? StateMutability::NonPayable : StateMutability::View;
break;
}
case Type::Category::Array:
{
auto const& type = dynamic_cast<ArrayType const&>(*_memberAccess.expression().annotation().type);
if (member == "length" && type.isDynamicallySized() && type.dataStoredIn(DataLocation::Storage))
if (member == "length" && type.isDynamicallySized() && type.dataStoredInAnyOf({ DataLocation::Storage, DataLocation::TransientStorage }))
mutability = StateMutability::View;
break;
}
Expand All @@ -446,15 +446,15 @@ void ViewPureChecker::endVisit(IndexAccess const& _indexAccess)
else
{
bool writes = _indexAccess.annotation().willBeWrittenTo;
if (_indexAccess.baseExpression().annotation().type->dataStoredIn(DataLocation::Storage))
if (_indexAccess.baseExpression().annotation().type->dataStoredInAnyOf({ DataLocation::Storage, DataLocation::TransientStorage }))
reportMutability(writes ? StateMutability::NonPayable : StateMutability::View, _indexAccess.location());
}
}

void ViewPureChecker::endVisit(IndexRangeAccess const& _indexRangeAccess)
{
bool writes = _indexRangeAccess.annotation().willBeWrittenTo;
if (_indexRangeAccess.baseExpression().annotation().type->dataStoredIn(DataLocation::Storage))
if (_indexRangeAccess.baseExpression().annotation().type->dataStoredInAnyOf({ DataLocation::Storage, DataLocation::TransientStorage }))
reportMutability(writes ? StateMutability::NonPayable : StateMutability::View, _indexRangeAccess.location());
}

Expand Down
8 changes: 5 additions & 3 deletions libsolidity/ast/AST.cpp
Expand Up @@ -816,7 +816,9 @@ std::set<VariableDeclaration::Location> VariableDeclaration::allowedDataLocation
{
using Location = VariableDeclaration::Location;

if (!hasReferenceOrMappingType() || isStateVariable() || isEventOrErrorParameter())
if (isStateVariable())
return std::set<Location>{ Location::Unspecified, Location::TransientStorage };
else if (!hasReferenceOrMappingType() || isEventOrErrorParameter())
return std::set<Location>{ Location::Unspecified };
else if (isCallableOrCatchParameter())
{
Expand All @@ -826,15 +828,15 @@ std::set<VariableDeclaration::Location> VariableDeclaration::allowedDataLocation
isInternalCallableParameter() ||
isLibraryFunctionParameter()
)
locations.insert(Location::Storage);
locations.insert({ Location::Storage, Location::TransientStorage });
if (!isTryCatchParameter() && !isConstructorParameter())
locations.insert(Location::CallData);

return locations;
}
else if (isLocalVariable())
// Further restrictions will be imposed later on.
return std::set<Location>{ Location::Memory, Location::Storage, Location::CallData };
return std::set<Location>{ Location::CallData, Location::Memory, Location::Storage, Location::TransientStorage };
else
// Struct members etc.
return std::set<Location>{ Location::Unspecified };
Expand Down
6 changes: 4 additions & 2 deletions libsolidity/ast/AST.h
Expand Up @@ -1053,13 +1053,14 @@ class FunctionDefinition: public CallableDeclaration, public StructurallyDocumen
class VariableDeclaration: public Declaration, public StructurallyDocumented
{
public:
enum Location { Unspecified, Storage, Memory, CallData };
enum class Mutability { Mutable, Immutable, Constant };
enum Location { Unspecified, Storage, TransientStorage, Memory, CallData };
enum class Mutability { Mutable, Transient, Immutable, Constant };
static std::string mutabilityToString(Mutability _mutability)
{
switch (_mutability)
{
case Mutability::Mutable: return "mutable";
case Mutability::Transient: return "transient";
case Mutability::Immutable: return "immutable";
case Mutability::Constant: return "constant";
}
Expand Down Expand Up @@ -1140,6 +1141,7 @@ class VariableDeclaration: public Declaration, public StructurallyDocumented
Mutability mutability() const { return m_mutability; }
bool isConstant() const { return m_mutability == Mutability::Constant; }
bool immutable() const { return m_mutability == Mutability::Immutable; }
bool transient() const { return m_mutability == Mutability::Transient; }
ASTPointer<OverrideSpecifier> const& overrides() const { return m_overrides; }
Location referenceLocation() const { return m_location; }
/// @returns a set of allowed storage locations for the variable.
Expand Down
10 changes: 6 additions & 4 deletions libsolidity/ast/ASTJsonExporter.cpp
Expand Up @@ -1053,12 +1053,14 @@ std::string ASTJsonExporter::location(VariableDeclaration::Location _location)
{
case VariableDeclaration::Location::Unspecified:
return "default";
case VariableDeclaration::Location::Storage:
return "storage";
case VariableDeclaration::Location::Memory:
return "memory";
case VariableDeclaration::Location::CallData:
return "calldata";
case VariableDeclaration::Location::Memory:
return "memory";
case VariableDeclaration::Location::Storage:
return "storage";
case VariableDeclaration::Location::TransientStorage:
return "transient";
}
// To make the compiler happy
return {};
Expand Down

0 comments on commit 890cbef

Please sign in to comment.