• 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

87.72
/src/semantic_analyzer/SemanticAnalysisVisitor.cpp
1
#include "SemanticAnalysisVisitor.h"
2

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

6
#include "translation_unit/Context.h"
7
#include "types/Type.h"
8
#include "util/Logger.h"
9
#include "util/LogManager.h"
10

11
namespace semantic_analyzer {
12

13
static const translation_unit::Context EXTERNAL_CONTEXT {"external", 0};
14

15
static Logger& err = LogManager::getErrorLogger();
16

17
SemanticAnalysisVisitor::SemanticAnalysisVisitor() {
410✔
18
    type::Type functionType = type::function(type::signedInteger());
410✔
19
    symbolTable.insertFunction("printf", functionType.getFunction(), EXTERNAL_CONTEXT);
1,230✔
20
    symbolTable.insertFunction("scanf", functionType.getFunction(), EXTERNAL_CONTEXT);
1,230✔
21
}
410✔
22

23
SemanticAnalysisVisitor::~SemanticAnalysisVisitor() {
410✔
24
}
410✔
25

26
void SemanticAnalysisVisitor::printSymbolTable() const {
398✔
27
    symbolTable.printTable();
398✔
28
}
398✔
29

30
void SemanticAnalysisVisitor::visit(ast::DeclarationSpecifiers& declarationSpecifiers) {
1,292✔
31
    // FIXME: this would look so much better
32
    /*for (std::string error : declarationSpecifiers.getSemanticErrors()) {
33
     semanticError(error, globalContext);
34
     }*/
35
    if (declarationSpecifiers.getStorageSpecifiers().size() > 1) {
1,292✔
36
        semanticError("multiple storage classes in declaration specifiers",
×
37
                declarationSpecifiers.getStorageSpecifiers().at(1).getContext());
×
38
    }
39
}
1,292✔
40

41
void SemanticAnalysisVisitor::visit(ast::Declaration& declaration) {
574✔
42
    declaration.visitChildren(*this);
574✔
43

44
    auto baseType = declaration.getDeclarationSpecifiers().getTypeSpecifiers().at(0).getType();
574✔
45
    for (const auto& declarator : declaration.getDeclarators()) {
1,236✔
46
        auto type = declarator->getFundamentalType(baseType);
662✔
47
        if (type.isVoid()) {
662✔
48
            semanticError("variable `" + declarator->getName() + "` declared void", declarator->getContext());
2✔
49
        } else if (symbolTable.isAtFileScope() && symbolTable.hasFunction(declarator->getName())) {
660✔
50
            semanticError("symbol `" + declarator->getName() + "` declaration conflicts with function of the same name",
×
51
                    declarator->getContext());
×
52
        } else if (symbolTable.insertSymbol(declarator->getName(), type, declarator->getContext())) {
660✔
53
            declarator->setHolder(symbolTable.lookup(declarator->getName()));
658✔
54
            // TODO: type check initializers
55
            if (declarator->hasInitializer() && symbolTable.isAtFileScope()) {
658✔
56
                long initValue = 0;
28✔
57
                if (declarator->getInitializer()->evaluateConstant(initValue)) {
28✔
58
                    symbolTable.setGlobalInitializer(declarator->getName(), initValue);
28✔
59
                } else {
60
                    semanticError("global initializer is not a constant expression", declarator->getContext());
×
61
                }
62
            }
63
        } else {
64
            semanticError(
2✔
65
                    "symbol `" + declarator->getName() +
4✔
66
                            "` declaration conflicts with previous declaration on " +
4✔
67
                            to_string(symbolTable.lookup(declarator->getName()).getContext()),
4✔
68
                    declarator->getContext());
4✔
69
        }
70
    }
662✔
71
}
574✔
72

73
void SemanticAnalysisVisitor::visit(ast::Declarator& declarator) {
1,380✔
74
    declarator.visitChildren(*this);
1,380✔
75
}
1,380✔
76

77
void SemanticAnalysisVisitor::visit(ast::InitializedDeclarator& declarator) {
662✔
78
    declarator.visitChildren(*this);
662✔
79
}
662✔
80

81
void SemanticAnalysisVisitor::visit(ast::ArrayAccess& arrayAccess) {
×
82
    arrayAccess.visitLeftOperand(*this);
×
83
    arrayAccess.visitRightOperand(*this);
×
84

85
    auto type = arrayAccess.leftOperandType();
×
86
    if (type.isPointer()) {
×
87
        arrayAccess.setLvalue(symbolTable.createTemporarySymbol(type.dereference()));
×
88
        arrayAccess.setResultSymbol(symbolTable.createTemporarySymbol(type.dereference()));
×
89
    } else {
90
        semanticError("invalid type for operator[]\n", arrayAccess.getContext());
×
91
    }
92
}
×
93

94
void SemanticAnalysisVisitor::visit(ast::FunctionCall& functionCall) {
960✔
95
    functionCall.visitOperand(*this);
960✔
96
    functionCall.visitArguments(*this);
960✔
97

98
    auto functionSymbol = symbolTable.findFunction(functionCall.operandSymbol()->getName());
960✔
99

100
    functionCall.setSymbol(functionSymbol);
960✔
101

102
    auto& arguments = functionCall.getArgumentList();
960✔
103
    if (arguments.size() == functionSymbol.argumentCount()) {
960✔
104
        auto declaredArguments = functionSymbol.arguments();
130✔
105
        for (std::size_t i { 0 }; i < arguments.size(); ++i) {
348✔
106
            const auto& declaredArgument = declaredArguments.at(i);
218✔
107
            const auto& actualArgument = arguments.at(i)->getResultSymbol();
218✔
108
            typeCheck(actualArgument->getType(), declaredArgument, functionCall.getContext());
218✔
109
        }
110

111
        auto returnType = functionSymbol.returnType();
130✔
112
        if (!returnType.isVoid()) {
130✔
113
            functionCall.setResultSymbol(symbolTable.createTemporarySymbol(returnType));
90✔
114
        }
115
    } else if (functionSymbol.getContext() == EXTERNAL_CONTEXT) {
960✔
116
    // FIXME: using EXTERNAL_CONTEXT as a workaround for printf/scanf external functions until varargs are properly implemented
117
        auto returnType = functionSymbol.returnType();
830✔
118
        if (!returnType.isVoid()) {
830✔
119
            functionCall.setResultSymbol(symbolTable.createTemporarySymbol(returnType));
830✔
120
        }
121
    } else {
830✔
122
        semanticError("no match for function " + functionSymbol.getType().to_string(), functionCall.getContext());
×
123
    }
124
}
960✔
125

126
void SemanticAnalysisVisitor::visit(ast::IdentifierExpression& identifier) {
2,944✔
127
    if (symbolTable.hasSymbol(identifier.getIdentifier())) {
2,944✔
128
        identifier.setResultSymbol(symbolTable.lookup(identifier.getIdentifier()));
2,942✔
129
    } else {
130
        semanticError("symbol `" + identifier.getIdentifier() + "` is not defined", identifier.getContext());
2✔
131
    }
132
}
2,944✔
133

134
void SemanticAnalysisVisitor::visit(ast::ConstantExpression& constant) {
1,370✔
135
    constant.setResultSymbol(symbolTable.createTemporarySymbol(constant.getType()));
1,370✔
136
}
1,370✔
137

138
void SemanticAnalysisVisitor::visit(ast::StringLiteralExpression& stringLiteral) {
830✔
139
    std::string constantSymbol = symbolTable.newConstant(stringLiteral.getValue());
830✔
140
    stringLiteral.setConstantSymbol(constantSymbol);
830✔
141
    stringLiteral.setResultSymbol(symbolTable.createTemporarySymbol(stringLiteral.getType()));
830✔
142
}
830✔
143

144
void SemanticAnalysisVisitor::visit(ast::PostfixExpression& expression) {
24✔
145
    expression.visitOperand(*this);
24✔
146

147
    expression.setType(expression.operandType());
24✔
148
    auto operandSymbol = *expression.operandSymbol();
24✔
149
    expression.setResultSymbol(operandSymbol);
24✔
150

151
    auto preOperationSymbolName = operandSymbol.getName() + "_pre";
24✔
152
    symbolTable.insertSymbol(preOperationSymbolName, operandSymbol.getType(), operandSymbol.getContext());
24✔
153
    expression.setPreOperationSymbol(symbolTable.lookup(preOperationSymbolName));
24✔
154

155
    if (!expression.isLval()) {
24✔
156
        semanticError("lvalue required as increment operand", expression.getContext());
×
157
    }
158
}
24✔
159

160
void SemanticAnalysisVisitor::visit(ast::PrefixExpression& expression) {
28✔
161
    expression.visitOperand(*this);
28✔
162

163
    expression.setType(expression.operandType());
28✔
164
    expression.setResultSymbol(*expression.operandSymbol());
28✔
165

166
    if (!expression.isLval()) {
28✔
167
        semanticError("lvalue required as increment operand", expression.getContext());
×
168
    }
169
}
28✔
170

171
void SemanticAnalysisVisitor::visit(ast::UnaryExpression& expression) {
558✔
172
    expression.visitOperand(*this);
558✔
173

174
    switch (expression.getOperator()->getLexeme().front()) {
558✔
175
    case '&':
346✔
176
        expression.setResultSymbol(symbolTable.createTemporarySymbol(type::pointer(expression.operandType())));
346✔
177
        break;
346✔
178
    case '*':
90✔
179
        if (expression.operandType().isPointer()) {
90✔
180
            expression.setResultSymbol(symbolTable.createTemporarySymbol(expression.operandType().dereference()));
90✔
181
            expression.setLvalueSymbol(symbolTable.createTemporarySymbol(expression.operandType()));
90✔
182
        } else {
183
            semanticError("invalid type argument of ‘unary *’ :" + expression.operandType().to_string(), expression.getContext());
×
184
        }
185
        break;
90✔
186
    case '+':
4✔
187
        expression.setResultSymbol(*expression.operandSymbol());
4✔
188
        break;
4✔
189
    case '-':
88✔
190
        expression.setResultSymbol(symbolTable.createTemporarySymbol(expression.operandType()));
88✔
191
        break;
88✔
192
    case '!':
30✔
193
        expression.setResultSymbol(symbolTable.createTemporarySymbol(type::signedInteger()));
30✔
194
        expression.setTruthyLabel(symbolTable.newLabel());
30✔
195
        expression.setFalsyLabel(symbolTable.newLabel());
30✔
196
        break;
30✔
197
    default:
×
198
        throw std::runtime_error { "Unidentified increment operator: " + expression.getOperator()->getLexeme() };
×
199
    }
200
}
558✔
201

202
void SemanticAnalysisVisitor::visit(ast::TypeCast& expression) {
×
203
    expression.visitOperand(*this);
×
204

205
    expression.setResultSymbol(symbolTable.createTemporarySymbol(expression.getType().getType()));
×
206
}
×
207

208
void SemanticAnalysisVisitor::visit(ast::ArithmeticExpression& expression) {
140✔
209
    expression.visitLeftOperand(*this);
140✔
210
    expression.visitRightOperand(*this);
140✔
211

212
    typeCheck(
140✔
213
            expression.leftOperandType(),
280✔
214
            expression.rightOperandType(),
280✔
215
            expression.getContext());
280✔
216
    // FIXME: type conversion
217
    expression.setResultSymbol(symbolTable.createTemporarySymbol(expression.leftOperandType()));
140✔
218
}
140✔
219

220
void SemanticAnalysisVisitor::visit(ast::ShiftExpression& expression) {
20✔
221
    expression.visitLeftOperand(*this);
20✔
222
    expression.visitRightOperand(*this);
20✔
223

224
    if (expression.rightOperandType().isPrimitive() && !expression.rightOperandType().getPrimitive().isFloating()) {
20✔
225
        expression.setResultSymbol(symbolTable.createTemporarySymbol(expression.leftOperandType()));
20✔
226
    } else {
227
        semanticError("argument of type int required for shift expression", expression.getContext());
×
228
    }
229
}
20✔
230

231
void SemanticAnalysisVisitor::visit(ast::ComparisonExpression& expression) {
180✔
232
    expression.visitLeftOperand(*this);
180✔
233
    expression.visitRightOperand(*this);
180✔
234

235
    typeCheck(
180✔
236
            expression.leftOperandType(),
360✔
237
            expression.rightOperandType(),
360✔
238
            expression.getContext());
360✔
239

240
    expression.setResultSymbol(symbolTable.createTemporarySymbol(type::signedInteger()));
180✔
241
    expression.setTruthyLabel(symbolTable.newLabel());
180✔
242
    expression.setFalsyLabel(symbolTable.newLabel());
180✔
243
}
180✔
244

245
void SemanticAnalysisVisitor::visit(ast::BitwiseExpression& expression) {
16✔
246
    expression.visitLeftOperand(*this);
16✔
247
    expression.visitRightOperand(*this);
16✔
248
    expression.setType(expression.leftOperandType());
16✔
249

250
    typeCheck(
16✔
251
            expression.leftOperandType(),
32✔
252
            expression.rightOperandType(),
32✔
253
            expression.getContext());
32✔
254

255
    expression.setResultSymbol(
16✔
256
            symbolTable.createTemporarySymbol(expression.getType()));
32✔
257
}
16✔
258

259
void SemanticAnalysisVisitor::visit(ast::LogicalAndExpression& expression) {
12✔
260
    expression.visitLeftOperand(*this);
12✔
261
    expression.visitRightOperand(*this);
12✔
262

263
    typeCheck(
12✔
264
            expression.leftOperandType(),
24✔
265
            expression.rightOperandType(),
24✔
266
            expression.getContext());
24✔
267

268
    expression.setResultSymbol(symbolTable.createTemporarySymbol(type::signedInteger()));
12✔
269
    expression.setExitLabel(symbolTable.newLabel());
12✔
270
}
12✔
271

272
void SemanticAnalysisVisitor::visit(ast::LogicalOrExpression& expression) {
12✔
273
    expression.visitLeftOperand(*this);
12✔
274
    expression.visitRightOperand(*this);
12✔
275

276
    typeCheck(
12✔
277
            expression.leftOperandType(),
24✔
278
            expression.rightOperandType(),
24✔
279
            expression.getContext());
24✔
280

281
    expression.setResultSymbol(symbolTable.createTemporarySymbol(type::signedInteger()));
12✔
282
    expression.setExitLabel(symbolTable.newLabel());
12✔
283
}
12✔
284

285
void SemanticAnalysisVisitor::visit(ast::AssignmentExpression& expression) {
562✔
286
    expression.visitLeftOperand(*this);
562✔
287
    expression.visitRightOperand(*this);
562✔
288

289
    if (expression.isLval()) {
562✔
290
        typeCheck(
558✔
291
                expression.leftOperandType(),
1,116✔
292
                expression.rightOperandType(),
1,116✔
293
                expression.getContext());
1,116✔
294

295
        expression.setResultSymbol(*expression.leftOperandSymbol());
558✔
296
    } else {
297
        semanticError("lvalue required on the left side of assignment", expression.getContext());
12✔
298
    }
299
}
562✔
300

301
void SemanticAnalysisVisitor::visit(ast::ExpressionList& expression) {
2✔
302
    expression.visitLeftOperand(*this);
2✔
303
    expression.visitRightOperand(*this);
2✔
304
    // Comma operator: value and type of the right operand
305
    expression.setType(expression.rightOperandType());
2✔
306
    expression.setResultSymbol(*expression.rightOperandSymbol());
2✔
307
}
2✔
308

309
void SemanticAnalysisVisitor::visit(ast::Operator&) {
×
310
}
×
311

312
void SemanticAnalysisVisitor::visit(ast::JumpStatement& statement) {
×
313
    throw std::runtime_error { "not implemented" };
×
314
}
315

316
void SemanticAnalysisVisitor::visit(ast::ReturnStatement& statement) {
498✔
317
    statement.returnExpression->accept(*this);
498✔
318
}
498✔
319

320
void SemanticAnalysisVisitor::visit(ast::VoidReturnStatement& statement) {
26✔
321
}
26✔
322

323
void SemanticAnalysisVisitor::visit(ast::IfStatement& statement) {
20✔
324
    statement.testExpression->accept(*this);
20✔
325
    statement.body->accept(*this);
20✔
326

327
    statement.setFalsyLabel(symbolTable.newLabel());
20✔
328
}
20✔
329

330
void SemanticAnalysisVisitor::visit(ast::IfElseStatement& statement) {
16✔
331
    statement.testExpression->accept(*this);
16✔
332
    statement.truthyBody->accept(*this);
16✔
333
    statement.falsyBody->accept(*this);
16✔
334

335
    statement.setFalsyLabel(symbolTable.newLabel());
16✔
336
    statement.setExitLabel(symbolTable.newLabel());
16✔
337
}
16✔
338

339
void SemanticAnalysisVisitor::visit(ast::LoopStatement& loop) {
50✔
340
    loop.header->accept(*this);
50✔
341
    loop.body->accept(*this);
50✔
342
}
50✔
343

344
void SemanticAnalysisVisitor::visit(ast::ForLoopHeader& loopHeader) {
30✔
345
    if (loopHeader.initialization) {
30✔
346
        loopHeader.initialization->accept(*this);
20✔
347
    }
348
    if (loopHeader.clause) {
30✔
349
        loopHeader.clause->accept(*this);
22✔
350
    }
351
    if (loopHeader.increment) {
30✔
352
        loopHeader.increment->accept(*this);
22✔
353
    }
354

355
    loopHeader.setLoopEntry(symbolTable.newLabel());
30✔
356
    loopHeader.setLoopExit(symbolTable.newLabel());
30✔
357
}
30✔
358

359
void SemanticAnalysisVisitor::visit(ast::WhileLoopHeader& loopHeader) {
20✔
360
    loopHeader.clause->accept(*this);
20✔
361

362
    loopHeader.setLoopEntry(symbolTable.newLabel());
20✔
363
    loopHeader.setLoopExit(symbolTable.newLabel());
20✔
364
}
20✔
365

366
void SemanticAnalysisVisitor::visit(ast::Pointer&) {
78✔
367
}
78✔
368

369
void SemanticAnalysisVisitor::visit(ast::Identifier&) {
858✔
370
}
858✔
371

372
void SemanticAnalysisVisitor::visit(ast::ArrayDeclarator& declaration) {
×
373
    declaration.subscriptExpression->accept(*this);
×
374
    throw std::runtime_error { "not implemented" };
×
375
}
376

377
void SemanticAnalysisVisitor::visit(ast::FunctionDeclarator& declarator) {
522✔
378
    declarator.visitFormalArguments(*this);
522✔
379

380
    argumentNames.clear();
522✔
381
    std::vector<type::Type> arguments;
522✔
382
    for (auto& argumentDeclaration : declarator.getFormalArguments()) {
718✔
383
        arguments.push_back(argumentDeclaration.getType());
196✔
384
        argumentNames.push_back(argumentDeclaration.getName());
196✔
385
    }
386

387
    type::Type returnType = definitionReturnType.value_or(type::signedInteger());
522✔
388
    type::Type functionType = type::function(returnType, arguments);
522✔
389
    if (symbolTable.hasGlobalVariable(declarator.getName())) {
522✔
390
        semanticError("function `" + declarator.getName() + "` conflicts with global variable of the same name",
2✔
391
                declarator.getContext());
4✔
392
        return;
2✔
393
    }
394
    FunctionEntry functionEntry = symbolTable.insertFunction(
395
            declarator.getName(),
1,040✔
396
            functionType.getFunction(),
1,040✔
397
            declarator.getContext());
1,560✔
398

399
    if (functionEntry.getContext() != declarator.getContext()) {
520✔
400
        semanticError("function `" + declarator.getName() + "` definition conflicts with previous one on "
×
401
                + to_string(functionEntry.getContext()), declarator.getContext());
×
402
    }
403
}
526✔
404

405
void SemanticAnalysisVisitor::visit(ast::FormalArgument& argument) {
196✔
406
    argument.visitSpecifiers(*this);
196✔
407
    argument.visitDeclarator(*this);
196✔
408
    if (argument.getType().isVoid()) {
196✔
409
        semanticError("function argument ‘" + argument.getName() + "’ declared void", argument.getDeclarationContext());
×
410
    }
411
}
196✔
412

413
void SemanticAnalysisVisitor::visit(ast::FunctionDefinition& function) {
522✔
414
    function.visitReturnType(*this);
522✔
415
    const auto& specs = function.getReturnTypeSpecifiers().getTypeSpecifiers();
522✔
416
    if (!specs.empty()) {
522✔
417
        definitionReturnType = specs.at(0).getType();
522✔
418
    }
419
    function.visitDeclarator(*this);
522✔
420
    definitionReturnType.reset();
522✔
421

422
    if (!symbolTable.hasFunction(function.getName())) {
522✔
423
        return;
2✔
424
    }
425
    function.setSymbol(symbolTable.findFunction(function.getName()));
520✔
426
    symbolTable.startFunction(function.getName(), argumentNames);
520✔
427
    // Parameters and outermost body declarations share one scope (C); do not enterBlockScope.
428
    function.visitBodyChildren(*this);
520✔
429
    function.setArguments(symbolTable.getCurrentScopeArguments());
520✔
430
    function.setLocalVariables(symbolTable.getCurrentScopeSymbols());
520✔
431
    symbolTable.endFunction();
520✔
432
}
433

434
void SemanticAnalysisVisitor::visit(ast::Block& block) {
112✔
435
    symbolTable.enterBlockScope();
112✔
436
    block.visitChildren(*this);
112✔
437
    symbolTable.exitBlockScope();
112✔
438
}
112✔
439

440
void SemanticAnalysisVisitor::typeCheck(const type::Type& typeFrom, const type::Type& typeTo,
1,136✔
441
        const translation_unit::Context& context)
442
{
443
    if (!typeTo.canAssignFrom(typeFrom)) {
1,136✔
444
        semanticError("type mismatch: can't convert " + typeFrom.to_string() + " to " + typeTo.to_string(), context);
×
445
    }
446
}
1,136✔
447

448
void SemanticAnalysisVisitor::semanticError(std::string message, const translation_unit::Context& context) {
12✔
449
    containsSemanticErrors = true;
12✔
450
    err << context << ": error: " << message << "\n";
12✔
451
}
12✔
452

453
bool SemanticAnalysisVisitor::successfulSemanticAnalysis() const {
410✔
454
    return !containsSemanticErrors;
410✔
455
}
456

457
std::map<std::string, std::string> SemanticAnalysisVisitor::getConstants() const {
398✔
458
    return symbolTable.getConstants();
398✔
459
}
460

461
std::vector<ValueEntry> SemanticAnalysisVisitor::getGlobalVariables() const {
398✔
462
    return symbolTable.getGlobalVariables();
398✔
463
}
464

465

466
void SemanticAnalysisVisitor::visit(ast::MemberAccess& expression) {
170✔
467
    expression.getBase()->accept(*this);
170✔
468
    type::Type baseType = expression.getBase()->getType();
170✔
469
    type::Type structType = baseType;
170✔
470
    if (expression.isArrow()) {
170✔
471
        if (!baseType.isPointer()) {
28✔
NEW
472
            semanticError("base of '->' is not a pointer", expression.getContext());
×
NEW
473
            return;
×
474
        }
475
        structType = baseType.dereference();
28✔
476
    }
477
    if (!structType.isStructure()) {
170✔
NEW
478
        semanticError("request for member in non-struct", expression.getContext());
×
NEW
479
        return;
×
480
    }
481
    type::Type memberTy = type::signedInteger();
170✔
482
    int offset = 0;
170✔
483
    if (!structType.memberType(expression.getMemberName(), memberTy) ||
340✔
484
            !structType.memberOffset(expression.getMemberName(), offset)) {
170✔
NEW
485
        semanticError("struct has no member named `" + expression.getMemberName() + "`", expression.getContext());
×
NEW
486
        return;
×
487
    }
488
    expression.setMemberOffset(offset);
170✔
489
    expression.setBaseResultSymbol(*expression.getBase()->getResultSymbol());
170✔
490
    expression.setResultSymbol(symbolTable.createTemporarySymbol(memberTy));
170✔
491
    expression.setFieldAddressSymbol(symbolTable.createTemporarySymbol(type::pointer(memberTy)));
170✔
492
}
170✔
493

494
} // namespace semantic_analyzer
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