Coverage Report

Created: 2026-06-30 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/solidity/libsolidity/codegen/LValue.h
Line
Count
Source
1
/*
2
  This file is part of solidity.
3
4
  solidity is free software: you can redistribute it and/or modify
5
  it under the terms of the GNU General Public License as published by
6
  the Free Software Foundation, either version 3 of the License, or
7
  (at your option) any later version.
8
9
  solidity is distributed in the hope that it will be useful,
10
  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
  GNU General Public License for more details.
13
14
  You should have received a copy of the GNU General Public License
15
  along with solidity.  If not, see <http://www.gnu.org/licenses/>.
16
*/
17
// SPDX-License-Identifier: GPL-3.0
18
/**
19
 * @author Christian <c@ethdev.com>
20
 * @date 2015
21
 * LValues for use in the expression compiler.
22
 */
23
24
#pragma once
25
26
#include <libsolidity/codegen/ArrayUtils.h>
27
#include <libsolutil/Common.h>
28
#include <liblangutil/SourceLocation.h>
29
#include <libevmasm/Instruction.h>
30
#include <memory>
31
#include <vector>
32
33
namespace solidity::frontend
34
{
35
36
class Declaration;
37
class Type;
38
class TupleType;
39
class ArrayType;
40
class CompilerContext;
41
class VariableDeclaration;
42
43
/**
44
 * Abstract class used to retrieve, delete and store data in lvalues/variables.
45
 */
46
class LValue
47
{
48
protected:
49
  explicit LValue(CompilerContext& _compilerContext, Type const* _dataType = nullptr):
50
340k
    m_context(_compilerContext), m_dataType(_dataType) {}
51
52
public:
53
340k
  virtual ~LValue() = default;
54
  /// @returns the number of stack slots occupied by the lvalue reference
55
0
  virtual unsigned sizeOnStack() const { return 1; }
56
  /// Copies the value of the current lvalue to the top of the stack and, if @a _remove is true,
57
  /// also removes the reference from the stack.
58
  /// @a _location source location of the current expression, used for error reporting.
59
  virtual void retrieveValue(langutil::SourceLocation const& _location, bool _remove = false) const = 0;
60
  /// Moves a value from the stack to the lvalue. Removes the value if @a _move is true.
61
  /// @a _location is the source location of the expression that caused this operation.
62
  /// Stack pre: value [lvalue_ref]
63
  /// Stack post: if !_move: value_of(lvalue_ref)
64
  virtual void storeValue(Type const& _sourceType,
65
    langutil::SourceLocation const& _location = {}, bool _move = false) const = 0;
66
  /// Stores zero in the lvalue. Removes the reference from the stack if @a _removeReference is true.
67
  /// @a _location is the source location of the requested operation
68
  virtual void setToZero(
69
    langutil::SourceLocation const& _location = {},
70
    bool _removeReference = true
71
  ) const = 0;
72
73
protected:
74
  CompilerContext& m_context;
75
  Type const* m_dataType;
76
};
77
78
/**
79
 * Local variable that is completely stored on the stack.
80
 */
81
class StackVariable: public LValue
82
{
83
public:
84
  StackVariable(CompilerContext& _compilerContext, VariableDeclaration const& _declaration);
85
86
6.72k
  unsigned sizeOnStack() const override { return 0; }
87
  void retrieveValue(langutil::SourceLocation const& _location, bool _remove = false) const override;
88
  void storeValue(
89
    Type const& _sourceType,
90
    langutil::SourceLocation const& _location = {},
91
    bool _move = false
92
  ) const override;
93
  void setToZero(
94
    langutil::SourceLocation const& _location = {},
95
    bool _removeReference = true
96
  ) const override;
97
98
private:
99
  /// Base stack offset (@see CompilerContext::baseStackOffsetOfVariable) of the local variable.
100
  unsigned m_baseStackOffset;
101
  /// Number of stack elements occupied by the value (not the reference).
102
  unsigned m_size;
103
};
104
105
/**
106
 * Reference to some item in memory.
107
 */
108
class MemoryItem: public LValue
109
{
110
public:
111
  MemoryItem(CompilerContext& _compilerContext, Type const& _type, bool _padded = true);
112
56
  unsigned sizeOnStack() const override { return 1; }
113
  void retrieveValue(langutil::SourceLocation const& _location, bool _remove = false) const override;
114
  void storeValue(
115
    Type const& _sourceType,
116
    langutil::SourceLocation const& _location = {},
117
    bool _move = false
118
  ) const override;
119
  void setToZero(
120
    langutil::SourceLocation const& _location = {},
121
    bool _removeReference = true
122
  ) const override;
123
private:
124
  /// Special flag to deal with byte array elements.
125
  bool m_padded = false;
126
};
127
128
/**
129
 * Reference to an immutable variable. During contract creation this refers to a location in memory. At the
130
 * end of contract creation the values from these memory locations are copied into all occurrences of the immutable
131
 * variable in the runtime code.
132
 */
133
class ImmutableItem: public LValue
134
{
135
public:
136
  ImmutableItem(CompilerContext& _compilerContext, VariableDeclaration const& _variable);
137
102
  unsigned sizeOnStack() const override { return 0; }
138
  void retrieveValue(langutil::SourceLocation const& _location, bool _remove = false) const override;
139
  void storeValue(
140
    Type const& _sourceType,
141
    langutil::SourceLocation const& _location = {},
142
    bool _move = false
143
  ) const override;
144
  void setToZero(
145
    langutil::SourceLocation const& _location = {},
146
    bool _removeReference = true
147
  ) const override;
148
private:
149
  VariableDeclaration const& m_variable;
150
};
151
152
/**
153
 * Reference to some item in storage/transient storage. On the stack this is <storage key> <offset_inside_value>,
154
 * where 0 <= offset_inside_value < 32 and an offset of i means that the value is multiplied
155
 * by 2**i before storing it.
156
 */
157
template<bool IsTransient>
158
class GenericStorageItem : public LValue
159
{
160
public:
161
  /// Constructs the LValue and pushes the location of @a _declaration onto the stack.
162
  GenericStorageItem(CompilerContext& _compilerContext, VariableDeclaration const& _declaration);
163
  /// Constructs the LValue and assumes that the storage reference is already on the stack.
164
  GenericStorageItem(CompilerContext& _compilerContext, Type const& _type);
165
1.05k
  unsigned sizeOnStack() const override { return 2; }
solidity::frontend::GenericStorageItem<false>::sizeOnStack() const
Line
Count
Source
165
1.05k
  unsigned sizeOnStack() const override { return 2; }
Unexecuted instantiation: solidity::frontend::GenericStorageItem<true>::sizeOnStack() const
166
  void retrieveValue(langutil::SourceLocation const& _location, bool _remove = false) const override;
167
  void storeValue(
168
    Type const& _sourceType,
169
    langutil::SourceLocation const& _location = {},
170
    bool _move = false
171
  ) const override;
172
  void setToZero(
173
    langutil::SourceLocation const& _location = {},
174
    bool _removeReference = true
175
  ) const override;
176
private:
177
  static constexpr evmasm::Instruction s_storeInstruction = IsTransient ? evmasm::Instruction::TSTORE : evmasm::Instruction::SSTORE;
178
  static constexpr evmasm::Instruction s_loadInstruction = IsTransient ? evmasm::Instruction::TLOAD : evmasm::Instruction::SLOAD;
179
};
180
extern template class GenericStorageItem<false>;
181
extern template class GenericStorageItem<true>;
182
using StorageItem = GenericStorageItem<false>;
183
using TransientStorageItem = GenericStorageItem<true>;
184
185
/**
186
 * Reference to a single byte inside a storage byte array.
187
 * Stack: <storage_ref> <byte_number>
188
 */
189
class StorageByteArrayElement: public LValue
190
{
191
public:
192
  /// Constructs the LValue and assumes that the storage reference is already on the stack.
193
  StorageByteArrayElement(CompilerContext& _compilerContext);
194
170
  unsigned sizeOnStack() const override { return 2; }
195
  void retrieveValue(langutil::SourceLocation const& _location, bool _remove = false) const override;
196
  void storeValue(
197
    Type const& _sourceType,
198
    langutil::SourceLocation const& _location = {},
199
    bool _move = false
200
  ) const override;
201
  void setToZero(
202
    langutil::SourceLocation const& _location = {},
203
    bool _removeReference = true
204
  ) const override;
205
};
206
207
/**
208
 * Tuple object that can itself hold several LValues.
209
 */
210
class TupleObject: public LValue
211
{
212
public:
213
  /// Constructs the LValue assuming that the other LValues are present on the stack.
214
  /// Empty unique_ptrs are possible if e.g. some values should be ignored during assignment.
215
  TupleObject(CompilerContext& _compilerContext, std::vector<std::unique_ptr<LValue>>&& _lvalues);
216
  unsigned sizeOnStack() const override;
217
  void retrieveValue(langutil::SourceLocation const& _location, bool _remove = false) const override;
218
  void storeValue(
219
    Type const& _sourceType,
220
    langutil::SourceLocation const& _location = {},
221
    bool _move = false
222
  ) const override;
223
  void setToZero(
224
    langutil::SourceLocation const& _location = {},
225
    bool _removeReference = true
226
  ) const override;
227
228
private:
229
  std::vector<std::unique_ptr<LValue>> m_lvalues;
230
};
231
232
}