source: src/Validate/Autogen.cpp @ 5d3d281

Last change on this file since 5d3d281 was 5d3d281, checked in by Michael Brooks <mlbrooks@…>, 7 days 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.