source: src/Validate/Autogen.cpp@ 3322180

ADT ast-experimental pthread-emulation qualifiedEnum
Last change on this file since 3322180 was 3322180, checked in by Thierry Delisle <tdelisle@…>, 3 years ago

Fix enum assignment warning

  • Property mode set to 100644
File size: 27.1 KB
Line 
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//
7// Autogen.cpp -- Generate automatic routines for data types.
8//
9// Author : Andrew Beach
10// Created On : Thu Dec 2 13:44:00 2021
11// Last Modified By : Andrew Beach
12// Last Modified On : Thr Jan 27 9:29:00 2022
13// Update Count : 1
14//
15
16#include "Autogen.hpp"
17
18#include <algorithm> // for count_if
19#include <cassert> // for strict_dynamic_cast, assert, assertf
20#include <iterator> // for back_insert_iterator, back_inserter
21#include <list> // for list, _List_iterator, list<>::iter...
22#include <set> // for set, _Rb_tree_const_iterator
23#include <utility> // for pair
24#include <vector> // for vector
25
26#include "AST/Attribute.hpp"
27#include "AST/Decl.hpp"
28#include "AST/DeclReplacer.hpp"
29#include "AST/Expr.hpp"
30#include "AST/Pass.hpp"
31#include "AST/Stmt.hpp"
32#include "AST/SymbolTable.hpp"
33#include "CodeGen/OperatorTable.h" // for isCtorDtor, isCtorDtorAssign
34#include "Common/ScopedMap.h" // for ScopedMap<>::const_iterator, Scope...
35#include "Common/utility.h" // for cloneAll, operator+
36#include "GenPoly/ScopedSet.h" // for ScopedSet, ScopedSet<>::iterator
37#include "InitTweak/GenInit.h" // for fixReturnStatements
38#include "InitTweak/InitTweak.h" // for isAssignment, isCopyConstructor
39#include "SymTab/Mangler.h" // for Mangler
40#include "CompilationState.h"
41
42// TODO: The other new ast function should be moved over to this file.
43#include "SymTab/Autogen.h"
44
45namespace Validate {
46
47namespace {
48
49// --------------------------------------------------------------------------
50struct AutogenerateRoutines_new final :
51 public ast::WithDeclsToAdd<>,
52 public ast::WithShortCircuiting {
53 void previsit( const ast::EnumDecl * enumDecl );
54 void previsit( const ast::StructDecl * structDecl );
55 void previsit( const ast::UnionDecl * structDecl );
56 void previsit( const ast::TypeDecl * typeDecl );
57 void previsit( const ast::TraitDecl * traitDecl );
58 void previsit( const ast::FunctionDecl * functionDecl );
59 void postvisit( const ast::FunctionDecl * functionDecl );
60
61private:
62 // Current level of nested functions.
63 unsigned int functionNesting = 0;
64};
65
66// --------------------------------------------------------------------------
67/// Class used to generate functions for a particular declaration.
68/// Note it isn't really stored, it is just a class for organization and to
69/// help pass around some of the common arguments.
70class FuncGenerator {
71public:
72 std::list<ast::ptr<ast::Decl>> forwards;
73 std::list<ast::ptr<ast::Decl>> definitions;
74
75 FuncGenerator( const ast::Type * type, unsigned int functionNesting ) :
76 type( type ), functionNesting( functionNesting )
77 {}
78
79 /// Generate functions (and forward decls.) and append them to the list.
80 void generateAndAppendFunctions( std::list<ast::ptr<ast::Decl>> & );
81
82 virtual bool shouldAutogen() const = 0;
83protected:
84 const ast::Type * type;
85 unsigned int functionNesting;
86 ast::Linkage::Spec proto_linkage = ast::Linkage::AutoGen;
87
88 // Internal helpers:
89 void genStandardFuncs();
90 void produceDecl( const ast::FunctionDecl * decl );
91 void produceForwardDecl( const ast::FunctionDecl * decl );
92
93 const CodeLocation& getLocation() const { return getDecl()->location; }
94 ast::FunctionDecl * genProto( const std::string& name,
95 std::vector<ast::ptr<ast::DeclWithType>>&& params,
96 std::vector<ast::ptr<ast::DeclWithType>>&& returns ) const;
97
98 ast::ObjectDecl * dstParam() const;
99 ast::ObjectDecl * srcParam() const;
100 ast::FunctionDecl * genCtorProto() const;
101 ast::FunctionDecl * genCopyProto() const;
102 ast::FunctionDecl * genDtorProto() const;
103 ast::FunctionDecl * genAssignProto() const;
104 ast::FunctionDecl * genFieldCtorProto( unsigned int fields ) const;
105
106 // Internal Hooks:
107 virtual void genFuncBody( ast::FunctionDecl * decl ) = 0;
108 virtual void genFieldCtors() = 0;
109 virtual bool isConcurrentType() const { return false; }
110 virtual const ast::Decl * getDecl() const = 0;
111};
112
113class StructFuncGenerator final : public FuncGenerator {
114 const ast::StructDecl * decl;
115public:
116 StructFuncGenerator( const ast::StructDecl * decl,
117 const ast::StructInstType * type,
118 unsigned int functionNesting ) :
119 FuncGenerator( type, functionNesting ), decl( decl )
120 {}
121
122 // Built-ins do not use autogeneration.
123 bool shouldAutogen() const final { return !decl->linkage.is_builtin; }
124private:
125 void genFuncBody( ast::FunctionDecl * decl ) final;
126 void genFieldCtors() final;
127 bool isConcurrentType() const final {
128 return decl->is_thread() || decl->is_monitor();
129 }
130 virtual const ast::Decl * getDecl() const final { return decl; }
131
132 /// Generates a single struct member operation.
133 /// (constructor call, destructor call, assignment call)
134 // This is managed because it uses another helper that returns a ast::ptr.
135 ast::ptr<ast::Stmt> makeMemberOp(
136 const CodeLocation& location,
137 const ast::ObjectDecl * dstParam, const ast::Expr * src,
138 const ast::ObjectDecl * field, ast::FunctionDecl * func,
139 SymTab::LoopDirection direction );
140
141 /// Generates the body of a struct function by iterating the struct members
142 /// (via parameters). Generates default constructor, copy constructor,
143 /// copy assignment, and destructor bodies. No field constructor bodies.
144 template<typename Iterator>
145 void makeFunctionBody( Iterator member, Iterator end,
146 ast::FunctionDecl * func, SymTab::LoopDirection direction );
147
148 /// Generate the body of a constructor which takes parameters that match
149 /// fields. (With arguments for one to all of the fields.)
150 template<typename Iterator>
151 void makeFieldCtorBody( Iterator member, Iterator end,
152 ast::FunctionDecl * func );
153};
154
155class UnionFuncGenerator final : public FuncGenerator {
156 const ast::UnionDecl * decl;
157public:
158 UnionFuncGenerator( const ast::UnionDecl * decl,
159 const ast::UnionInstType * type,
160 unsigned int functionNesting ) :
161 FuncGenerator( type, functionNesting ), decl( decl )
162 {}
163
164 // Built-ins do not use autogeneration.
165 bool shouldAutogen() const final { return !decl->linkage.is_builtin; }
166private:
167 void genFuncBody( ast::FunctionDecl * decl ) final;
168 void genFieldCtors() final;
169 const ast::Decl * getDecl() const final { return decl; }
170
171 /// Generate a single union assignment expression (using memcpy).
172 ast::ExprStmt * makeAssignOp( const CodeLocation& location,
173 const ast::ObjectDecl * dstParam, const ast::ObjectDecl * srcParam );
174};
175
176class EnumFuncGenerator final : public FuncGenerator {
177 const ast::EnumDecl * decl;
178public:
179 EnumFuncGenerator( const ast::EnumDecl * decl,
180 const ast::EnumInstType * type,
181 unsigned int functionNesting ) :
182 FuncGenerator( type, functionNesting ), decl( decl )
183 {
184 // TODO: These functions are somewhere between instrinsic and autogen,
185 // could possibly use a new linkage type. For now we just make the
186 // basic ones intrinsic to code-gen them as C assignments.
187 const auto & real_type = decl->base;
188 const auto & basic = real_type.as<ast::BasicType>();
189 if(!real_type || (basic && basic->isInteger())) proto_linkage = ast::Linkage::Intrinsic;
190 }
191
192 bool shouldAutogen() const final { return true; }
193private:
194 void genFuncBody( ast::FunctionDecl * decl ) final;
195 void genFieldCtors() final;
196 const ast::Decl * getDecl() const final { return decl; }
197};
198
199class TypeFuncGenerator final : public FuncGenerator {
200 const ast::TypeDecl * decl;
201public:
202 TypeFuncGenerator( const ast::TypeDecl * decl,
203 ast::TypeInstType * type,
204 unsigned int functionNesting ) :
205 FuncGenerator( type, functionNesting ), decl( decl )
206 {}
207
208 bool shouldAutogen() const final { return true; }
209 void genFieldCtors() final;
210private:
211 void genFuncBody( ast::FunctionDecl * decl ) final;
212 const ast::Decl * getDecl() const final { return decl; }
213};
214
215// --------------------------------------------------------------------------
216const std::vector<ast::ptr<ast::TypeDecl>>& getGenericParams( const ast::Type * t ) {
217 if ( auto inst = dynamic_cast< const ast::StructInstType * >( t ) ) {
218 return inst->base->params;
219 } else if ( auto inst = dynamic_cast< const ast::UnionInstType * >( t ) ) {
220 return inst->base->params;
221 }
222 static std::vector<ast::ptr<ast::TypeDecl>> const empty;
223 return empty;
224}
225
226/// Changes the node inside a pointer so that it has the unused attribute.
227void addUnusedAttribute( ast::ptr<ast::DeclWithType> & declPtr ) {
228 ast::DeclWithType * decl = declPtr.get_and_mutate();
229 decl->attributes.push_back( new ast::Attribute( "unused" ) );
230}
231
232// --------------------------------------------------------------------------
233void AutogenerateRoutines_new::previsit( const ast::EnumDecl * enumDecl ) {
234 // Must visit children (enum constants) to add them to the symbol table.
235 if ( !enumDecl->body ) return;
236
237 ast::EnumInstType enumInst( enumDecl->name );
238 enumInst.base = enumDecl;
239 EnumFuncGenerator gen( enumDecl, &enumInst, functionNesting );
240 gen.generateAndAppendFunctions( declsToAddAfter );
241}
242
243void AutogenerateRoutines_new::previsit( const ast::StructDecl * structDecl ) {
244 visit_children = false;
245 if ( !structDecl->body ) return;
246
247 ast::StructInstType structInst( structDecl->name );
248 structInst.base = structDecl;
249 for ( const ast::TypeDecl * typeDecl : structDecl->params ) {
250 structInst.params.push_back( new ast::TypeExpr(
251 typeDecl->location,
252 new ast::TypeInstType( typeDecl )
253 ) );
254 }
255 StructFuncGenerator gen( structDecl, &structInst, functionNesting );
256 gen.generateAndAppendFunctions( declsToAddAfter );
257}
258
259void AutogenerateRoutines_new::previsit( const ast::UnionDecl * unionDecl ) {
260 visit_children = false;
261 if ( !unionDecl->body ) return;
262
263 ast::UnionInstType unionInst( unionDecl->name );
264 unionInst.base = unionDecl;
265 for ( const ast::TypeDecl * typeDecl : unionDecl->params ) {
266 unionInst.params.push_back( new ast::TypeExpr(
267 unionDecl->location,
268 new ast::TypeInstType( typeDecl )
269 ) );
270 }
271 UnionFuncGenerator gen( unionDecl, &unionInst, functionNesting );
272 gen.generateAndAppendFunctions( declsToAddAfter );
273}
274
275/// Generate ctor/dtors/assign for typedecls, e.g., otype T = int *;
276void AutogenerateRoutines_new::previsit( const ast::TypeDecl * typeDecl ) {
277 if ( !typeDecl->base ) return;
278
279 ast::TypeInstType refType( typeDecl->name, typeDecl );
280 TypeFuncGenerator gen( typeDecl, &refType, functionNesting );
281 gen.generateAndAppendFunctions( declsToAddAfter );
282}
283
284void AutogenerateRoutines_new::previsit( const ast::TraitDecl * ) {
285 // Ensure that we don't add assignment ops for types defined as part of the trait
286 visit_children = false;
287}
288
289void AutogenerateRoutines_new::previsit( const ast::FunctionDecl * ) {
290 // Track whether we're currently in a function.
291 // Can ignore function type idiosyncrasies, because function type can never
292 // declare a new type.
293 functionNesting += 1;
294}
295
296void AutogenerateRoutines_new::postvisit( const ast::FunctionDecl * ) {
297 functionNesting -= 1;
298}
299
300void FuncGenerator::generateAndAppendFunctions(
301 std::list<ast::ptr<ast::Decl>> & decls ) {
302 if ( !shouldAutogen() ) return;
303
304 // Generate the functions (they go into forwards and definitions).
305 genStandardFuncs();
306 genFieldCtors();
307
308 // Now export the lists contents.
309 decls.splice( decls.end(), forwards );
310 decls.splice( decls.end(), definitions );
311}
312
313void FuncGenerator::produceDecl( const ast::FunctionDecl * decl ) {
314 assert( nullptr != decl->stmts );
315
316 definitions.push_back( decl );
317}
318
319/// Make a forward declaration of the decl and add it to forwards.
320void FuncGenerator::produceForwardDecl( const ast::FunctionDecl * decl ) {
321 if (0 != functionNesting) return;
322 ast::FunctionDecl * fwd = ast::deepCopy( decl );
323 fwd->stmts = nullptr;
324 fwd->fixUniqueId();
325 forwards.push_back( fwd );
326}
327
328/// Generates a basic prototype function declaration.
329ast::FunctionDecl * FuncGenerator::genProto( const std::string& name,
330 std::vector<ast::ptr<ast::DeclWithType>>&& params,
331 std::vector<ast::ptr<ast::DeclWithType>>&& returns ) const {
332
333 // Handle generic prameters and assertions, if any.
334 auto const & old_type_params = getGenericParams( type );
335 std::vector<ast::ptr<ast::TypeDecl>> type_params;
336 std::vector<ast::ptr<ast::DeclWithType>> assertions;
337 for ( auto & old_param : old_type_params ) {
338 ast::TypeDecl * decl = ast::deepCopy( old_param );
339 for ( auto assertion : decl->assertions ) {
340 assertions.push_back( assertion );
341 }
342 decl->assertions.clear();
343 type_params.push_back( decl );
344 }
345 // TODO: The values in params and returns still may point at the old
346 // generic params, that does not appear to be an issue but perhaps it
347 // should be addressed.
348
349 ast::FunctionDecl * decl = new ast::FunctionDecl(
350 // Auto-generated routines use the type declaration's location.
351 getLocation(),
352 name,
353 std::move( type_params ),
354 std::move( assertions ),
355 std::move( params ),
356 std::move( returns ),
357 // Only a prototype, no body.
358 nullptr,
359 // Use static storage if we are at the top level.
360 (0 < functionNesting) ? ast::Storage::Classes() : ast::Storage::Static,
361 proto_linkage,
362 std::vector<ast::ptr<ast::Attribute>>(),
363 // Auto-generated routines are inline to avoid conflicts.
364 ast::Function::Specs( ast::Function::Inline ) );
365 decl->fixUniqueId();
366 return decl;
367}
368
369ast::ObjectDecl * FuncGenerator::dstParam() const {
370 return new ast::ObjectDecl( getLocation(), "_dst",
371 new ast::ReferenceType( ast::deepCopy( type ) ),
372 nullptr, {}, ast::Linkage::Cforall );
373}
374
375ast::ObjectDecl * FuncGenerator::srcParam() const {
376 return new ast::ObjectDecl( getLocation(), "_src",
377 ast::deepCopy( type ),
378 nullptr, {}, ast::Linkage::Cforall );
379}
380
381/// Use the current type T to create `void ?{}(T & _dst)`.
382ast::FunctionDecl * FuncGenerator::genCtorProto() const {
383 return genProto( "?{}", { dstParam() }, {} );
384}
385
386/// Use the current type T to create `void ?{}(T & _dst, T _src)`.
387ast::FunctionDecl * FuncGenerator::genCopyProto() const {
388 return genProto( "?{}", { dstParam(), srcParam() }, {} );
389}
390
391/// Use the current type T to create `void ?{}(T & _dst)`.
392ast::FunctionDecl * FuncGenerator::genDtorProto() const {
393 // The destructor must be mutex on a concurrent type.
394 auto dst = dstParam();
395 if ( isConcurrentType() ) {
396 add_qualifiers( dst->type, ast::CV::Qualifiers( ast::CV::Mutex ) );
397 }
398 return genProto( "^?{}", { dst }, {} );
399}
400
401/// Use the current type T to create `T ?{}(T & _dst, T _src)`.
402ast::FunctionDecl * FuncGenerator::genAssignProto() const {
403 // Only the name is different, so just reuse the generation function.
404 auto retval = srcParam();
405 retval->name = "_ret";
406 return genProto( "?=?", { dstParam(), srcParam() }, { retval } );
407}
408
409// This one can return null if the last field is an unnamed bitfield.
410ast::FunctionDecl * FuncGenerator::genFieldCtorProto(
411 unsigned int fields ) const {
412 assert( 0 < fields );
413 auto aggr = strict_dynamic_cast<const ast::AggregateDecl *>( getDecl() );
414
415 std::vector<ast::ptr<ast::DeclWithType>> params = { dstParam() };
416 for ( unsigned int index = 0 ; index < fields ; ++index ) {
417 auto member = aggr->members[index].strict_as<ast::DeclWithType>();
418 if ( SymTab::isUnnamedBitfield(
419 dynamic_cast<const ast::ObjectDecl *>( member ) ) ) {
420 if ( index == fields - 1 ) {
421 return nullptr;
422 }
423 continue;
424 }
425
426 auto * paramType = ast::deepCopy( member->get_type() );
427 paramType->attributes.clear();
428 ast::ObjectDecl * param = new ast::ObjectDecl(
429 getLocation(), member->name, paramType );
430 param->linkage = ast::Linkage::Cforall;
431 for ( auto & attr : member->attributes ) {
432 if ( attr->isValidOnFuncParam() ) {
433 param->attributes.push_back( attr );
434 }
435 }
436 params.emplace_back( param );
437 }
438 return genProto( "?{}", std::move( params ), {} );
439}
440
441void appendReturnThis( ast::FunctionDecl * decl ) {
442 assert( 1 <= decl->params.size() );
443 assert( 1 == decl->returns.size() );
444 assert( decl->stmts );
445
446 const CodeLocation& location = (decl->stmts->kids.empty())
447 ? decl->stmts->location : decl->stmts->kids.back()->location;
448 const ast::DeclWithType * thisParam = decl->params.front();
449 decl->stmts.get_and_mutate()->push_back(
450 new ast::ReturnStmt( location,
451 new ast::VariableExpr( location, thisParam )
452 )
453 );
454}
455
456void FuncGenerator::genStandardFuncs() {
457 // The order here determines the order that these functions are generated.
458 // Assignment should come last since it uses copy constructor in return.
459 ast::FunctionDecl *(FuncGenerator::*standardProtos[4])() const = {
460 &FuncGenerator::genCtorProto, &FuncGenerator::genCopyProto,
461 &FuncGenerator::genDtorProto, &FuncGenerator::genAssignProto };
462 for ( auto & generator : standardProtos ) {
463 ast::FunctionDecl * decl = (this->*generator)();
464 produceForwardDecl( decl );
465 genFuncBody( decl );
466 if ( CodeGen::isAssignment( decl->name ) ) {
467 appendReturnThis( decl );
468 }
469 produceDecl( decl );
470 }
471}
472
473void StructFuncGenerator::genFieldCtors() {
474 // The field constructors are only generated if the default constructor
475 // and copy constructor are both generated, since the need both.
476 unsigned numCtors = std::count_if( definitions.begin(), definitions.end(),
477 [](const ast::Decl * decl){ return CodeGen::isConstructor( decl->name ); }
478 );
479 if ( 2 != numCtors ) return;
480
481 for ( unsigned int num = 1 ; num <= decl->members.size() ; ++num ) {
482 ast::FunctionDecl * ctor = genFieldCtorProto( num );
483 if ( nullptr == ctor ) {
484 continue;
485 }
486 produceForwardDecl( ctor );
487 makeFieldCtorBody( decl->members.begin(), decl->members.end(), ctor );
488 produceDecl( ctor );
489 }
490}
491
492void StructFuncGenerator::genFuncBody( ast::FunctionDecl * functionDecl ) {
493 // Generate appropriate calls to member constructors and assignment.
494 // Destructor needs to do everything in reverse,
495 // so pass "forward" based on whether the function is a destructor
496 if ( CodeGen::isDestructor( functionDecl->name ) ) {
497 makeFunctionBody( decl->members.rbegin(), decl->members.rend(),
498 functionDecl, SymTab::LoopBackward );
499 } else {
500 makeFunctionBody( decl->members.begin(), decl->members.end(),
501 functionDecl, SymTab::LoopForward );
502 }
503}
504
505ast::ptr<ast::Stmt> StructFuncGenerator::makeMemberOp(
506 const CodeLocation& location, const ast::ObjectDecl * dstParam,
507 const ast::Expr * src, const ast::ObjectDecl * field,
508 ast::FunctionDecl * func, SymTab::LoopDirection direction ) {
509 InitTweak::InitExpander_new srcParam( src );
510 // Assign to destination.
511 ast::Expr * dstSelect = new ast::MemberExpr(
512 location,
513 field,
514 new ast::CastExpr(
515 location,
516 new ast::VariableExpr( location, dstParam ),
517 dstParam->type.strict_as<ast::ReferenceType>()->base
518 )
519 );
520 return genImplicitCall(
521 srcParam, dstSelect, location, func->name,
522 field, direction
523 );
524}
525
526template<typename Iterator>
527void StructFuncGenerator::makeFunctionBody( Iterator current, Iterator end,
528 ast::FunctionDecl * func, SymTab::LoopDirection direction ) {
529 // Trying to get the best code location. Should probably use a helper or
530 // just figure out what that would be given where this is called.
531 assert( nullptr == func->stmts );
532 const CodeLocation& location = func->location;
533
534 ast::CompoundStmt * stmts = new ast::CompoundStmt( location );
535
536 for ( ; current != end ; ++current ) {
537 const ast::ptr<ast::Decl> & member = *current;
538 auto field = member.as<ast::ObjectDecl>();
539 if ( nullptr == field ) {
540 continue;
541 }
542
543 // Don't assign to constant members (but do construct/destruct them).
544 if ( CodeGen::isAssignment( func->name ) ) {
545 // For array types we need to strip off the array layers.
546 const ast::Type * type = field->get_type();
547 while ( auto at = dynamic_cast<const ast::ArrayType *>( type ) ) {
548 type = at->base;
549 }
550 if ( type->is_const() ) {
551 continue;
552 }
553 }
554
555 assert( !func->params.empty() );
556 const ast::ObjectDecl * dstParam =
557 func->params.front().strict_as<ast::ObjectDecl>();
558 const ast::ObjectDecl * srcParam = nullptr;
559 if ( 2 == func->params.size() ) {
560 srcParam = func->params.back().strict_as<ast::ObjectDecl>();
561 }
562
563 ast::Expr * srcSelect = (srcParam) ? new ast::MemberExpr(
564 location, field, new ast::VariableExpr( location, srcParam )
565 ) : nullptr;
566 ast::ptr<ast::Stmt> stmt =
567 makeMemberOp( location, dstParam, srcSelect, field, func, direction );
568
569 if ( nullptr != stmt ) {
570 stmts->kids.push_back( stmt );
571 }
572 }
573
574 func->stmts = stmts;
575}
576
577template<typename Iterator>
578void StructFuncGenerator::makeFieldCtorBody( Iterator current, Iterator end,
579 ast::FunctionDecl * func ) {
580 const CodeLocation& location = func->location;
581 auto & params = func->params;
582 // Need at least the constructed parameter and one field parameter.
583 assert( 2 <= params.size() );
584
585 ast::CompoundStmt * stmts = new ast::CompoundStmt( location );
586
587 auto dstParam = params.front().strict_as<ast::ObjectDecl>();
588 // Skip over the 'this' parameter.
589 for ( auto param = params.begin() + 1 ; current != end ; ++current ) {
590 const ast::ptr<ast::Decl> & member = *current;
591 ast::ptr<ast::Stmt> stmt = nullptr;
592 auto field = member.as<ast::ObjectDecl>();
593 // Not sure why it could be null.
594 // Don't make a function for a parameter that is an unnamed bitfield.
595 if ( nullptr == field || SymTab::isUnnamedBitfield( field ) ) {
596 continue;
597 // Matching Parameter: Initialize the field by copy.
598 } else if ( params.end() != param ) {
599 const ast::Expr *srcSelect = new ast::VariableExpr(
600 func->location, param->get() );
601 stmt = makeMemberOp( location, dstParam, srcSelect, field, func, SymTab::LoopForward );
602 ++param;
603 // No Matching Parameter: Initialize the field by default constructor.
604 } else {
605 stmt = makeMemberOp( location, dstParam, nullptr, field, func, SymTab::LoopForward );
606 }
607
608 if ( nullptr != stmt ) {
609 stmts->kids.push_back( stmt );
610 }
611 }
612 func->stmts = stmts;
613}
614
615void UnionFuncGenerator::genFieldCtors() {
616 // Field constructors are only generated if default and copy constructor
617 // are generated, since they need access to both
618 unsigned numCtors = std::count_if( definitions.begin(), definitions.end(),
619 []( const ast::Decl * d ){ return CodeGen::isConstructor( d->name ); }
620 );
621 if ( 2 != numCtors ) {
622 return;
623 }
624
625 // Create a constructor which takes the first member type as a
626 // parameter. For example for `union A { int x; char y; };` generate
627 // a function with signature `void ?{}(A *, int)`. This mimics C's
628 // behaviour which initializes the first member of the union.
629
630 // Still, there must be some members.
631 if ( !decl->members.empty() ) {
632 ast::FunctionDecl * ctor = genFieldCtorProto( 1 );
633 if ( nullptr == ctor ) {
634 return;
635 }
636 produceForwardDecl( ctor );
637 auto params = ctor->params;
638 auto dstParam = params.front().strict_as<ast::ObjectDecl>();
639 auto srcParam = params.back().strict_as<ast::ObjectDecl>();
640 ctor->stmts = new ast::CompoundStmt( getLocation(),
641 { makeAssignOp( getLocation(), dstParam, srcParam ) }
642 );
643 produceDecl( ctor );
644 }
645}
646
647void UnionFuncGenerator::genFuncBody( ast::FunctionDecl * functionDecl ) {
648 const CodeLocation& location = functionDecl->location;
649 auto & params = functionDecl->params;
650 if ( InitTweak::isCopyConstructor( functionDecl )
651 || InitTweak::isAssignment( functionDecl ) ) {
652 assert( 2 == params.size() );
653 auto dstParam = params.front().strict_as<ast::ObjectDecl>();
654 auto srcParam = params.back().strict_as<ast::ObjectDecl>();
655 functionDecl->stmts = new ast::CompoundStmt( location,
656 { makeAssignOp( location, dstParam, srcParam ) }
657 );
658 } else {
659 assert( 1 == params.size() );
660 // Default constructor and destructor is empty.
661 functionDecl->stmts = new ast::CompoundStmt( location );
662 // Add unused attribute to parameter to silence warnings.
663 addUnusedAttribute( params.front() );
664
665 // Just an extra step to make the forward and declaration match.
666 if ( forwards.empty() ) return;
667 ast::FunctionDecl * fwd = strict_dynamic_cast<ast::FunctionDecl *>(
668 forwards.back().get_and_mutate() );
669 addUnusedAttribute( fwd->params.front() );
670 }
671}
672
673ast::ExprStmt * UnionFuncGenerator::makeAssignOp( const CodeLocation& location,
674 const ast::ObjectDecl * dstParam, const ast::ObjectDecl * srcParam ) {
675 return new ast::ExprStmt( location, new ast::UntypedExpr(
676 location,
677 new ast::NameExpr( location, "__builtin_memcpy" ),
678 {
679 new ast::AddressExpr( location,
680 new ast::VariableExpr( location, dstParam ) ),
681 new ast::AddressExpr( location,
682 new ast::VariableExpr( location, srcParam ) ),
683 new ast::SizeofExpr( location, srcParam->type ),
684 } ) );
685}
686
687void EnumFuncGenerator::genFieldCtors() {
688 // Enumerations to not have field constructors.
689}
690
691void EnumFuncGenerator::genFuncBody( ast::FunctionDecl * functionDecl ) {
692 const CodeLocation& location = functionDecl->location;
693 auto & params = functionDecl->params;
694 if ( InitTweak::isCopyConstructor( functionDecl )
695 || InitTweak::isAssignment( functionDecl ) ) {
696 assert( 2 == params.size() );
697 auto dstParam = params.front().strict_as<ast::ObjectDecl>();
698 auto srcParam = params.back().strict_as<ast::ObjectDecl>();
699
700 /* This looks like a recursive call, but code-gen will turn it into
701 * a C-style assignment.
702 *
703 * This is still before function pointer type conversion,
704 * so this will have to do it manually.
705 *
706 * It will also reference the parent function declaration, creating
707 * a cycle for references. This also means that the ref-counts are
708 * now non-zero and the declaration will be deleted if it ever
709 * returns to zero.
710 */
711 auto callExpr = new ast::ApplicationExpr( location,
712 ast::VariableExpr::functionPointer( location, functionDecl ),
713 {
714 new ast::VariableExpr( location, dstParam ),
715 new ast::VariableExpr( location, srcParam ),
716 }
717 );
718 functionDecl->stmts = new ast::CompoundStmt( location,
719 { new ast::ExprStmt( location, callExpr ) }
720 );
721 } else {
722 assert( 1 == params.size() );
723 // Default constructor and destructor is empty.
724 functionDecl->stmts = new ast::CompoundStmt( location );
725 // Just add unused attribute to parameter to silence warnings.
726 addUnusedAttribute( params.front() );
727
728 // Just an extra step to make the forward and declaration match.
729 if ( forwards.empty() ) return;
730 ast::FunctionDecl * fwd = strict_dynamic_cast<ast::FunctionDecl *>(
731 forwards.back().get_and_mutate() );
732 addUnusedAttribute( fwd->params.front() );
733 }
734}
735
736void TypeFuncGenerator::genFieldCtors() {
737 // Opaque types do not have field constructors.
738}
739
740void TypeFuncGenerator::genFuncBody( ast::FunctionDecl * functionDecl ) {
741 const CodeLocation& location = functionDecl->location;
742 auto & params = functionDecl->type->params;
743 assertf( 1 == params.size() || 2 == params.size(),
744 "Incorrect number of parameters in autogenerated typedecl function: %zd",
745 params.size() );
746 auto dstParam = params.front().strict_as<ast::ObjectDecl>();
747 auto srcParam = (2 == params.size())
748 ? params.back().strict_as<ast::ObjectDecl>() : nullptr;
749 // Generate appropriate calls to member constructor and assignment.
750 ast::UntypedExpr * expr = new ast::UntypedExpr( location,
751 new ast::NameExpr( location, functionDecl->name )
752 );
753 expr->args.push_back( new ast::CastExpr( location,
754 new ast::VariableExpr( location, dstParam ),
755 new ast::ReferenceType( decl->base )
756 ) );
757 if ( srcParam ) {
758 expr->args.push_back( new ast::CastExpr( location,
759 new ast::VariableExpr( location, srcParam ),
760 decl->base
761 ) );
762 }
763 functionDecl->stmts = new ast::CompoundStmt( location,
764 { new ast::ExprStmt( location, expr ) }
765 );
766}
767
768} // namespace
769
770void autogenerateRoutines( ast::TranslationUnit & translationUnit ) {
771 ast::Pass<AutogenerateRoutines_new>::run( translationUnit );
772}
773
774} // Validate
775
776// Local Variables: //
777// tab-width: 4 //
778// mode: c++ //
779// compile-command: "make install" //
780// End: //
Note: See TracBrowser for help on using the repository browser.