source: src/Concurrency/Keywords.cc@ 68f9c43

new-env with_gc
Last change on this file since 68f9c43 was 68f9c43, checked in by Aaron Moss <a3moss@…>, 8 years ago

First pass at delete removal

  • Property mode set to 100644
File size: 19.8 KB
RevLine 
[64adb03]1//
2// Cforall Version 1.0.0 Copyright (C) 2016 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//
7// Keywords.cc --
8//
9// Author : Thierry Delisle
10// Created On : Mon Mar 13 12:41:22 2017
11// Last Modified By :
12// Last Modified On :
[6b0b624]13// Update Count : 5
[64adb03]14//
15
16#include "Concurrency/Keywords.h"
17
[bf2438c]18#include <cassert> // for assert
19#include <string> // for string, operator==
20
[2065609]21#include "Common/PassVisitor.h" // for PassVisitor
[bf2438c]22#include "Common/SemanticError.h" // for SemanticError
23#include "Common/utility.h" // for deleteAll, map_range
[bff227f]24#include "CodeGen/OperatorTable.h" // for isConstructor
25#include "InitTweak/InitTweak.h" // for getPointerBase
[bf2438c]26#include "Parser/LinkageSpec.h" // for Cforall
27#include "SynTree/Constant.h" // for Constant
28#include "SynTree/Declaration.h" // for StructDecl, FunctionDecl, ObjectDecl
29#include "SynTree/Expression.h" // for VariableExpr, ConstantExpr, Untype...
30#include "SynTree/Initializer.h" // for SingleInit, ListInit, Initializer ...
31#include "SynTree/Label.h" // for Label
32#include "SynTree/Statement.h" // for CompoundStmt, DeclStmt, ExprStmt
33#include "SynTree/Type.h" // for StructInstType, Type, PointerType
34#include "SynTree/Visitor.h" // for Visitor, acceptAll
35
36class Attribute;
[64adb03]37
38namespace Concurrency {
39 //=============================================================================================
[2065609]40 // Pass declarations
[64adb03]41 //=============================================================================================
42
[bcda04c]43 //-----------------------------------------------------------------------------
44 //Handles sue type declarations :
45 // sue MyType { struct MyType {
46 // int data; int data;
47 // a_struct_t more_data; a_struct_t more_data;
48 // => NewField_t newField;
49 // }; };
50 // static inline NewField_t * getter_name( MyType * this ) { return &this->newField; }
51 //
[2065609]52 class ConcurrentSueKeyword : public WithDeclsToAdd {
[bcda04c]53 public:
54
[bd4d011]55 ConcurrentSueKeyword( std::string&& type_name, std::string&& field_name, std::string&& getter_name, std::string&& context_error, bool needs_main ) :
56 type_name( type_name ), field_name( field_name ), getter_name( getter_name ), context_error( context_error ), needs_main( needs_main ) {}
[bcda04c]57
58 virtual ~ConcurrentSueKeyword() {}
59
[2065609]60 void postvisit( StructDecl * decl );
[bcda04c]61
62 void handle( StructDecl * );
63 FunctionDecl * forwardDeclare( StructDecl * );
64 ObjectDecl * addField( StructDecl * );
[2f9a722]65 void addRoutines( ObjectDecl *, FunctionDecl * );
[bcda04c]66
67 virtual bool is_target( StructDecl * decl ) = 0;
68
69 private:
70 const std::string type_name;
71 const std::string field_name;
72 const std::string getter_name;
73 const std::string context_error;
[bd4d011]74 bool needs_main;
[bcda04c]75
76 StructDecl* type_decl = nullptr;
77 };
78
79
[64adb03]80 //-----------------------------------------------------------------------------
81 //Handles thread type declarations :
82 // thread Mythread { struct MyThread {
83 // int data; int data;
84 // a_struct_t more_data; a_struct_t more_data;
85 // => thread_desc __thrd_d;
86 // }; };
87 // static inline thread_desc * get_thread( MyThread * this ) { return &this->__thrd_d; }
88 //
[bcda04c]89 class ThreadKeyword final : public ConcurrentSueKeyword {
[64adb03]90 public:
91
[bcda04c]92 ThreadKeyword() : ConcurrentSueKeyword(
93 "thread_desc",
94 "__thrd",
95 "get_thread",
[bd4d011]96 "thread keyword requires threads to be in scope, add #include <thread>",
97 true
[bcda04c]98 )
99 {}
100
101 virtual ~ThreadKeyword() {}
102
103 virtual bool is_target( StructDecl * decl ) override final { return decl->is_thread(); }
104
105 static void implement( std::list< Declaration * > & translationUnit ) {
[2065609]106 PassVisitor< ThreadKeyword > impl;
107 acceptAll( translationUnit, impl );
[bcda04c]108 }
[64adb03]109 };
110
111 //-----------------------------------------------------------------------------
112 //Handles coroutine type declarations :
113 // coroutine MyCoroutine { struct MyCoroutine {
114 // int data; int data;
115 // a_struct_t more_data; a_struct_t more_data;
116 // => coroutine_desc __cor_d;
117 // }; };
118 // static inline coroutine_desc * get_coroutine( MyCoroutine * this ) { return &this->__cor_d; }
119 //
[bcda04c]120 class CoroutineKeyword final : public ConcurrentSueKeyword {
[64adb03]121 public:
122
[bcda04c]123 CoroutineKeyword() : ConcurrentSueKeyword(
124 "coroutine_desc",
125 "__cor",
126 "get_coroutine",
[bd4d011]127 "coroutine keyword requires coroutines to be in scope, add #include <coroutine>",
128 true
[bcda04c]129 )
130 {}
[b32ada31]131
[bcda04c]132 virtual ~CoroutineKeyword() {}
133
134 virtual bool is_target( StructDecl * decl ) override final { return decl->is_coroutine(); }
[b32ada31]135
136 static void implement( std::list< Declaration * > & translationUnit ) {
[2065609]137 PassVisitor< CoroutineKeyword > impl;
138 acceptAll( translationUnit, impl );
[b32ada31]139 }
[64adb03]140 };
141
142 //-----------------------------------------------------------------------------
143 //Handles monitor type declarations :
144 // monitor MyMonitor { struct MyMonitor {
145 // int data; int data;
146 // a_struct_t more_data; a_struct_t more_data;
147 // => monitor_desc __mon_d;
148 // }; };
149 // static inline monitor_desc * get_coroutine( MyMonitor * this ) { return &this->__cor_d; }
150 //
[bcda04c]151 class MonitorKeyword final : public ConcurrentSueKeyword {
[64adb03]152 public:
153
[bcda04c]154 MonitorKeyword() : ConcurrentSueKeyword(
155 "monitor_desc",
156 "__mon",
157 "get_monitor",
[bd4d011]158 "monitor keyword requires monitors to be in scope, add #include <monitor>",
159 false
[bcda04c]160 )
161 {}
162
163 virtual ~MonitorKeyword() {}
164
165 virtual bool is_target( StructDecl * decl ) override final { return decl->is_monitor(); }
166
167 static void implement( std::list< Declaration * > & translationUnit ) {
[2065609]168 PassVisitor< MonitorKeyword > impl;
169 acceptAll( translationUnit, impl );
[bcda04c]170 }
[64adb03]171 };
172
173 //-----------------------------------------------------------------------------
174 //Handles mutex routines definitions :
175 // void foo( A * mutex a, B * mutex b, int i ) { void foo( A * a, B * b, int i ) {
[9243cc91]176 // monitor_desc * __monitors[] = { get_monitor(a), get_monitor(b) };
[64adb03]177 // monitor_guard_t __guard = { __monitors, 2 };
178 // /*Some code*/ => /*Some code*/
179 // } }
180 //
[2065609]181 class MutexKeyword final {
[64adb03]182 public:
183
[2065609]184 void postvisit( FunctionDecl * decl );
185 void postvisit( StructDecl * decl );
[64adb03]186
187 std::list<DeclarationWithType*> findMutexArgs( FunctionDecl* );
188 void validate( DeclarationWithType * );
[549c006]189 void addDtorStatments( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &);
[97e3296]190 void addStatments( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &);
[64adb03]191
192 static void implement( std::list< Declaration * > & translationUnit ) {
[2065609]193 PassVisitor< MutexKeyword > impl;
[64adb03]194 acceptAll( translationUnit, impl );
195 }
[9243cc91]196
197 private:
198 StructDecl* monitor_decl = nullptr;
[ef42b143]199 StructDecl* guard_decl = nullptr;
[549c006]200 StructDecl* dtor_guard_decl = nullptr;
[97e3296]201
202 static std::unique_ptr< Type > generic_func;
[64adb03]203 };
204
[97e3296]205 std::unique_ptr< Type > MutexKeyword::generic_func = std::unique_ptr< Type >(
206 new FunctionType(
207 noQualifiers,
208 true
209 )
210 );
211
[bd4d011]212 //-----------------------------------------------------------------------------
213 //Handles mutex routines definitions :
214 // void foo( A * mutex a, B * mutex b, int i ) { void foo( A * a, B * b, int i ) {
215 // monitor_desc * __monitors[] = { get_monitor(a), get_monitor(b) };
216 // monitor_guard_t __guard = { __monitors, 2 };
217 // /*Some code*/ => /*Some code*/
218 // } }
219 //
[2065609]220 class ThreadStarter final {
[bd4d011]221 public:
222
[2065609]223 void postvisit( FunctionDecl * decl );
[549c006]224 void previsit ( StructDecl * decl );
[bd4d011]225
226 void addStartStatement( FunctionDecl * decl, DeclarationWithType * param );
227
228 static void implement( std::list< Declaration * > & translationUnit ) {
[2065609]229 PassVisitor< ThreadStarter > impl;
[bd4d011]230 acceptAll( translationUnit, impl );
231 }
[549c006]232
233 private :
234 bool thread_ctor_seen = false;
235 StructDecl * thread_decl = nullptr;
[bd4d011]236 };
237
[64adb03]238 //=============================================================================================
239 // General entry routine
240 //=============================================================================================
241 void applyKeywords( std::list< Declaration * > & translationUnit ) {
242 ThreadKeyword ::implement( translationUnit );
243 CoroutineKeyword ::implement( translationUnit );
244 MonitorKeyword ::implement( translationUnit );
[bcda04c]245 }
246
247 void implementMutexFuncs( std::list< Declaration * > & translationUnit ) {
[64adb03]248 MutexKeyword ::implement( translationUnit );
249 }
250
[bcda04c]251 void implementThreadStarter( std::list< Declaration * > & translationUnit ) {
[bd4d011]252 ThreadStarter ::implement( translationUnit );
[bcda04c]253 }
254
[b32ada31]255 //=============================================================================================
[bcda04c]256 // Generic keyword implementation
[b32ada31]257 //=============================================================================================
[2db79e5]258 void fixupGenerics(FunctionType * func, StructDecl * decl) {
259 cloneAll(decl->parameters, func->forall);
260 for ( TypeDecl * td : func->forall ) {
261 strict_dynamic_cast<StructInstType*>(
262 func->parameters.front()->get_type()->stripReferences()
263 )->parameters.push_back(
264 new TypeExpr( new TypeInstType( noQualifiers, td->name, td ) )
265 );
266 }
267 }
268
[2065609]269 void ConcurrentSueKeyword::postvisit(StructDecl * decl) {
[9f5ecf5]270 if( decl->name == type_name && decl->body ) {
[bcda04c]271 assert( !type_decl );
272 type_decl = decl;
[b32ada31]273 }
[bcda04c]274 else if ( is_target(decl) ) {
[b32ada31]275 handle( decl );
276 }
277 }
278
[bcda04c]279 void ConcurrentSueKeyword::handle( StructDecl * decl ) {
[9f5ecf5]280 if( ! decl->body ) return;
[b32ada31]281
[a16764a6]282 if( !type_decl ) SemanticError( decl, context_error );
[b32ada31]283
[bcda04c]284 FunctionDecl * func = forwardDeclare( decl );
285 ObjectDecl * field = addField( decl );
[2f9a722]286 addRoutines( field, func );
[b32ada31]287 }
288
[bcda04c]289 FunctionDecl * ConcurrentSueKeyword::forwardDeclare( StructDecl * decl ) {
290
291 StructDecl * forward = decl->clone();
292 forward->set_body( false );
293 forward->get_members().clear();
294
[bd4d011]295 FunctionType * get_type = new FunctionType( noQualifiers, false );
[bcda04c]296 ObjectDecl * this_decl = new ObjectDecl(
297 "this",
[ba3706f]298 noStorageClasses,
[b32ada31]299 LinkageSpec::Cforall,
300 nullptr,
[83a071f9]301 new ReferenceType(
[b32ada31]302 noQualifiers,
[bcda04c]303 new StructInstType(
304 noQualifiers,
305 decl
306 )
[b32ada31]307 ),
308 nullptr
309 );
310
[2db79e5]311 get_type->get_parameters().push_back( this_decl->clone() );
[bd4d011]312 get_type->get_returnVals().push_back(
[e04b636]313 new ObjectDecl(
314 "ret",
[ba3706f]315 noStorageClasses,
[e04b636]316 LinkageSpec::Cforall,
317 nullptr,
318 new PointerType(
319 noQualifiers,
320 new StructInstType(
321 noQualifiers,
[bcda04c]322 type_decl
[e04b636]323 )
324 ),
325 nullptr
326 )
327 );
[2db79e5]328 fixupGenerics(get_type, decl);
[b32ada31]329
[bcda04c]330 FunctionDecl * get_decl = new FunctionDecl(
331 getter_name,
332 Type::Static,
333 LinkageSpec::Cforall,
[bd4d011]334 get_type,
[bcda04c]335 nullptr,
336 noAttributes,
337 Type::Inline
338 );
339
[bd4d011]340 FunctionDecl * main_decl = nullptr;
341
342 if( needs_main ) {
343 FunctionType * main_type = new FunctionType( noQualifiers, false );
[bf2438c]344
[bd4d011]345 main_type->get_parameters().push_back( this_decl->clone() );
346
347 main_decl = new FunctionDecl(
348 "main",
[ba3706f]349 noStorageClasses,
[bd4d011]350 LinkageSpec::Cforall,
351 main_type,
352 nullptr
353 );
[2db79e5]354 fixupGenerics(main_type, decl);
[bd4d011]355 }
356
[2065609]357 declsToAddBefore.push_back( forward );
358 if( needs_main ) declsToAddBefore.push_back( main_decl );
359 declsToAddBefore.push_back( get_decl );
[bcda04c]360
361 return get_decl;
362 }
363
364 ObjectDecl * ConcurrentSueKeyword::addField( StructDecl * decl ) {
365 ObjectDecl * field = new ObjectDecl(
366 field_name,
[ba3706f]367 noStorageClasses,
[bcda04c]368 LinkageSpec::Cforall,
369 nullptr,
370 new StructInstType(
371 noQualifiers,
372 type_decl
373 ),
374 nullptr
375 );
376
377 decl->get_members().push_back( field );
378
379 return field;
380 }
381
[2f9a722]382 void ConcurrentSueKeyword::addRoutines( ObjectDecl * field, FunctionDecl * func ) {
[ba3706f]383 CompoundStmt * statement = new CompoundStmt();
[bf2438c]384 statement->push_back(
[b32ada31]385 new ReturnStmt(
[e04b636]386 new AddressExpr(
[bcda04c]387 new MemberExpr(
388 field,
[2db79e5]389 new CastExpr(
390 new VariableExpr( func->get_functionType()->get_parameters().front() ),
391 func->get_functionType()->get_parameters().front()->get_type()->stripReferences()->clone()
392 )
[e04b636]393 )
[b32ada31]394 )
395 )
396 );
397
[bcda04c]398 FunctionDecl * get_decl = func->clone();
399
400 get_decl->set_statements( statement );
[e04b636]401
402 declsToAddAfter.push_back( get_decl );
403
[bcda04c]404 // get_decl->fixUniqueId();
[b32ada31]405 }
406
[64adb03]407 //=============================================================================================
408 // Mutex keyword implementation
409 //=============================================================================================
[97e3296]410
[2065609]411 void MutexKeyword::postvisit(FunctionDecl* decl) {
[102a58b]412
[64adb03]413 std::list<DeclarationWithType*> mutexArgs = findMutexArgs( decl );
414 if( mutexArgs.empty() ) return;
415
[a16764a6]416 if( CodeGen::isConstructor(decl->name) ) SemanticError( decl, "constructors cannot have mutex parameters" );
[549c006]417
418 bool isDtor = CodeGen::isDestructor( decl->name );
419
[a16764a6]420 if( isDtor && mutexArgs.size() != 1 ) SemanticError( decl, "destructors can only have 1 mutex argument" );
[549c006]421
[64adb03]422 for(auto arg : mutexArgs) {
423 validate( arg );
424 }
425
426 CompoundStmt* body = decl->get_statements();
427 if( ! body ) return;
428
[a16764a6]429 if( !monitor_decl || !guard_decl || !dtor_guard_decl )
430 SemanticError( decl, "mutex keyword requires monitors to be in scope, add #include <monitor>" );
[b32ada31]431
[549c006]432 if( isDtor ) {
433 addDtorStatments( decl, body, mutexArgs );
434 }
435 else {
436 addStatments( decl, body, mutexArgs );
437 }
[64adb03]438 }
439
[2065609]440 void MutexKeyword::postvisit(StructDecl* decl) {
[102a58b]441
[9f5ecf5]442 if( decl->name == "monitor_desc" ) {
[9243cc91]443 assert( !monitor_decl );
444 monitor_decl = decl;
445 }
[9f5ecf5]446 else if( decl->name == "monitor_guard_t" ) {
[ef42b143]447 assert( !guard_decl );
448 guard_decl = decl;
449 }
[549c006]450 else if( decl->name == "monitor_dtor_guard_t" ) {
451 assert( !dtor_guard_decl );
452 dtor_guard_decl = decl;
453 }
[9243cc91]454 }
455
[64adb03]456 std::list<DeclarationWithType*> MutexKeyword::findMutexArgs( FunctionDecl* decl ) {
457 std::list<DeclarationWithType*> mutexArgs;
458
459 for( auto arg : decl->get_functionType()->get_parameters()) {
460 //Find mutex arguments
461 Type* ty = arg->get_type();
[615a096]462 if( ! ty->get_mutex() ) continue;
[64adb03]463
464 //Append it to the list
465 mutexArgs.push_back( arg );
466 }
467
468 return mutexArgs;
469 }
470
471 void MutexKeyword::validate( DeclarationWithType * arg ) {
472 Type* ty = arg->get_type();
473
474 //Makes sure it's not a copy
[870d1f0]475 ReferenceType* rty = dynamic_cast< ReferenceType * >( ty );
[a16764a6]476 if( ! rty ) SemanticError( arg, "Mutex argument must be of reference type " );
[64adb03]477
478 //Make sure the we are pointing directly to a type
[83a071f9]479 Type* base = rty->get_base();
[a16764a6]480 if( dynamic_cast< ReferenceType * >( base ) ) SemanticError( arg, "Mutex argument have exactly one level of indirection " );
481 if( dynamic_cast< PointerType * >( base ) ) SemanticError( arg, "Mutex argument have exactly one level of indirection " );
[64adb03]482
483 //Make sure that typed isn't mutex
[a16764a6]484 if( base->get_mutex() ) SemanticError( arg, "mutex keyword may only appear once per argument " );
[64adb03]485 }
486
[549c006]487 void MutexKeyword::addDtorStatments( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) {
488 Type * arg_type = args.front()->get_type()->clone();
489 arg_type->set_mutex( false );
490
491 ObjectDecl * monitors = new ObjectDecl(
492 "__monitor",
[ba3706f]493 noStorageClasses,
[549c006]494 LinkageSpec::Cforall,
495 nullptr,
496 new PointerType(
497 noQualifiers,
498 new StructInstType(
499 noQualifiers,
500 monitor_decl
501 )
502 ),
503 new SingleInit( new UntypedExpr(
504 new NameExpr( "get_monitor" ),
505 { new CastExpr( new VariableExpr( args.front() ), arg_type ) }
506 ))
507 );
508
509 assert(generic_func);
510
511 //in reverse order :
512 // monitor_guard_t __guard = { __monitors, #, func };
513 body->push_front(
[ba3706f]514 new DeclStmt( new ObjectDecl(
[549c006]515 "__guard",
[ba3706f]516 noStorageClasses,
[549c006]517 LinkageSpec::Cforall,
518 nullptr,
519 new StructInstType(
520 noQualifiers,
521 dtor_guard_decl
522 ),
523 new ListInit(
524 {
525 new SingleInit( new AddressExpr( new VariableExpr( monitors ) ) ),
526 new SingleInit( new CastExpr( new VariableExpr( func ), generic_func->clone() ) )
527 },
528 noDesignators,
529 true
530 )
531 ))
532 );
533
534 //monitor_desc * __monitors[] = { get_monitor(a), get_monitor(b) };
[ba3706f]535 body->push_front( new DeclStmt( monitors) );
[549c006]536 }
537
[97e3296]538 void MutexKeyword::addStatments( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) {
[9243cc91]539 ObjectDecl * monitors = new ObjectDecl(
540 "__monitors",
[ba3706f]541 noStorageClasses,
[9243cc91]542 LinkageSpec::Cforall,
543 nullptr,
544 new ArrayType(
545 noQualifiers,
546 new PointerType(
547 noQualifiers,
548 new StructInstType(
549 noQualifiers,
550 monitor_decl
551 )
552 ),
553 new ConstantExpr( Constant::from_ulong( args.size() ) ),
554 false,
555 false
556 ),
557 new ListInit(
[bd41764]558 map_range < std::list<Initializer*> > ( args, [](DeclarationWithType * var ){
[cb0e6de]559 Type * type = var->get_type()->clone();
560 type->set_mutex( false );
[9243cc91]561 return new SingleInit( new UntypedExpr(
562 new NameExpr( "get_monitor" ),
[cb0e6de]563 { new CastExpr( new VariableExpr( var ), type ) }
[9243cc91]564 ) );
565 })
566 )
567 );
568
[97e3296]569 assert(generic_func);
570
[64adb03]571 //in reverse order :
[97e3296]572 // monitor_guard_t __guard = { __monitors, #, func };
[64adb03]573 body->push_front(
[ba3706f]574 new DeclStmt( new ObjectDecl(
[64adb03]575 "__guard",
[ba3706f]576 noStorageClasses,
[64adb03]577 LinkageSpec::Cforall,
578 nullptr,
579 new StructInstType(
580 noQualifiers,
[ef42b143]581 guard_decl
[64adb03]582 ),
583 new ListInit(
584 {
[9243cc91]585 new SingleInit( new VariableExpr( monitors ) ),
[97e3296]586 new SingleInit( new ConstantExpr( Constant::from_ulong( args.size() ) ) ),
587 new SingleInit( new CastExpr( new VariableExpr( func ), generic_func->clone() ) )
[ef42b143]588 },
589 noDesignators,
590 true
[64adb03]591 )
592 ))
593 );
594
[ef42b143]595 //monitor_desc * __monitors[] = { get_monitor(a), get_monitor(b) };
[ba3706f]596 body->push_front( new DeclStmt( monitors) );
[64adb03]597 }
[bd4d011]598
599 //=============================================================================================
600 // General entry routine
601 //=============================================================================================
[549c006]602 void ThreadStarter::previsit( StructDecl * decl ) {
603 if( decl->name == "thread_desc" && decl->body ) {
604 assert( !thread_decl );
605 thread_decl = decl;
606 }
607 }
608
[2065609]609 void ThreadStarter::postvisit(FunctionDecl * decl) {
[9f5ecf5]610 if( ! CodeGen::isConstructor(decl->name) ) return;
[bd4d011]611
[549c006]612 Type * typeof_this = InitTweak::getTypeofThis(decl->type);
613 StructInstType * ctored_type = dynamic_cast< StructInstType * >( typeof_this );
614 if( ctored_type && ctored_type->baseStruct == thread_decl ) {
615 thread_ctor_seen = true;
616 }
617
[bd4d011]618 DeclarationWithType * param = decl->get_functionType()->get_parameters().front();
[ce8c12f]619 auto type = dynamic_cast< StructInstType * >( InitTweak::getPointerBase( param->get_type() ) );
[bd4d011]620 if( type && type->get_baseStruct()->is_thread() ) {
[549c006]621 if( !thread_decl || !thread_ctor_seen ) {
[a16764a6]622 SemanticError( type->get_baseStruct()->location, "thread keyword requires threads to be in scope, add #include <thread>");
[549c006]623 }
624
[bd4d011]625 addStartStatement( decl, param );
626 }
627 }
628
629 void ThreadStarter::addStartStatement( FunctionDecl * decl, DeclarationWithType * param ) {
630 CompoundStmt * stmt = decl->get_statements();
631
632 if( ! stmt ) return;
633
[bf2438c]634 stmt->push_back(
[bd4d011]635 new ExprStmt(
636 new UntypedExpr(
637 new NameExpr( "__thrd_start" ),
638 { new VariableExpr( param ) }
639 )
640 )
641 );
642 }
[68fe077a]643};
[6b0b624]644
645// Local Variables: //
646// mode: c //
647// tab-width: 4 //
648// End: //
Note: See TracBrowser for help on using the repository browser.