source: src/Validate/Autogen.cpp @ bbfe226

ADTast-experimentalenumforall-pointer-decaypthread-emulationqualifiedEnum
Last change on this file since bbfe226 was a488783, checked in by Andrew Beach <ajbeach@…>, 2 years ago

Translated the first half of validate-D. HoistControlStruct? is pretty much the same, Autogen has changed a lot due to the changes in the AST.

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