source: src/CodeGen/CodeGenerator.cpp@ 8de86b3

Last change on this file since 8de86b3 was 9506c70, checked in by Andrew Beach <ajbeach@…>, 7 months ago

Stricter BranchStmt code generation that should prevent some of the warning cases removed in the concurrency test update. This also caught a bad case in the control flow handling code.

  • Property mode set to 100644
File size: 36.5 KB
RevLine 
[8941b6b]1//
2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
[83fd57d]7// CodeGenerator.cpp --
[8941b6b]8//
9// Author : Andrew Beach
10// Created On : Tue Oct 17 15:54:00 2023
[d96f7c4]11// Last Modified By : Peter A. Buhr
12// Last Modified On : Fri Jan 17 14:19:22 2025
13// Update Count : 1
[8941b6b]14//
15
[83fd57d]16#include "CodeGenerator.hpp"
[8941b6b]17
18#include "AST/Print.hpp"
[c92bdcc]19#include "OperatorTable.hpp" // for OperatorInfo, operatorLookup
20#include "CodeGen/GenType.hpp" // for genType
[8941b6b]21#include "Common/ToString.hpp" // for toString
[c92bdcc]22#include "Common/UniqueName.hpp" // for UniqueName
[8941b6b]23
24namespace CodeGen {
25
[0bd3faf]26int CodeGenerator::tabsize = 4;
[8941b6b]27
28// The kinds of statements that should be followed by whitespace.
29static bool wantSpacing( ast::Stmt const * stmt ) {
30 return dynamic_cast<ast::IfStmt const *>( stmt )
31 || dynamic_cast<ast::CompoundStmt const *>( stmt )
32 || dynamic_cast<ast::WhileDoStmt const *>( stmt )
33 || dynamic_cast<ast::ForStmt const *>( stmt )
34 || dynamic_cast<ast::SwitchStmt const *>( stmt );
35}
36
[0bd3faf]37void CodeGenerator::extension( ast::Expr const * expr ) {
[8941b6b]38 if ( expr->extension ) output << "__extension__ ";
39}
40
[0bd3faf]41void CodeGenerator::extension( ast::Decl const * decl ) {
[8941b6b]42 if ( decl->extension ) output << "__extension__ ";
43}
44
[0bd3faf]45void CodeGenerator::asmName( ast::DeclWithType const * decl ) {
[8941b6b]46 if ( auto asmName = decl->asmName.as<ast::ConstantExpr>() ) {
47 output << " asm ( " << asmName->rep << " )";
48 }
49}
50
[0bd3faf]51CodeGenerator::LabelPrinter & CodeGenerator::LabelPrinter::operator()(
[8941b6b]52 std::vector<ast::Label> const & l ) {
53 labels = &l;
54 return *this;
55}
56
[0bd3faf]57std::ostream & CodeGenerator::LabelPrinter::operator()( std::ostream & output ) const {
[8941b6b]58 const std::vector<ast::Label> & labels = *this->labels;
59 for ( const ast::Label & label : labels ) {
60 output << label.name + ": ";
61 this->cg.genAttributes( label.attributes );
62 }
63 return output;
64}
65
66// Using updateLocation at the beginning of a node and endl within a node
67// should become the method of formating.
[0bd3faf]68void CodeGenerator::updateLocation( CodeLocation const & to ) {
[8941b6b]69 // Skip if linemarks shouldn't appear or if location is unset.
70 if ( !options.lineMarks || to.isUnset() ) return;
71
72 if ( currentLocation.followedBy( to, 0 ) ) {
73 return;
74 } else if ( currentLocation.followedBy( to, 1 ) ) {
75 output << "\n" << indent;
76 currentLocation.first_line += 1;
77 } else if ( currentLocation.followedBy( to, 2 ) ) {
78 output << "\n\n" << indent;
79 currentLocation.first_line += 2;
80 } else {
[661e7b0]81 output << "\n# " << to.first_line << " \"" << to.filename.c_str()
[8941b6b]82 << "\"\n" << indent;
83 currentLocation = to;
84 }
85 output << std::flush;
86}
87
[0bd3faf]88void CodeGenerator::updateLocation( ast::ParseNode const * to ) {
[8941b6b]89 updateLocation( to->location );
90}
91
[0bd3faf]92std::ostream & CodeGenerator::LineEnder::operator()( std::ostream & os ) const {
[8941b6b]93 os << "\n" << std::flush;
94 cg.currentLocation.first_line++;
95 return os;
96}
97
[0bd3faf]98CodeGenerator::CodeGenerator( std::ostream & os, const Options & options ) :
99 indent( 0, CodeGenerator::tabsize ), output( os ),
[8941b6b]100 options( options ), printLabels( *this ), endl( *this )
101{}
102
[0bd3faf]103std::string CodeGenerator::mangleName( ast::DeclWithType const * decl ) {
[c7ebbec]104 if ( !options.pretty && decl->linkage.is_mangled && decl->mangleName != "" ) {
[8941b6b]105 return decl->scopedMangleName();
106 } else {
107 return decl->name;
108 }
109}
110
[0bd3faf]111void CodeGenerator::genAttributes(
[8941b6b]112 const std::vector<ast::ptr<ast::Attribute>> & attributes ) {
113 if ( attributes.empty() ) return;
114 output << "__attribute__ ((";
115 for ( auto attr = attributes.begin() ;; ) {
116 output << (*attr)->name;
117 if ( !(*attr)->params.empty() ) {
118 output << "(";
119 genCommaList( (*attr)->params );
120 output << ")";
121 }
122 if ( ++attr == attributes.end() ) break;
123 output << ",";
124 }
125 output << ")) ";
126}
127
[0bd3faf]128void CodeGenerator::previsit( ast::Node const * ) {
[8941b6b]129 // All traversal is manual.
130 // TODO: Which means the ast::Pass is just providing a default no visit?
131 visit_children = false;
[7959e56]132 changeState_ArgToIntrinsic(false);
[8941b6b]133}
134
[0bd3faf]135void CodeGenerator::previsit( ast::ParseNode const * node ) {
[8941b6b]136 previsit( (ast::Node const *)node );
137 updateLocation( node );
138}
139
[0bd3faf]140void CodeGenerator::postvisit( ast::Node const * node ) {
[8941b6b]141 std::stringstream ss;
142 ast::print( ss, node );
143 assertf( false, "Unhandled node reached in CodeGenerator: %s", ss.str().c_str() );
144}
145
[0bd3faf]146void CodeGenerator::previsit( ast::Expr const * expr ) {
[8941b6b]147 previsit( (ast::ParseNode const *)expr );
148 GuardAction( [this, expr](){
149 if ( options.printExprTypes && expr->result ) {
150 output << " /* " << genType( expr->result, "", options ) << " */ ";
151 }
152 } );
153}
154
[0bd3faf]155void CodeGenerator::postvisit( ast::FunctionDecl const * decl ) {
[8941b6b]156 // Deleted decls should never be used, so don't print them in C.
157 if ( decl->isDeleted && options.genC ) return;
158 extension( decl );
159 genAttributes( decl->attributes );
160
161 handleStorageClass( decl );
162 ast::print( output, decl->funcSpec );
163
164 Options subOptions = options;
165 subOptions.anonymousUnused = decl->stmts;
166
167 std::ostringstream acc;
[0bd3faf]168 ast::Pass<CodeGenerator> subCG( acc, subOptions );
[8941b6b]169 // Add the forall clause.
[3c4003b9]170 if ( !decl->type_params.empty() ) {
171 assertf( !options.genC, "FunctionDecl forall should not reach code generation." );
[8941b6b]172 acc << "forall(";
173 subCG.core.genCommaList( decl->type_params );
174 acc << ")" << std::endl;
175 }
[a1fbad0]176 // The forall clause should be printed early as part of the preamble.
177 output << acc.str();
178 acc.str("");
[8941b6b]179
180 acc << mangleName( decl );
181
182 if ( 0 == decl->params.size() ) {
[db19e1d]183 if ( !decl->type->isVarArgs ) {
184 acc << "(void)";
185 } else if ( options.genC ) {
[8941b6b]186 acc << "()";
187 } else {
[db19e1d]188 acc << "(...)";
[8941b6b]189 }
190 } else {
191 acc << "(";
192 subCG.core.genCommaList( decl->params );
193 if ( decl->type->isVarArgs ) {
194 acc << ", ...";
195 }
196 acc << ")";
197 }
198
199 if ( 1 == decl->returns.size() ) {
200 ast::ptr<ast::Type> const & type = decl->returns[0]->get_type();
201 output << genTypeNoAttr( type, acc.str(), subOptions );
[0139351]202 } else if ( 0 == decl->returns.size() ) {
[8941b6b]203 output << "void " + acc.str();
[0139351]204 } else {
205 assertf( !options.genC, "Multi-return should not reach code generation." );
206 ast::ptr<ast::Type> type = new ast::TupleType( copy( decl->type->returns ) );
207 output << genTypeNoAttr( type, acc.str(), subOptions );
[8941b6b]208 }
209
210 asmName( decl );
211
212 if ( decl->stmts ) {
213 decl->stmts->accept( *visitor );
214 }
215 if ( decl->isDeleted ) {
216 output << " = void";
217 }
218}
219
[0bd3faf]220ast::ObjectDecl const * CodeGenerator::postvisit(
[8941b6b]221 ast::ObjectDecl const * decl ) {
222 // Deleted decls should never be used, so don't print them in C.
223 if ( decl->isDeleted && options.genC ) return decl;
224
225 // GCC allows an empty declarator (no name) for bit-fields and C
226 // states: 6.7.2.1 Structure and union specifiers, point 4, page 113:
227 // If the (bit field) value is zero, the declaration shall have no
228 // declarator. For anything else, the anonymous name refers to the
229 // anonymous object for plan9 inheritance.
230 if ( decl->name.empty() && options.genC && !decl->bitfieldWidth ) {
231 // TODO: Should this be changed in a pervious pass?
232 auto mutDecl = ast::mutate( decl );
233 // Only generate an anonymous name when generating C code,
234 // otherwise it clutters the output too much.
235 static UniqueName name = { "__anonymous_object" };
236 mutDecl->name = name.newName();
237 // Stops unused parameter warnings.
238 if ( options.anonymousUnused ) {
239 mutDecl->attributes.push_back( new ast::Attribute( "unused" ) );
240 }
241 decl = mutDecl;
242 }
243
244 extension( decl );
245 genAttributes( decl->attributes );
246
247 handleStorageClass( decl );
248 output << genType( decl->type, mangleName( decl ),
249 Options( options.pretty, options.genC, false, false ) );
250
251 asmName( decl );
252
253 if ( decl->init ) {
[f070ea8]254 bool isGenericInit = options.genC || decl->init->maybeConstructed;
255 output << ( (isGenericInit) ? " = " : " @= " );
[8941b6b]256 decl->init->accept( *visitor );
257 }
258 if ( decl->isDeleted ) {
259 output << " = void";
260 }
261
262 if ( decl->bitfieldWidth ) {
263 output << ":";
264 decl->bitfieldWidth->accept( *visitor );
265 }
266 return decl;
267}
268
[0bd3faf]269void CodeGenerator::handleStorageClass( ast::DeclWithType const * decl ) {
[8941b6b]270 if ( decl->storage.any() ) {
271 ast::print( output, decl->storage );
272 }
273}
274
[0bd3faf]275void CodeGenerator::handleAggregate(
[8941b6b]276 ast::AggregateDecl const * decl, std::string const & kind ) {
277 if ( !decl->params.empty() && !options.genC ) {
278 output << "forall(";
279 genCommaList( decl->params );
280 output << ")\n" << indent << std::flush;
281 }
282
283 output << kind;
284 genAttributes( decl->attributes );
285 output << decl->name;
286
287 if ( decl->body ) {
288 auto & members = decl->members;
289 output << " {" << endl;
290
291 ++indent;
292 for ( auto & member : members ) {
293 output << indent;
294 member->accept( *visitor );
295 output << ";" << endl;
296 }
297 --indent;
298
299 output << indent << "}";
300 }
301}
302
[0bd3faf]303void CodeGenerator::postvisit( ast::StructDecl const * decl ) {
[8941b6b]304 extension( decl );
305 handleAggregate( decl, "struct " );
306}
307
[0bd3faf]308void CodeGenerator::postvisit( ast::UnionDecl const * decl ) {
[8941b6b]309 extension( decl );
310 handleAggregate( decl, "union " );
311}
312
313template<typename pass_type>
314inline void genEnumInitializer( ast::Pass<pass_type> * visitor,
315 ast::Type const * baseType, std::ostream & output,
316 ast::Init const * init, long long * curVal, Options options ) {
317 auto baseTypeAsBasic = dynamic_cast<ast::BasicType const *>( baseType );
318 // Value is provided.
319 if ( init ) {
320 output << " = (" << genType( baseType, "", options ) << ")";
321 init->accept( *visitor );
322 // If it is an integral type and initilizer offered,
323 // need to update the curVal.
324 if ( baseTypeAsBasic && baseTypeAsBasic->isInteger() ) {
325 ast::Expr const * expr = ((ast::SingleInit const *)(init))->value;
326 // Unwrap introduced cast.
327 while ( auto temp = dynamic_cast<ast::CastExpr const *>( expr ) ) {
328 expr = temp->arg;
329 }
330 *curVal = ((ast::ConstantExpr const *)(expr))->intValue() + 1;
331 }
332 // Generate next value from previous value.
333 } else if ( baseTypeAsBasic && baseTypeAsBasic->isInteger() ) {
334 output << " = (" << genType( baseType, "", options ) << ")";
335 output << (*curVal)++;
336 }
337}
338
[0bd3faf]339void CodeGenerator::postvisit( ast::EnumDecl const * decl ) {
[8941b6b]340 extension( decl );
341 auto members = decl->members;
[c75b30a]342 // if ( decl->base && !members.empty() ) {
343 // long long curVal = 0;
344 // for ( auto member : members ) {
345 // auto obj = member.strict_as<ast::ObjectDecl>();
346 // output << "static ";
347 // output << genType( decl->base, mangleName( obj ), options );
348 // genEnumInitializer( visitor, decl->base, output, obj->init, &curVal, options );
349 // output << ";" << endl;
350 // }
351 // } else {
[8941b6b]352 output << "enum ";
353 genAttributes( decl->attributes );
354
355 output << decl->name;
356
357 if ( !members.empty() ) {
358 output << " {" << endl;
359
360 ++indent;
361 for ( auto member : members ) {
362 auto obj = member.strict_as<ast::ObjectDecl>();
363 output << indent << mangleName( obj );
[c75b30a]364 if ( !decl->base && obj->init ) {
[8941b6b]365 output << " = ";
366 obj->init->accept( *visitor );
367 }
368 output << "," << endl;
369 }
370 --indent;
371
372 output << indent << "}";
373 }
[c75b30a]374 // }
[8941b6b]375}
376
[0bd3faf]377void CodeGenerator::postvisit( ast::TraitDecl const * decl ) {
[8941b6b]378 assertf( !options.genC, "TraitDecls should not reach code generation." );
379 extension( decl );
380 handleAggregate( decl, "trait " );
381}
382
[0bd3faf]383void CodeGenerator::postvisit( ast::TypedefDecl const * decl ) {
[8941b6b]384 assertf( !options.genC, "Typedefs should not reach code generation." );
385 output << "typedef " << genType( decl->base, decl->name, options ) << endl;
386}
387
[0bd3faf]388void CodeGenerator::postvisit( ast::TypeDecl const * decl ) {
[8941b6b]389 assertf( !options.genC, "TypeDecls should not reach code generation." );
390 output << decl->genTypeString() << " " << decl->name;
391 if ( decl->sized ) {
392 output << " | sized(" << decl->name << ")";
393 }
394 if ( !decl->assertions.empty() ) {
395 output << " | { ";
396 for ( ast::DeclWithType const * assert : decl->assertions ) {
397 assert->accept( *visitor );
398 output << "; ";
399 }
400 output << " }";
401 }
402}
403
[0bd3faf]404void CodeGenerator::postvisit( ast::StaticAssertDecl const * decl ) {
[8941b6b]405 output << "_Static_assert(";
406 decl->cond->accept( *visitor );
407 output << ", ";
408 decl->msg->accept( *visitor );
409 output << ")";
410}
411
[0bd3faf]412void CodeGenerator::postvisit( ast::Designation const * designation ) {
[8941b6b]413 auto designators = designation->designators;
414 if ( 0 == designators.size() ) return;
415 for ( ast::ptr<ast::Expr> const & des : designators ) {
416 // If the expression is a NameExpr or VariableExpr, then it is a field.
417 if ( des.as<ast::NameExpr>() || des.as<ast::VariableExpr>() ) {
418 output << ".";
419 des->accept( *visitor );
420 // Otherwise, it is a ConstantExpr or CastExpr, then it is an index.
421 } else {
422 output << "[";
423 des->accept( *visitor );
424 output << "]";
425 }
426 }
427 output << " = ";
428}
429
[0bd3faf]430void CodeGenerator::postvisit( ast::SingleInit const * init ) {
[8941b6b]431 init->value->accept( *visitor );
432}
433
[0bd3faf]434void CodeGenerator::postvisit( ast::ListInit const * init ) {
[8941b6b]435 auto initBegin = init->initializers.begin();
436 auto initEnd = init->initializers.end();
437 auto desigBegin = init->designations.begin();
438 auto desigEnd = init->designations.end();
439
440 output << "{ ";
441 if ( initBegin != initEnd ) while (true) {
442 (*desigBegin)->accept( *visitor );
443 (*initBegin)->accept( *visitor );
444 ++initBegin, ++desigBegin;
445 if ( initBegin == initEnd ) break;
446 output << ", ";
447 }
448 output << " }";
449 assertf( initBegin == initEnd && desigBegin == desigEnd,
450 "Initializers and designators not the same length. %s", toCString( init ) );
451}
452
[0bd3faf]453void CodeGenerator::postvisit( ast::ConstructorInit const * init ) {
[8941b6b]454 assertf( !options.genC, "ConstructorInit nodes should not reach code generation." );
455 // This isn't actual code, but labels the constructor/destructor pairs.
456 output << "<ctorinit>{" << endl << ++indent << "ctor: ";
457 if ( init->ctor ) init->ctor->accept( *visitor );
458 output << ", " << endl << indent << "dtor: ";
459 if ( init->dtor ) init->dtor->accept( *visitor );
460 output << endl << --indent << "}";
461}
462
[0bd3faf]463void CodeGenerator::postvisit( ast::ApplicationExpr const * expr ) {
[8941b6b]464 extension( expr );
465 if ( auto var = expr->func.as<ast::VariableExpr>() ) {
466 const OperatorInfo * opInfo;
467 if ( var->var->linkage == ast::Linkage::Intrinsic &&
468 ( opInfo = operatorLookup( var->var->name ) ) ) {
[7959e56]469 changeState_ArgToIntrinsic(true);
[8941b6b]470 auto arg = expr->args.begin();
471 switch ( opInfo->type ) {
472 case OT_INDEX:
473 assert( 2 == expr->args.size() );
474 (*arg++)->accept( *visitor );
475 output << "[";
476 (*arg)->accept( *visitor );
477 output << "]";
478 break;
479
480 // There are no intrinsic definitions of the function call operator.
481 case OT_CALL:
482 assert( false );
483 break;
484
485 case OT_CTOR:
486 case OT_DTOR:
487 // No-op constructor, but run the internal expression.
488 if ( 1 == expr->args.size() ) {
489 output << "(";
490 (*arg++)->accept( *visitor );
491 output << ") /* " << opInfo->inputName << " */";
492 // These are all implemented as some form of assignment.
493 } else if ( 2 == expr->args.size() ) {
494 output << "(";
495 (*arg++)->accept( *visitor );
496 output << opInfo->symbol;
497 (*arg)->accept( *visitor );
498 output << ") /* " << opInfo->inputName << " */";
499 // No constructors with 0 or more than 2 parameters.
500 } else {
501 assert( false );
502 }
503 break;
504
505 case OT_PREFIX:
506 case OT_PREFIXASSIGN:
507 assert( 1 == expr->args.size() );
508 output << "(" << opInfo->symbol;
509 (*arg)->accept( *visitor );
510 output << ")";
511 break;
512
513 case OT_POSTFIX:
514 case OT_POSTFIXASSIGN:
515 assert( 1 == expr->args.size() );
516 (*arg)->accept( *visitor );
517 output << opInfo->symbol;
518 break;
519
520 case OT_INFIX:
521 case OT_INFIXASSIGN:
522 assert( 2 == expr->args.size() );
523 output << "(";
524 (*arg++)->accept( *visitor );
525 output << opInfo->symbol;
526 (*arg)->accept( *visitor );
527 output << ")";
528 break;
529
530 // There are no intrinsic definitions of 0/1 or label address
531 // as function.
532 case OT_CONSTANT:
533 case OT_LABELADDRESS:
534 assert( false );
535 }
536 // TODO: This is a work-around to make it a constant until a proper
537 // constexpr solution is created.
538 } else if ( var->var->linkage == ast::Linkage::BuiltinCFA &&
539 var->var->name == "intptr" ) {
540 output << "((void*)";
541 auto arg = expr->args.begin();
542 (*arg++)->accept( *visitor );
543 output << ")";
544 } else {
545 var->accept( *visitor );
546 output << "(";
547 genCommaList( expr->args );
548 output << ")";
549 }
550 } else {
551 expr->func->accept( *visitor );
552 output << "(";
553 genCommaList( expr->args );
554 output << ")";
555 }
556}
557
[0bd3faf]558void CodeGenerator::postvisit( ast::UntypedExpr const * expr ) {
[8941b6b]559 extension( expr );
560 if ( auto name = expr->func.as<ast::NameExpr>() ) {
561 if ( const OperatorInfo * opInfo = operatorLookup( name->name ) ) {
[7959e56]562 changeState_ArgToIntrinsic(true);
[8941b6b]563 auto arg = expr->args.begin();
564 switch ( opInfo->type ) {
565 case OT_INDEX:
566 assert( 2 == expr->args.size() );
567 (*arg++)->accept( *visitor );
568 output << "[";
569 (*arg)->accept( *visitor );
570 output << "]";
571 break;
572
573 case OT_CALL:
574 assert( false );
575
576 case OT_CTOR:
577 case OT_DTOR:
578 // No-op constructor, but run the internal expression.
579 if ( 1 == expr->args.size() ) {
580 output << "(";
581 (*arg++)->accept( *visitor );
582 output << ")";
583 // These are all implemented as some form of assignment.
584 } else if ( 2 == expr->args.size() ) {
585 output << "(";
586 (*arg++)->accept( *visitor );
587 output << opInfo->symbol;
588 (*arg)->accept( *visitor );
589 output << ") /* " << opInfo->inputName << " */";
590 // No constructors with 0 or more than 2 parameters.
591 } else {
592 assertf( !options.genC, "UntypedExpr constructor/destructor with 0 or more than 2 parameters." );
593 output << "(";
594 (*arg++)->accept( *visitor );
595 output << opInfo->symbol << "{ ";
596 genCommaList( arg, expr->args.end() );
597 output << "}) /* " << opInfo->inputName << " */";
598 }
599 break;
600
601 case OT_PREFIX:
602 case OT_PREFIXASSIGN:
603 case OT_LABELADDRESS:
604 assert( 1 == expr->args.size() );
605 output << "(" << opInfo->symbol;
606 (*arg)->accept( *visitor );
607 output << ")";
608 break;
609
610 case OT_POSTFIX:
611 case OT_POSTFIXASSIGN:
612 assert( 1 == expr->args.size() );
613 (*arg)->accept( *visitor );
614 output << opInfo->symbol;
615 break;
616
617 case OT_INFIX:
618 case OT_INFIXASSIGN:
619 assert( 2 == expr->args.size() );
620 output << "(";
621 (*arg++)->accept( *visitor );
622 output << opInfo->symbol;
623 (*arg)->accept( *visitor );
624 output << ")";
625 break;
626
627 // There are no intrinsic definitions of 0/1 or label address
628 // as function.
629 case OT_CONSTANT:
630 assert( false );
631 }
632 // builtin routines
633 } else {
634 name->accept( *visitor );
635 output << "(";
636 genCommaList( expr->args );
637 output << ")";
638 }
639 } else {
640 expr->func->accept( *visitor );
641 output << "(";
642 genCommaList( expr->args );
643 output << ")";
644 }
645}
646
[0bd3faf]647void CodeGenerator::postvisit( ast::RangeExpr const * expr ) {
[8941b6b]648 expr->low->accept( *visitor );
649 output << " ... ";
650 expr->high->accept( *visitor );
651}
652
[0bd3faf]653void CodeGenerator::postvisit( ast::NameExpr const * expr ) {
[8941b6b]654 extension( expr );
655 if ( const OperatorInfo * opInfo = operatorLookup( expr->name ) ) {
656 if ( OT_CONSTANT == opInfo->type ) {
657 output << opInfo->symbol;
658 } else {
659 output << opInfo->outputName;
660 }
661 } else {
662 output << expr->name;
663 }
664}
665
[0bd3faf]666void CodeGenerator::postvisit( ast::DimensionExpr const * expr ) {
[8941b6b]667 extension( expr );
668 output << "/*non-type*/" << expr->name;
669}
670
[0bd3faf]671void CodeGenerator::postvisit( ast::AddressExpr const * expr ) {
[8941b6b]672 extension( expr );
673 output << "(&";
674 expr->arg->accept( *visitor );
675 output << ")";
676}
677
[0bd3faf]678void CodeGenerator::postvisit( ast::LabelAddressExpr const * expr ) {
[8941b6b]679 extension( expr );
680 output << "(&&" << expr->arg << ")";
681}
682
[0bd3faf]683void CodeGenerator::postvisit( ast::CastExpr const * expr ) {
[8941b6b]684 extension( expr );
685 output << "(";
[ecf3812]686 switch ( expr->kind ) {
687 case ast::CCast:
688 if ( expr->result->isVoid() ) {
689 output << "(void)";
690 } else {
691 output << "(";
692 output << genType( expr->result, "", options );
693 output << ")";
694 }
695 break;
696 case ast::CoerceCast:
697 assertf( ast::CoerceCast != expr->kind, "Coercion cast is not implemented." );
698 // And likely shouldn't reach code generation when it is implemented.
699 break;
700 case ast::ReturnCast:
701 // This should be invisible in the resulting C code.
702 // Can we insert a check here?
703 //assert( ResolvExpr::typesCompatable(???) );
704 if ( options.genC ) break;
705 output << "(return ";
[8941b6b]706 output << genType( expr->result, "", options );
707 output << ")";
[ecf3812]708 break;
[8941b6b]709 }
710 expr->arg->accept( *visitor );
711 output << ")";
712}
713
[0bd3faf]714void CodeGenerator::postvisit( ast::KeywordCastExpr const * expr ) {
[8941b6b]715 assertf( !options.genC, "KeywordCastExpr should not reach code generation." );
716 extension( expr );
717 output << "((" << expr->targetString() << " &)";
718 expr->arg->accept( *visitor );
719 output << ")";
720}
721
[0bd3faf]722void CodeGenerator::postvisit( ast::VirtualCastExpr const * expr ) {
[8941b6b]723 assertf( !options.genC, "VirtualCastExpr should not reach code generation." );
724 extension( expr );
725 // TODO: Is this busted?
726 output << "(virtual ";
727 expr->arg->accept( *visitor );
728 output << ")";
729}
730
[0bd3faf]731void CodeGenerator::postvisit( ast::UntypedMemberExpr const * expr ) {
[8941b6b]732 assertf( !options.genC, "UntypedMemberExpr should not reach code generation." );
733 extension( expr );
734 expr->aggregate->accept( *visitor );
735 output << ".";
736 expr->member->accept( *visitor );
737}
738
[0bd3faf]739void CodeGenerator::postvisit( ast::MemberExpr const * expr ) {
[8941b6b]740 extension( expr );
741 expr->aggregate->accept( *visitor );
742 output << "." << mangleName( expr->member );
743}
744
[0bd3faf]745void CodeGenerator::postvisit( ast::VariableExpr const * expr ) {
[8941b6b]746 extension( expr );
747 const OperatorInfo * opInfo;
[7959e56]748 if ( visitingArgToIntrinsic
749 && options.genC
750 && dynamic_cast<ast::ZeroType const *>( expr->var->get_type() ) ) {
751 // int * p; p = 0; ==> ?=?( p, (zero_t){} ); ==> p = 0;
752 // void f( zero_t z ) { g(z); } ==> g(z); ==> g(z);
753 // (we are at the last '==>')
754 output << "0";
755 } else if ( expr->var->linkage == ast::Linkage::Intrinsic
[8941b6b]756 && ( opInfo = operatorLookup( expr->var->name ) )
757 && opInfo->type == OT_CONSTANT ) {
758 output << opInfo->symbol;
759 } else {
760 output << mangleName( expr->var );
761 }
762}
763
[0bd3faf]764void CodeGenerator::postvisit( ast::ConstantExpr const * expr ) {
[8941b6b]765 extension( expr );
766 output << expr->rep;
767}
768
[0bd3faf]769void CodeGenerator::postvisit( ast::SizeofExpr const * expr ) {
[8941b6b]770 extension( expr );
771 output << "sizeof(";
[b6f2e7ab]772 if ( auto type = expr->type.as<ast::TypeofType>() ) {
773 type->expr->accept( *visitor );
[8941b6b]774 } else {
[b6f2e7ab]775 output << genType( expr->type, "", options );
[8941b6b]776 }
777 output << ")";
778}
779
[0bd3faf]780void CodeGenerator::postvisit( ast::AlignofExpr const * expr ) {
[8941b6b]781 // Using the GCC extension to avoid changing the std to C11.
782 extension( expr );
783 output << "__alignof__(";
[b6f2e7ab]784 if ( auto type = expr->type.as<ast::TypeofType>() ) {
785 type->expr->accept( *visitor );
[8941b6b]786 } else {
[b6f2e7ab]787 output << genType( expr->type, "", options );
[8941b6b]788 }
789 output << ")";
790}
791
[0bd3faf]792void CodeGenerator::postvisit( ast::UntypedOffsetofExpr const * expr ) {
[8941b6b]793 assertf( !options.genC, "UntypedOffsetofExpr should not reach code generation." );
794 output << "offsetof(";
795 output << genType( expr->type, "", options );
796 output << ", " << expr->member;
797 output << ")";
798}
799
[0bd3faf]800void CodeGenerator::postvisit( ast::OffsetofExpr const * expr ) {
[8941b6b]801 // Use GCC builtin
802 output << "__builtin_offsetof(";
803 output << genType( expr->type, "", options );
804 output << ", " << mangleName( expr->member );
805 output << ")";
806}
807
[0bd3faf]808void CodeGenerator::postvisit( ast::OffsetPackExpr const * expr ) {
[8941b6b]809 assertf( !options.genC, "OffsetPackExpr should not reach code generation." );
810 output << "__CFA_offsetpack(" << genType( expr->type, "", options ) << ")";
811}
812
[0bd3faf]813void CodeGenerator::postvisit( ast::LogicalExpr const * expr ) {
[8941b6b]814 extension( expr );
815 output << "(";
816 expr->arg1->accept( *visitor );
817 output << ( ( expr->isAnd ) ? " && " : " || " );
818 expr->arg2->accept( *visitor );
819 output << ")";
820}
821
[0bd3faf]822void CodeGenerator::postvisit( ast::ConditionalExpr const * expr ) {
[8941b6b]823 extension( expr );
824 output << "(";
825 expr->arg1->accept( *visitor );
826 output << " ? ";
827 expr->arg2->accept( *visitor );
828 output << " : ";
829 expr->arg3->accept( *visitor );
830 output << ")";
831}
832
[0bd3faf]833void CodeGenerator::postvisit( ast::CommaExpr const * expr ) {
[8941b6b]834 extension( expr );
835 output << "(";
836 if ( options.genC ) {
837 // arg1 of a comma expression is never used, so it can be safely cast
838 // to void to reduce gcc warnings.
839 ast::ptr<ast::Expr> arg1 = new ast::CastExpr( expr->location, expr->arg1 );
840 arg1->accept( *visitor );
841 } else {
842 expr->arg1->accept( *visitor );
843 }
844 output << " , ";
845 expr->arg2->accept( *visitor );
846 output << ")";
847}
848
[0bd3faf]849void CodeGenerator::postvisit( ast::TupleAssignExpr const * expr ) {
[8941b6b]850 assertf( !options.genC, "TupleAssignExpr should not reach code generation." );
851 expr->stmtExpr->accept( *visitor );
852}
853
[0bd3faf]854void CodeGenerator::postvisit( ast::UntypedTupleExpr const * expr ) {
[8941b6b]855 assertf( !options.genC, "UntypedTupleExpr should not reach code generation." );
856 extension( expr );
857 output << "[";
858 genCommaList( expr->exprs );
859 output << "]";
860}
861
[0bd3faf]862void CodeGenerator::postvisit( ast::TupleExpr const * expr ) {
[8941b6b]863 assertf( !options.genC, "TupleExpr should not reach code generation." );
864 extension( expr );
865 output << "[";
866 genCommaList( expr->exprs );
867 output << "]";
868}
869
[0bd3faf]870void CodeGenerator::postvisit( ast::TupleIndexExpr const * expr ) {
[8941b6b]871 assertf( !options.genC, "TupleIndexExpr should not reach code generation." );
872 extension( expr );
873 expr->tuple->accept( *visitor );
874 output << "." << expr->index;
875}
876
[0bd3faf]877void CodeGenerator::postvisit( ast::TypeExpr const * expr ) {
[8941b6b]878 // TODO: Should there be an assertion there?
879 if ( !options.genC ) {
880 output << genType( expr->type, "", options );
881 }
882}
883
[0bd3faf]884void CodeGenerator::postvisit( ast::AsmExpr const * expr ) {
[8941b6b]885 if ( !expr->inout.empty() ) {
886 output << "[ " << expr->inout << " ] ";
887 }
888 expr->constraint->accept( *visitor );
889 output << " ( ";
890 expr->operand->accept( *visitor );
891 output << " )";
892}
893
[0bd3faf]894void CodeGenerator::postvisit( ast::CompoundLiteralExpr const * expr ) {
[8941b6b]895 //assert( expr->result && dynamic_cast<ast::ListInit const *>( expr->init ) );
896 assert( expr->result && expr->init.as<ast::ListInit>() );
897 output << "(" << genType( expr->result, "", options ) << ")";
898 expr->init->accept( *visitor );
899}
900
[0bd3faf]901void CodeGenerator::postvisit( ast::UniqueExpr const * expr ) {
[8941b6b]902 assertf( !options.genC, "UniqueExpr should not reach code generation." );
903 output << "unq<" << expr->id << ">{ ";
904 expr->expr->accept( *visitor );
905 output << " }";
906}
907
[0bd3faf]908void CodeGenerator::postvisit( ast::StmtExpr const * expr ) {
[8941b6b]909 auto stmts = expr->stmts->kids;
910 output << "({" << endl;
911 ++indent;
912 unsigned int numStmts = stmts.size();
913 unsigned int i = 0;
914 for ( ast::ptr<ast::Stmt> const & stmt : stmts ) {
915 output << indent << printLabels( stmt->labels );
916 if ( i + 1 == numStmts ) {
917 // Last statement in a statement expression needs to be handled
918 // specially - cannot cast to void, otherwise the expression
919 // statement has no value.
920 if ( ast::ExprStmt const * exprStmt = stmt.as<ast::ExprStmt>() ) {
921 exprStmt->expr->accept( *visitor );
922 output << ";" << endl;
923 ++i;
924 break;
925 }
926 }
927 stmt->accept( *visitor );
928 output << endl;
929 if ( wantSpacing( stmt ) ) output << endl;
930 ++i;
931 }
932 --indent;
933 output << indent << "})";
934}
935
[0bd3faf]936void CodeGenerator::postvisit( ast::ConstructorExpr const * expr ) {
[8941b6b]937 assertf( !options.genC, "ConstructorExpr should not reach code generation." );
938 expr->callExpr->accept( *visitor );
939}
940
[0bd3faf]941void CodeGenerator::postvisit( ast::DeletedExpr const * expr ) {
[8941b6b]942 assertf( !options.genC, "DeletedExpr should not reach code generation." );
943 expr->expr->accept( *visitor );
944}
945
[0bd3faf]946void CodeGenerator::postvisit( ast::DefaultArgExpr const * expr ) {
[8941b6b]947 assertf( !options.genC, "DefaultArgExpr should not reach code generation." );
948 expr->expr->accept( *visitor );
949}
950
[0bd3faf]951void CodeGenerator::postvisit( ast::GenericExpr const * expr ) {
[8941b6b]952 assertf( !options.genC, "GenericExpr should not reach code generation." );
953 output << "_Generic(";
954 expr->control->accept( *visitor );
955 output << ", ";
956 unsigned int numAssocs = expr->associations.size();
957 unsigned int i = 0;
958 for ( const ast::GenericExpr::Association & assoc : expr->associations ) {
959 if ( nullptr == assoc.type ) {
960 output << "default: ";
961 } else {
962 output << genType( assoc.type, "", options ) << ": ";
963 }
964 assoc.expr->accept( *visitor );
965 ++i;
966 if ( i != numAssocs ) output << ", ";
967 }
968 output << ")";
969}
970
[0bd3faf]971void CodeGenerator::postvisit( ast::CompoundStmt const * stmt ) {
[8941b6b]972 output << "{" << endl;
973
974 ++indent;
975 for ( auto kid : stmt->kids ) {
976 output << indent << printLabels( kid->labels );
977 kid->accept( *visitor );
978 output << endl;
979 if ( wantSpacing( kid ) ) output << endl;
980 }
981 --indent;
982
983 output << indent << "}";
984}
985
[0bd3faf]986void CodeGenerator::postvisit( ast::ExprStmt const * stmt ) {
[8941b6b]987 assert( stmt );
988 // Cast the top-level expression to void to reduce gcc warnings.
989 if ( options.genC ) {
990 ast::ptr<ast::Expr> expr = new ast::CastExpr( stmt->location, stmt->expr );
991 expr->accept( *visitor );
992 } else {
993 stmt->expr->accept( *visitor );
994 }
995 output << ";";
996}
997
[0bd3faf]998void CodeGenerator::postvisit( ast::AsmStmt const * stmt ) {
[8941b6b]999 output << "asm ";
1000 if ( stmt->isVolatile ) output << "volatile ";
1001 if ( !stmt->gotoLabels.empty() ) output << "goto ";
1002 output << "( ";
1003 if ( stmt->instruction ) stmt->instruction->accept( *visitor );
1004 output << " : ";
1005 genCommaList( stmt->output );
1006 output << " : ";
1007 genCommaList( stmt->input );
1008 output << " : ";
1009 genCommaList( stmt->clobber );
1010 if ( !stmt->gotoLabels.empty() ) {
1011 output << " : ";
1012 auto it = stmt->gotoLabels.begin();
1013 while (true) {
1014 output << *it++;
1015 if ( stmt->gotoLabels.end() == it ) break;
1016 output << ", ";
1017 }
1018 }
1019 output << " );";
1020}
1021
[0bd3faf]1022void CodeGenerator::postvisit( ast::AsmDecl const * decl ) {
[8941b6b]1023 output << "asm ";
1024 ast::AsmStmt const * stmt = decl->stmt;
1025 output << "( ";
1026 if ( stmt->instruction ) stmt->instruction->accept( *visitor );
1027 output << " )";
1028}
1029
[0bd3faf]1030void CodeGenerator::postvisit( ast::DirectiveDecl const * decl ) {
[8941b6b]1031 // endl prevents spaces before the directive.
1032 output << endl << decl->stmt->directive;
1033}
1034
[0bd3faf]1035void CodeGenerator::postvisit( ast::DirectiveStmt const * stmt ) {
[8941b6b]1036 // endl prevents spaces before the directive.
1037 output << endl << stmt->directive;
1038}
1039
[0bd3faf]1040void CodeGenerator::postvisit( ast::IfStmt const * stmt ) {
[8941b6b]1041 output << "if ( ";
1042 stmt->cond->accept( *visitor );
1043 output << " ) ";
1044
1045 stmt->then->accept( *visitor );
1046
1047 if ( nullptr != stmt->else_ ) {
1048 output << " else ";
1049 stmt->else_->accept( *visitor );
1050 }
1051}
1052
[0bd3faf]1053void CodeGenerator::postvisit( ast::SwitchStmt const * stmt ) {
[8941b6b]1054 output << "switch ( ";
1055 stmt->cond->accept( *visitor );
1056 output << " ) ";
1057
[69ab896]1058 output << "{" << endl;
[8941b6b]1059 ++indent;
1060 for ( auto node : stmt->cases ) {
1061 node->accept( *visitor );
1062 }
1063 --indent;
1064 output << indent << "}";
1065}
1066
[0bd3faf]1067void CodeGenerator::postvisit( ast::CaseClause const * clause ) {
[8941b6b]1068 updateLocation( clause );
1069 output << indent;
1070 if ( clause->isDefault() ) {
1071 output << "default";
1072 } else {
1073 output << "case ";
1074 clause->cond->accept( *visitor );
1075 }
1076 output << ":" << endl;
1077
1078 ++indent;
1079 for ( auto stmt : clause->stmts ) {
1080 output << indent << printLabels( stmt->labels ) ;
1081 stmt->accept( *visitor );
1082 output << endl;
1083 }
1084 --indent;
1085}
1086
[0bd3faf]1087void CodeGenerator::postvisit( ast::BranchStmt const * stmt ) {
[8941b6b]1088 switch ( stmt->kind ) {
1089 case ast::BranchStmt::Goto:
1090 if ( !stmt->target.empty() ) {
1091 output << "goto " << stmt->target;
1092 } else if ( nullptr != stmt->computedTarget ) {
1093 output << "goto *";
1094 stmt->computedTarget->accept( *visitor );
1095 }
1096 break;
1097 case ast::BranchStmt::Break:
1098 output << "break";
1099 break;
1100 case ast::BranchStmt::Continue:
1101 output << "continue";
1102 break;
1103 case ast::BranchStmt::FallThrough:
1104 case ast::BranchStmt::FallThroughDefault:
[d96f7c4]1105 assertf( !options.genC, "fallthrough should not reach code generation." );
1106 output << "fallthrough";
[9506c70]1107 if ( ast::BranchStmt::FallThroughDefault == stmt->kind ) {
1108 assertf( stmt->target.empty(), "fallthough default should not have a target." );
1109 output << " default";
1110 }
[8941b6b]1111 break;
1112 default:
1113 assertf( false, "Bad BranchStmt value." );
1114 }
[9506c70]1115 // Print branch target for labelled break/continue/fallthrough.
1116 if ( ast::BranchStmt::Goto != stmt->kind && !stmt->target.empty() ) {
1117 assertf( !options.genC, "labelled branch should not reach code generation. %s", stmt->target.name.c_str() );
1118 output << " " << stmt->target;
[8941b6b]1119 }
1120 output << ";";
1121}
1122
[0bd3faf]1123void CodeGenerator::postvisit( ast::ReturnStmt const * stmt ) {
[8941b6b]1124 output << "return ";
1125 if ( stmt->expr ) stmt->expr->accept( *visitor );
1126 output << ";";
1127}
1128
[0bd3faf]1129void CodeGenerator::postvisit( ast::ThrowStmt const * stmt ) {
[8941b6b]1130 assertf( !options.genC, "ThrowStmt should not reach code generation." );
1131
1132 output << ((stmt->kind == ast::Terminate) ? "throw" : "throwResume");
1133 if ( stmt->expr ) {
1134 output << " ";
1135 stmt->expr->accept( *visitor );
1136 }
1137 if ( stmt->target ) {
1138 output << " _At ";
1139 stmt->target->accept( *visitor );
1140 }
1141 output << ";";
1142}
1143
[550446f]1144void CodeGenerator::postvisit( ast::TryStmt const * stmt ) {
1145 assertf( !options.genC, "TryStmt should not reach code generation." );
1146
1147 output << "try ";
1148 stmt->body->accept( *visitor );
1149 for ( ast::ptr<ast::CatchClause> const & handler : stmt->handlers ) {
1150 handler->accept( *visitor );
1151 }
1152 if ( stmt->finally ) stmt->finally->accept( *visitor );
1153}
1154
[0bd3faf]1155void CodeGenerator::postvisit( ast::CatchClause const * stmt ) {
[8941b6b]1156 assertf( !options.genC, "CatchClause should not reach code generation." );
1157
[550446f]1158 output << ((stmt->kind == ast::Terminate) ? " catch " : " catchResume ");
[8941b6b]1159 output << "( ";
1160 stmt->decl->accept( *visitor );
1161 if ( stmt->cond ) {
1162 output << " ; ";
1163 stmt->cond->accept( *visitor );
1164 }
1165 output << " ) ";
1166 stmt->body->accept( *visitor );
1167}
1168
[550446f]1169void CodeGenerator::postvisit( ast::FinallyClause const * clause ) {
1170 assertf( !options.genC, "FinallyClause should not reach code generation." );
1171
1172 output << " finally ";
1173 clause->body->accept( *visitor );
1174}
1175
[0bd3faf]1176void CodeGenerator::postvisit( ast::WaitForStmt const * stmt ) {
[8941b6b]1177 assertf( !options.genC, "WaitforStmt should not reach code generation." );
1178
1179 bool first = true;
1180 for ( ast::ptr<ast::WaitForClause> const & clause : stmt->clauses ) {
1181 if (first) { output << "or "; first = false; }
1182 if ( clause->when_cond ) {
1183 output << "when(";
[61e362f]1184 clause->when_cond->accept( *visitor );
[8941b6b]1185 output << ") ";
1186 }
1187 output << "waitfor(";
1188 clause->target->accept( *visitor );
1189 for ( ast::ptr<ast::Expr> const & expr : clause->target_args ) {
1190 output << ",";
1191 expr->accept( *visitor );
1192 }
1193 output << ") ";
1194 clause->stmt->accept( *visitor );
1195 }
1196
1197 if ( stmt->timeout_stmt ) {
1198 output << "or ";
1199 if ( stmt->timeout_cond ) {
1200 output << "when(";
1201 stmt->timeout_cond->accept( *visitor );
1202 output << ") ";
1203 }
1204 output << "timeout(";
1205 stmt->timeout_time->accept( *visitor );
1206 output << ") ";
1207 stmt->timeout_stmt->accept( *visitor );
1208 }
1209
1210 if ( stmt->else_stmt ) {
1211 output << "or ";
1212 if ( stmt->else_cond ) {
1213 output << "when(";
1214 stmt->else_cond->accept( *visitor );
1215 output << ")";
1216 }
1217 output << "else ";
1218 stmt->else_stmt->accept( *visitor );
1219 }
1220}
1221
[0bd3faf]1222void CodeGenerator::postvisit( ast::WithStmt const * stmt ) {
[8941b6b]1223 assertf( !options.genC, "WithStmt should not reach code generation." );
1224
1225 output << "with ( ";
1226 genCommaList( stmt->exprs );
1227 output << " ) ";
1228 stmt->stmt->accept( *visitor );
1229}
1230
[0bd3faf]1231void CodeGenerator::postvisit( ast::WhileDoStmt const * stmt ) {
[8941b6b]1232 if ( stmt->isDoWhile ) {
1233 output << "do";
1234 } else {
1235 output << "while (";
1236 stmt->cond->accept( *visitor );
1237 output << ")";
1238 }
1239 output << " ";
1240
[0bd3faf]1241 output << CodeGenerator::printLabels( stmt->body->labels );
[8941b6b]1242 stmt->body->accept( *visitor );
1243
1244 if ( stmt->isDoWhile ) {
1245 output << " while (";
1246 stmt->cond->accept( *visitor );
[88bc876]1247 output << ( ( nullptr == stmt->else_ ) ? ");" : ")" );
1248 }
1249 if ( stmt->else_ ) {
1250 output << " else ";
1251 stmt->else_->accept( *visitor );
[8941b6b]1252 }
1253}
1254
[0bd3faf]1255void CodeGenerator::postvisit( ast::ForStmt const * stmt ) {
[8941b6b]1256 // Initializer is always hoised so don't generate it.
1257 // TODO: Do an assertion check?
1258 output << "for (;";
1259
1260 if ( nullptr != stmt->cond ) {
1261 stmt->cond->accept( *visitor );
1262 }
1263 output << ";";
1264
1265 if ( nullptr != stmt->inc ) {
1266 // cast the top-level expression to void to reduce gcc warnings.
1267 ast::Expr * expr = new ast::CastExpr( stmt->inc );
1268 expr->accept( *visitor );
1269 }
1270 output << ") ";
1271
1272 if ( nullptr != stmt->body ) {
1273 output << printLabels( stmt->body->labels );
1274 stmt->body->accept( *visitor );
1275 }
[88bc876]1276
1277 if ( nullptr != stmt->else_ ) {
1278 assertf( !options.genC, "Loop else should not reach code generation." );
1279 output << " else ";
1280 stmt->else_->accept( *visitor );
1281 }
[8941b6b]1282}
1283
[0bd3faf]1284void CodeGenerator::postvisit( ast::NullStmt const * ) {
[8941b6b]1285 output << "/* null statement */ ;";
1286}
1287
[0bd3faf]1288void CodeGenerator::postvisit( ast::DeclStmt const * stmt ) {
[8941b6b]1289 stmt->decl->accept( *visitor );
1290
1291 if ( doSemicolon( stmt->decl ) ) output << ";";
1292}
1293
[0bd3faf]1294void CodeGenerator::postvisit( ast::ImplicitCtorDtorStmt const * stmt ) {
[8941b6b]1295 assertf( !options.genC, "ImplicitCtorCtorStmt should not reach code generation." );
1296 stmt->callStmt->accept( *visitor );
1297}
1298
[0bd3faf]1299void CodeGenerator::postvisit( ast::MutexStmt const * stmt ) {
[8941b6b]1300 assertf( !options.genC, "MutexStmt should not reach code generation." );
1301 // TODO: But this isn't what a mutex statement looks like.
1302 stmt->stmt->accept( *visitor );
1303}
1304
[6e7ed0aa]1305std::string genName( ast::DeclWithType const * decl ) {
1306 if ( const OperatorInfo * opInfo = operatorLookup( decl->name ) ) {
1307 return opInfo->outputName;
1308 } else {
1309 return decl->name;
1310 }
1311}
[8941b6b]1312
1313} // namespace CodeGen
Note: See TracBrowser for help on using the repository browser.