source: src/Validate/Autogen.cpp @ bccd70a

ast-experimental
Last change on this file since bccd70a was bccd70a, checked in by Andrew Beach <ajbeach@…>, 12 months ago

Removed internal code from TypeSubstitution? header. It caused a chain of include problems, which have been corrected.

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