source: src/Validate/Autogen.cpp@ 532c0cd

Last change on this file since 532c0cd was 5d3d281, checked in by Michael Brooks <mlbrooks@…>, 10 months ago

Remove autogen forward declarations, which are never needed, and cause warnings about static declarations without definitions.

Intended to fix the failing test from previous commit.

Autogen forward declarations are never needed because they do not depend on each other, much less with mutual recursion.

Consequences:

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