• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

rieske / trans / 28461496314

30 Jun 2026 04:55PM UTC coverage: 90.13% (-0.4%) from 90.53%
28461496314

Pull #44

github

rieske
Support multi-word struct pass/return and expand struct tests

Pass multi-word structs on the stack with correct SP adjustments when
pushing words; copy aggregates word-wise on assign. Return up to two
words in RAX/RDX and restore them on retrieve. Use the real function
return type from declaration specs (fixes void calls and struct
returns). Expand StructsTest for by-value/by-address args in different
positions, mutation, return by value/pointer, assign, and chains.
Pull Request #44: Implement C structs with member access

329 of 404 new or added lines in 13 files covered. (81.44%)

5415 of 6008 relevant lines covered (90.13%)

240586.41 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.66
/src/types/Type.cpp
1
#include "Type.h"
2

3
#include <stdexcept>
4
#include <algorithm>
5
#include <sstream>
6

7
namespace type {
8

9
static const int POINTER_SIZE {8};
10

11
Type voidType() {
56✔
12
    return Type{{}};
56✔
13
}
14

15
Type primitive(const Primitive& primitive, const std::vector<Qualifier>& qualifiers) {
5,026✔
16
    return Type{primitive, qualifiers};
5,026✔
17
}
18

19
Type pointer(const Type& pointsTo, const std::vector<Qualifier>& qualifiers) {
1,458✔
20
    auto p = Type{pointsTo};
1,458✔
21
    p._indirection = pointsTo._indirection+1;
1,458✔
22
    return p;
1,458✔
23
}
24

25
Type function(const Type& returnType, const std::vector<Type>& arguments) {
2,284✔
26
    return Type{returnType, arguments};
2,284✔
27
}
28

29
Type signedCharacter(const std::vector<Qualifier>& qualifiers) {
856✔
30
    return primitive(Primitive::signedCharacter(), qualifiers);
856✔
31
}
32
Type unsignedCharacter(const std::vector<Qualifier>& qualifiers) {
4✔
33
    return primitive(Primitive::unsignedCharacter(), qualifiers);
4✔
34
}
35

36
Type signedInteger(const std::vector<Qualifier>& qualifiers) {
4,150✔
37
    return primitive(Primitive::signedInteger(), qualifiers);
4,150✔
38
}
39

40
Type unsignedInteger(const std::vector<Qualifier>& qualifiers) {
4✔
41
    return primitive(Primitive::unsignedInteger(), qualifiers);
4✔
42
}
43

44
Type signedLong(const std::vector<Qualifier>& qualifiers) {
2✔
45
    return primitive(Primitive::signedLong(), qualifiers);
2✔
46
}
47

48
Type unsignedLong(const std::vector<Qualifier>& qualifiers) {
4✔
49
    return primitive(Primitive::unsignedLong(), qualifiers);
4✔
50
}
51

52
Type floating(const std::vector<Qualifier>& qualifiers) {
2✔
53
    return primitive(Primitive::floating(), qualifiers);
2✔
54
}
55

56
Type doubleFloating(const std::vector<Qualifier>& qualifiers) {
2✔
57
    return primitive(Primitive::doubleFloating(), qualifiers);
2✔
58
}
59

60
Type longDoubleFloating(const std::vector<Qualifier>& qualifiers) {
2✔
61
    return primitive(Primitive::longDoubleFloating(), qualifiers);
2✔
62
}
63

64
Type::Type(std::vector<Qualifier> qualifiers) {
5,116✔
65
    for (const auto& qualifier: qualifiers) {
5,124✔
66
        switch(qualifier) {
8✔
67
            case Qualifier::CONST:
4✔
68
                this->_const = true;
4✔
69
                break;
4✔
70
            case Qualifier::VOLATILE:
4✔
71
                this->_volatile = true;
4✔
72
                break;
4✔
73
            default:
×
74
                throw std::invalid_argument{"Unsupported type qualifier"};
×
75
        }
76
    }
77
}
5,116✔
78

79
Type::Type(const Primitive& primitive, std::vector<Qualifier> qualifiers):
5,026✔
80
    Type{qualifiers}
5,026✔
81
{
82
    _primitive = primitive;
5,026✔
83
}
5,026✔
84

85
Type::Type(const Type& returnType, const std::vector<Type>& arguments) {
2,284✔
86
    std::vector<std::unique_ptr<Type>> args;
2,284✔
87
    for (const auto& arg : arguments) {
2,684✔
88
        args.push_back(std::make_unique<Type>(arg));
400✔
89
    }
90
    _function = Function{std::make_unique<Type>(returnType), std::move(args)};
2,284✔
91
}
2,284✔
92

93
int Type::getSize() const {
5,350✔
94
    if (isPointer()) {
5,350✔
95
        return POINTER_SIZE;
1,544✔
96
    }
97
    if (isPrimitive()) {
3,806✔
98
        return _primitive->getSize();
3,738✔
99
    }
100
    if (isStructure()) {
68✔
101
        return _structure->size;
58✔
102
    }
103
    return _size;
10✔
104
}
105

106
bool Type::canAssignFrom(const Type& other) const {
1,136✔
107
    // TODO:
108
    return true;
1,136✔
109
}
110

111
bool Type::isVoid() const {
11,036✔
112
    return !isPrimitive() && !isFunction() && !isPointer() && !isStructure();
11,036✔
113
}
114

115
bool Type::isPrimitive() const {
21,522✔
116
    return _primitive.has_value();
21,522✔
117
}
118

119
Primitive Type::getPrimitive() const {
60✔
120
    return *_primitive;
60✔
121
}
122

123
bool Type::isConst() const {
6,516✔
124
    return _const;
6,516✔
125
}
126

127
bool Type::isVolatile() const {
6,516✔
128
    return _volatile;
6,516✔
129
}
130

131
bool Type::isPointer() const {
15,828✔
132
    return _indirection;
15,828✔
133
}
134

135
bool Type::isFunction() const {
606✔
136
    return _function.has_value();
606✔
137
}
138

139
Function Type::getFunction() const {
1,370✔
140
    return *_function;
1,370✔
141
}
142

143

144
Type Type::dereference() const {
1,702✔
145
    if (!isPointer()) {
1,702✔
146
        throw std::domain_error{"can not dereference non-pointer type"};
×
147
    }
148
    Type pointsTo = Type{*this};
1,702✔
149
    --pointsTo._indirection;
1,702✔
150
    return pointsTo;
1,702✔
151
}
152

153
std::string Type::to_string() const {
8,254✔
154
    if (isVoid()) {
8,254✔
155
        return "void";
92✔
156
    }
157
    if (isPointer()) {
8,208✔
158
        return dereference().to_string() + "*";
1,574✔
159
    }
160
    if (isPrimitive()) {
6,634✔
161
        std::stringstream str;
6,488✔
162
        if (isConst()) {
6,488✔
163
            str << "const ";
4✔
164
        }
165
        if (isVolatile()) {
6,488✔
166
            str << "volatile ";
4✔
167
        }
168
        str << _primitive->to_string();
6,488✔
169
        return str.str();
6,488✔
170
    }
6,488✔
171
    if (isFunction()) {
146✔
172
        return _function->to_string();
8✔
173
    }
174
    return "unknown type";
276✔
175
}
176

177

178
Type::Member::Member(std::string n, Type t, int off) :
70✔
179
        name { std::move(n) },
70✔
180
        type { std::make_unique<Type>(std::move(t)) },
70✔
181
        offsetBytes { off }
70✔
182
{
183
}
70✔
184

NEW
185
Type::Member::Member(const Member& other) :
×
NEW
186
        name { other.name },
×
NEW
187
        type { other.type ? std::make_unique<Type>(*other.type) : nullptr },
×
NEW
188
        offsetBytes { other.offsetBytes }
×
189
{
NEW
190
}
×
191

NEW
192
Type::Member& Type::Member::operator=(const Member& other) {
×
NEW
193
    if (this != &other) {
×
NEW
194
        name = other.name;
×
NEW
195
        type = other.type ? std::make_unique<Type>(*other.type) : nullptr;
×
NEW
196
        offsetBytes = other.offsetBytes;
×
197
    }
NEW
198
    return *this;
×
199
}
200

201
namespace {
202
constexpr int WORD_ALIGN = 8;
203

204
int alignUp(int value, int alignment) {
174✔
205
    return (value + alignment - 1) / alignment * alignment;
174✔
206
}
207

208
int memberStride(const Type& memberType) {
70✔
209
    int size = memberType.getSize();
70✔
210
    if (size < 1) {
70✔
NEW
211
        size = 1;
×
212
    }
213
    // Pointers and incomplete structs still get a full word as a member slot.
214
    return alignUp(size, WORD_ALIGN);
70✔
215
}
216

217
void layoutMembers(Type::StructBody& body, std::vector<std::pair<std::string, Type>> members) {
34✔
218
    body.members.clear();
34✔
219
    int offset = 0;
34✔
220
    for (auto& entry : members) {
104✔
221
        offset = alignUp(offset, WORD_ALIGN);
70✔
222
        body.members.emplace_back(entry.first, entry.second, offset);
70✔
223
        offset += memberStride(entry.second);
70✔
224
    }
225
    body.size = alignUp(offset, WORD_ALIGN);
34✔
226
    body.complete = true;
34✔
227
}
34✔
228
} // namespace
229

230
Type incompleteStructure() {
34✔
231
    Type result { std::vector<Qualifier> {} };
34✔
232
    result._structure = std::make_shared<Type::StructBody>();
34✔
233
    result._structure->complete = false;
34✔
234
    result._structure->size = 0;
34✔
235
    result._size = 0;
34✔
236
    return result;
34✔
NEW
237
}
×
238

NEW
239
Type structure(std::vector<std::pair<std::string, Type>> members) {
×
NEW
240
    Type result = incompleteStructure();
×
NEW
241
    completeStructure(result, std::move(members));
×
NEW
242
    return result;
×
NEW
243
}
×
244

245
void completeStructure(Type& structType, std::vector<std::pair<std::string, Type>> members) {
34✔
246
    if (!structType._structure) {
34✔
NEW
247
        structType._structure = std::make_shared<Type::StructBody>();
×
248
    }
249
    layoutMembers(*structType._structure, std::move(members));
34✔
250
    structType._size = structType._structure->size;
34✔
251
}
34✔
252

253
bool Type::isStructure() const {
576✔
254
    return _structure != nullptr;
576✔
255
}
256

NEW
257
bool Type::isCompleteStructure() const {
×
NEW
258
    return _structure && _structure->complete;
×
259
}
260

NEW
261
const std::vector<Type::Member>& Type::getStructMembers() const {
×
NEW
262
    return _structure->members;
×
263
}
264

265
bool Type::memberOffset(const std::string& memberName, int& offsetBytes) const {
170✔
266
    if (!_structure) {
170✔
NEW
267
        return false;
×
268
    }
269
    for (const auto& member : _structure->members) {
262✔
270
        if (member.name == memberName) {
262✔
271
            offsetBytes = member.offsetBytes;
170✔
272
            return true;
170✔
273
        }
274
    }
NEW
275
    return false;
×
276
}
277

278
bool Type::memberType(const std::string& memberName, Type& outType) const {
170✔
279
    if (!_structure) {
170✔
NEW
280
        return false;
×
281
    }
282
    for (const auto& member : _structure->members) {
262✔
283
        if (member.name == memberName) {
262✔
284
            outType = *member.type;
170✔
285
            return true;
170✔
286
        }
287
    }
NEW
288
    return false;
×
289
}
290

291
} // namespace type
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc