source: src/InitTweak/GenInit.cc @ fb4dc28

ADTast-experimental
Last change on this file since fb4dc28 was fb4dc28, checked in by Andrew Beach <ajbeach@…>, 13 months ago

Moved new ast code out of one of the old files. The new file may have to change if SymTab? is removed entirely, but for now at least, there is a lot less template code in headers.

  • Property mode set to 100644
File size: 28.2 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// GenInit.cc -- Generate initializers, and other stuff.
8//
9// Author           : Rob Schluntz
10// Created On       : Mon May 18 07:44:20 2015
11// Last Modified By : Andrew Beach
12// Last Modified On : Mon Oct 25 13:53:00 2021
13// Update Count     : 186
14//
15#include "GenInit.h"
16
17#include <stddef.h>                    // for NULL
18#include <algorithm>                   // for any_of
19#include <cassert>                     // for assert, strict_dynamic_cast, assertf
20#include <deque>
21#include <iterator>                    // for back_inserter, inserter, back_inse...
22#include <list>                        // for _List_iterator, list
23
24#include "AST/Decl.hpp"
25#include "AST/Init.hpp"
26#include "AST/Pass.hpp"
27#include "AST/Node.hpp"
28#include "AST/Stmt.hpp"
29#include "CompilationState.h"
30#include "CodeGen/OperatorTable.h"
31#include "Common/PassVisitor.h"        // for PassVisitor, WithGuards, WithShort...
32#include "Common/SemanticError.h"      // for SemanticError
33#include "Common/ToString.hpp"         // for toCString
34#include "Common/UniqueName.h"         // for UniqueName
35#include "Common/utility.h"            // for ValueGuard, maybeClone
36#include "GenPoly/GenPoly.h"           // for getFunctionType, isPolyType
37#include "GenPoly/ScopedSet.h"         // for ScopedSet, ScopedSet<>::const_iter...
38#include "InitTweak.h"                 // for isConstExpr, InitExpander, checkIn...
39#include "ResolvExpr/Resolver.h"
40#include "SymTab/Autogen.h"            // for genImplicitCall
41#include "SymTab/GenImplicitCall.hpp"  // for genImplicitCall
42#include "SymTab/Mangler.h"            // for Mangler
43#include "SynTree/LinkageSpec.h"       // for isOverridable, C
44#include "SynTree/Declaration.h"       // for ObjectDecl, DeclarationWithType
45#include "SynTree/Expression.h"        // for VariableExpr, UntypedExpr, Address...
46#include "SynTree/Initializer.h"       // for ConstructorInit, SingleInit, Initi...
47#include "SynTree/Label.h"             // for Label
48#include "SynTree/Mutator.h"           // for mutateAll
49#include "SynTree/Statement.h"         // for CompoundStmt, ImplicitCtorDtorStmt
50#include "SynTree/Type.h"              // for Type, ArrayType, Type::Qualifiers
51#include "SynTree/Visitor.h"           // for acceptAll, maybeAccept
52#include "Tuples/Tuples.h"             // for maybeImpure
53#include "Validate/FindSpecialDecls.h" // for SizeType
54
55namespace InitTweak {
56        namespace {
57                const std::list<Label> noLabels;
58                const std::list<Expression *> noDesignators;
59        }
60
61        struct ReturnFixer : public WithStmtsToAdd, public WithGuards {
62                /// consistently allocates a temporary variable for the return value
63                /// of a function so that anything which the resolver decides can be constructed
64                /// into the return type of a function can be returned.
65                static void makeReturnTemp( std::list< Declaration * > &translationUnit );
66
67                void premutate( FunctionDecl *functionDecl );
68                void premutate( ReturnStmt * returnStmt );
69
70          protected:
71                FunctionType * ftype = nullptr;
72                std::string funcName;
73        };
74
75        struct CtorDtor : public WithGuards, public WithShortCircuiting, public WithVisitorRef<CtorDtor>  {
76                /// create constructor and destructor statements for object declarations.
77                /// the actual call statements will be added in after the resolver has run
78                /// so that the initializer expression is only removed if a constructor is found
79                /// and the same destructor call is inserted in all of the appropriate locations.
80                static void generateCtorDtor( std::list< Declaration * > &translationUnit );
81
82                void previsit( ObjectDecl * );
83                void previsit( FunctionDecl *functionDecl );
84
85                // should not traverse into any of these declarations to find objects
86                // that need to be constructed or destructed
87                void previsit( StructDecl *aggregateDecl );
88                void previsit( AggregateDecl * ) { visit_children = false; }
89                void previsit( NamedTypeDecl * ) { visit_children = false; }
90                void previsit( FunctionType * ) { visit_children = false; }
91
92                void previsit( CompoundStmt * compoundStmt );
93
94          private:
95                // set of mangled type names for which a constructor or destructor exists in the current scope.
96                // these types require a ConstructorInit node to be generated, anything else is a POD type and thus
97                // should not have a ConstructorInit generated.
98
99                ManagedTypes managedTypes;
100                bool inFunction = false;
101        };
102
103        struct HoistArrayDimension final : public WithDeclsToAdd, public WithShortCircuiting, public WithGuards, public WithIndexer {
104                /// hoist dimension from array types in object declaration so that it uses a single
105                /// const variable of type size_t, so that side effecting array dimensions are only
106                /// computed once.
107                static void hoistArrayDimension( std::list< Declaration * > & translationUnit );
108
109                void premutate( ObjectDecl * objectDecl );
110                DeclarationWithType * postmutate( ObjectDecl * objectDecl );
111                void premutate( FunctionDecl *functionDecl );
112                // should not traverse into any of these declarations to find objects
113                // that need to be constructed or destructed
114                void premutate( AggregateDecl * ) { visit_children = false; }
115                void premutate( NamedTypeDecl * ) { visit_children = false; }
116                void premutate( FunctionType * ) { visit_children = false; }
117
118                // need this so that enumerators are added to the indexer, due to premutate(AggregateDecl *)
119                void premutate( EnumDecl * ) {}
120
121                void hoist( Type * type );
122
123                Type::StorageClasses storageClasses;
124                bool inFunction = false;
125        };
126
127        struct HoistArrayDimension_NoResolve final : public WithDeclsToAdd, public WithShortCircuiting, public WithGuards {
128                /// hoist dimension from array types in object declaration so that it uses a single
129                /// const variable of type size_t, so that side effecting array dimensions are only
130                /// computed once.
131                static void hoistArrayDimension( std::list< Declaration * > & translationUnit );
132
133                void premutate( ObjectDecl * objectDecl );
134                DeclarationWithType * postmutate( ObjectDecl * objectDecl );
135                void premutate( FunctionDecl *functionDecl );
136                // should not traverse into any of these declarations to find objects
137                // that need to be constructed or destructed
138                void premutate( AggregateDecl * ) { visit_children = false; }
139                void premutate( NamedTypeDecl * ) { visit_children = false; }
140                void premutate( FunctionType * ) { visit_children = false; }
141
142                void hoist( Type * type );
143
144                Type::StorageClasses storageClasses;
145                bool inFunction = false;
146        };
147
148        void genInit( std::list< Declaration * > & translationUnit ) {
149                if (!useNewAST) {
150                        HoistArrayDimension::hoistArrayDimension( translationUnit );
151                }
152                else {
153                        HoistArrayDimension_NoResolve::hoistArrayDimension( translationUnit );
154                }
155                fixReturnStatements( translationUnit );
156
157                if (!useNewAST) {
158                        CtorDtor::generateCtorDtor( translationUnit );
159                }
160        }
161
162        void fixReturnStatements( std::list< Declaration * > & translationUnit ) {
163                PassVisitor<ReturnFixer> fixer;
164                mutateAll( translationUnit, fixer );
165        }
166
167        void ReturnFixer::premutate( ReturnStmt *returnStmt ) {
168                std::list< DeclarationWithType * > & returnVals = ftype->get_returnVals();
169                assert( returnVals.size() == 0 || returnVals.size() == 1 );
170                // hands off if the function returns a reference - we don't want to allocate a temporary if a variable's address
171                // is being returned
172                if ( returnStmt->expr && returnVals.size() == 1 && isConstructable( returnVals.front()->get_type() ) ) {
173                        // explicitly construct the return value using the return expression and the retVal object
174                        assertf( returnVals.front()->name != "", "Function %s has unnamed return value\n", funcName.c_str() );
175
176                        ObjectDecl * retVal = strict_dynamic_cast< ObjectDecl * >( returnVals.front() );
177                        if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( returnStmt->expr ) ) {
178                                // return statement has already been mutated - don't need to do it again
179                                if ( varExpr->var == retVal ) return;
180                        }
181                        Statement * stmt = genCtorDtor( "?{}", retVal, returnStmt->expr );
182                        assertf( stmt, "ReturnFixer: genCtorDtor returned nullptr: %s / %s", toString( retVal ).c_str(), toString( returnStmt->expr ).c_str() );
183                        stmtsToAddBefore.push_back( stmt );
184
185                        // return the retVal object
186                        returnStmt->expr = new VariableExpr( returnVals.front() );
187                } // if
188        }
189
190        void ReturnFixer::premutate( FunctionDecl *functionDecl ) {
191                GuardValue( ftype );
192                GuardValue( funcName );
193
194                ftype = functionDecl->type;
195                funcName = functionDecl->name;
196        }
197
198        // precompute array dimension expression, because constructor generation may duplicate it,
199        // which would be incorrect if it is a side-effecting computation.
200        void HoistArrayDimension::hoistArrayDimension( std::list< Declaration * > & translationUnit ) {
201                PassVisitor<HoistArrayDimension> hoister;
202                mutateAll( translationUnit, hoister );
203        }
204
205        void HoistArrayDimension::premutate( ObjectDecl * objectDecl ) {
206                GuardValue( storageClasses );
207                storageClasses = objectDecl->get_storageClasses();
208        }
209
210        DeclarationWithType * HoistArrayDimension::postmutate( ObjectDecl * objectDecl ) {
211                hoist( objectDecl->get_type() );
212                return objectDecl;
213        }
214
215        void HoistArrayDimension::hoist( Type * type ) {
216                // if in function, generate const size_t var
217                static UniqueName dimensionName( "_array_dim" );
218
219                // C doesn't allow variable sized arrays at global scope or for static variables, so don't hoist dimension.
220                if ( ! inFunction ) return;
221                if ( storageClasses.is_static ) return;
222
223                if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {
224                        if ( ! arrayType->get_dimension() ) return; // xxx - recursive call to hoist?
225
226                        // need to resolve array dimensions in order to accurately determine if constexpr
227                        ResolvExpr::findSingleExpression( arrayType->dimension, Validate::SizeType->clone(), indexer );
228                        // array is variable-length when the dimension is not constexpr
229                        arrayType->isVarLen = ! isConstExpr( arrayType->dimension );
230                        // don't need to hoist dimension if it's definitely pure - only need to if there's potential for side effects.
231                        // xxx - hoisting has no side effects anyways, so don't skip since we delay resolve
232                        // still try to detect constant expressions
233                        if ( ! Tuples::maybeImpure( arrayType->dimension ) ) return;
234
235                        ObjectDecl * arrayDimension = new ObjectDecl( dimensionName.newName(), storageClasses, LinkageSpec::C, 0, Validate::SizeType->clone(), new SingleInit( arrayType->get_dimension() ) );
236                        arrayDimension->get_type()->set_const( true );
237
238                        arrayType->set_dimension( new VariableExpr( arrayDimension ) );
239                        declsToAddBefore.push_back( arrayDimension );
240
241                        hoist( arrayType->get_base() );
242                        return;
243                }
244        }
245
246        void HoistArrayDimension::premutate( FunctionDecl * ) {
247                GuardValue( inFunction );
248                inFunction = true;
249        }
250
251        // precompute array dimension expression, because constructor generation may duplicate it,
252        // which would be incorrect if it is a side-effecting computation.
253        void HoistArrayDimension_NoResolve::hoistArrayDimension( std::list< Declaration * > & translationUnit ) {
254                PassVisitor<HoistArrayDimension_NoResolve> hoister;
255                mutateAll( translationUnit, hoister );
256        }
257
258        void HoistArrayDimension_NoResolve::premutate( ObjectDecl * objectDecl ) {
259                GuardValue( storageClasses );
260                storageClasses = objectDecl->get_storageClasses();
261        }
262
263        DeclarationWithType * HoistArrayDimension_NoResolve::postmutate( ObjectDecl * objectDecl ) {
264                hoist( objectDecl->get_type() );
265                return objectDecl;
266        }
267
268        void HoistArrayDimension_NoResolve::hoist( Type * type ) {
269                // if in function, generate const size_t var
270                static UniqueName dimensionName( "_array_dim" );
271
272                // C doesn't allow variable sized arrays at global scope or for static variables, so don't hoist dimension.
273                if ( ! inFunction ) return;
274                if ( storageClasses.is_static ) return;
275
276                if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {
277                        if ( ! arrayType->get_dimension() ) return; // xxx - recursive call to hoist?
278                        // don't need to hoist dimension if it's definitely pure - only need to if there's potential for side effects.
279                        // xxx - hoisting has no side effects anyways, so don't skip since we delay resolve
280                        // still try to detect constant expressions
281                        if ( ! Tuples::maybeImpure( arrayType->dimension ) ) return;
282
283                        ObjectDecl * arrayDimension = new ObjectDecl( dimensionName.newName(), storageClasses, LinkageSpec::C, 0, Validate::SizeType->clone(), new SingleInit( arrayType->get_dimension() ) );
284                        arrayDimension->get_type()->set_const( true );
285
286                        arrayType->set_dimension( new VariableExpr( arrayDimension ) );
287                        declsToAddBefore.push_back( arrayDimension );
288
289                        hoist( arrayType->get_base() );
290                        return;
291                }
292        }
293
294        void HoistArrayDimension_NoResolve::premutate( FunctionDecl * ) {
295                GuardValue( inFunction );
296                inFunction = true;
297        }
298
299namespace {
300
301#       warning Remove the _New suffix after the conversion is complete.
302        struct HoistArrayDimension_NoResolve_New final :
303                        public ast::WithDeclsToAdd<>, public ast::WithShortCircuiting,
304                        public ast::WithGuards, public ast::WithConstTranslationUnit,
305                        public ast::WithVisitorRef<HoistArrayDimension_NoResolve_New> {
306                void previsit( const ast::ObjectDecl * decl );
307                const ast::DeclWithType * postvisit( const ast::ObjectDecl * decl );
308                // Do not look for objects inside there declarations (and type).
309                void previsit( const ast::AggregateDecl * ) { visit_children = false; }
310                void previsit( const ast::NamedTypeDecl * ) { visit_children = false; }
311                void previsit( const ast::FunctionType * ) { visit_children = false; }
312
313                const ast::Type * hoist( const ast::Type * type );
314
315                ast::Storage::Classes storageClasses;
316        };
317
318        void HoistArrayDimension_NoResolve_New::previsit(
319                        const ast::ObjectDecl * decl ) {
320                GuardValue( storageClasses ) = decl->storage;
321        }
322
323        const ast::DeclWithType * HoistArrayDimension_NoResolve_New::postvisit(
324                        const ast::ObjectDecl * objectDecl ) {
325                return mutate_field( objectDecl, &ast::ObjectDecl::type,
326                                hoist( objectDecl->type ) );
327        }
328
329        const ast::Type * HoistArrayDimension_NoResolve_New::hoist(
330                        const ast::Type * type ) {
331                static UniqueName dimensionName( "_array_dim" );
332
333                if ( !isInFunction() || storageClasses.is_static ) {
334                        return type;
335                }
336
337                if ( auto arrayType = dynamic_cast< const ast::ArrayType * >( type ) ) {
338                        if ( nullptr == arrayType->dimension ) {
339                                return type;
340                        }
341
342                        if ( !Tuples::maybeImpure( arrayType->dimension ) ) {
343                                return type;
344                        }
345
346                        ast::ptr<ast::Type> dimType = transUnit().global.sizeType;
347                        assert( dimType );
348                        add_qualifiers( dimType, ast::CV::Qualifiers( ast::CV::Const ) );
349
350                        ast::ObjectDecl * arrayDimension = new ast::ObjectDecl(
351                                arrayType->dimension->location,
352                                dimensionName.newName(),
353                                dimType,
354                                new ast::SingleInit(
355                                        arrayType->dimension->location,
356                                        arrayType->dimension
357                                )
358                        );
359
360                        ast::ArrayType * mutType = ast::mutate( arrayType );
361                        mutType->dimension = new ast::VariableExpr(
362                                        arrayDimension->location, arrayDimension );
363                        declsToAddBefore.push_back( arrayDimension );
364
365                        mutType->base = hoist( mutType->base );
366                        return mutType;
367                }
368                return type;
369        }
370
371        struct ReturnFixer_New final :
372                        public ast::WithStmtsToAdd<>, ast::WithGuards, ast::WithShortCircuiting {
373                void previsit( const ast::FunctionDecl * decl );
374                const ast::ReturnStmt * previsit( const ast::ReturnStmt * stmt );
375        private:
376                const ast::FunctionDecl * funcDecl = nullptr;
377        };
378
379        void ReturnFixer_New::previsit( const ast::FunctionDecl * decl ) {
380                if (decl->linkage == ast::Linkage::Intrinsic) visit_children = false;
381                GuardValue( funcDecl ) = decl;
382        }
383
384        const ast::ReturnStmt * ReturnFixer_New::previsit(
385                        const ast::ReturnStmt * stmt ) {
386                auto & returns = funcDecl->returns;
387                assert( returns.size() < 2 );
388                // Hands off if the function returns a reference.
389                // Don't allocate a temporary if the address is returned.
390                if ( stmt->expr && 1 == returns.size() ) {
391                        ast::ptr<ast::DeclWithType> retDecl = returns.front();
392                        if ( isConstructable( retDecl->get_type() ) ) {
393                                // Explicitly construct the return value using the return
394                                // expression and the retVal object.
395                                assertf( "" != retDecl->name,
396                                        "Function %s has unnamed return value.\n",
397                                        funcDecl->name.c_str() );
398
399                                auto retVal = retDecl.strict_as<ast::ObjectDecl>();
400                                if ( auto varExpr = stmt->expr.as<ast::VariableExpr>() ) {
401                                        // Check if the return statement is already set up.
402                                        if ( varExpr->var == retVal ) return stmt;
403                                }
404                                ast::ptr<ast::Stmt> ctorStmt = genCtorDtor(
405                                        retVal->location, "?{}", retVal, stmt->expr );
406                                assertf( ctorStmt,
407                                        "ReturnFixer: genCtorDtor returned nullptr: %s / %s",
408                                        toString( retVal ).c_str(),
409                                        toString( stmt->expr ).c_str() );
410                                stmtsToAddBefore.push_back( ctorStmt );
411
412                                // Return the retVal object.
413                                ast::ReturnStmt * mutStmt = ast::mutate( stmt );
414                                mutStmt->expr = new ast::VariableExpr(
415                                        stmt->location, retDecl );
416                                return mutStmt;
417                        }
418                }
419                return stmt;
420        }
421
422} // namespace
423
424        void genInit( ast::TranslationUnit & transUnit ) {
425                ast::Pass<HoistArrayDimension_NoResolve_New>::run( transUnit );
426                ast::Pass<ReturnFixer_New>::run( transUnit );
427        }
428
429        void fixReturnStatements( ast::TranslationUnit & transUnit ) {
430                ast::Pass<ReturnFixer_New>::run( transUnit );
431        }
432
433        void CtorDtor::generateCtorDtor( std::list< Declaration * > & translationUnit ) {
434                PassVisitor<CtorDtor> ctordtor;
435                acceptAll( translationUnit, ctordtor );
436        }
437
438        bool ManagedTypes::isManaged( Type * type ) const {
439                // references are never constructed
440                if ( dynamic_cast< ReferenceType * >( type ) ) return false;
441                // need to clear and reset qualifiers when determining if a type is managed
442                ValueGuard< Type::Qualifiers > qualifiers( type->get_qualifiers() );
443                type->get_qualifiers() = Type::Qualifiers();
444                if ( TupleType * tupleType = dynamic_cast< TupleType * > ( type ) ) {
445                        // tuple is also managed if any of its components are managed
446                        if ( std::any_of( tupleType->types.begin(), tupleType->types.end(), [&](Type * type) { return isManaged( type ); }) ) {
447                                return true;
448                        }
449                }
450                // a type is managed if it appears in the map of known managed types, or if it contains any polymorphism (is a type variable or generic type containing a type variable)
451                return managedTypes.find( SymTab::Mangler::mangleConcrete( type ) ) != managedTypes.end() || GenPoly::isPolyType( type );
452        }
453
454        bool ManagedTypes::isManaged( ObjectDecl * objDecl ) const {
455                Type * type = objDecl->get_type();
456                while ( ArrayType * at = dynamic_cast< ArrayType * >( type ) ) {
457                        // must always construct VLAs with an initializer, since this is an error in C
458                        if ( at->isVarLen && objDecl->init ) return true;
459                        type = at->get_base();
460                }
461                return isManaged( type );
462        }
463
464        // why is this not just on FunctionDecl?
465        void ManagedTypes::handleDWT( DeclarationWithType * dwt ) {
466                // if this function is a user-defined constructor or destructor, mark down the type as "managed"
467                if ( ! LinkageSpec::isOverridable( dwt->get_linkage() ) && CodeGen::isCtorDtor( dwt->get_name() ) ) {
468                        std::list< DeclarationWithType * > & params = GenPoly::getFunctionType( dwt->get_type() )->get_parameters();
469                        assert( ! params.empty() );
470                        Type * type = InitTweak::getPointerBase( params.front()->get_type() );
471                        assert( type );
472                        managedTypes.insert( SymTab::Mangler::mangleConcrete( type ) );
473                }
474        }
475
476        void ManagedTypes::handleStruct( StructDecl * aggregateDecl ) {
477                // don't construct members, but need to take note if there is a managed member,
478                // because that means that this type is also managed
479                for ( Declaration * member : aggregateDecl->get_members() ) {
480                        if ( ObjectDecl * field = dynamic_cast< ObjectDecl * >( member ) ) {
481                                if ( isManaged( field ) ) {
482                                        // generic parameters should not play a role in determining whether a generic type is constructed - construct all generic types, so that
483                                        // polymorphic constructors make generic types managed types
484                                        StructInstType inst( Type::Qualifiers(), aggregateDecl );
485                                        managedTypes.insert( SymTab::Mangler::mangleConcrete( &inst ) );
486                                        break;
487                                }
488                        }
489                }
490        }
491
492        void ManagedTypes::beginScope() { managedTypes.beginScope(); }
493        void ManagedTypes::endScope() { managedTypes.endScope(); }
494
495        bool ManagedTypes_new::isManaged( const ast::Type * type ) const {
496                // references are never constructed
497                if ( dynamic_cast< const ast::ReferenceType * >( type ) ) return false;
498                if ( auto tupleType = dynamic_cast< const ast::TupleType * > ( type ) ) {
499                        // tuple is also managed if any of its components are managed
500                        for (auto & component : tupleType->types) {
501                                if (isManaged(component)) return true;
502                        }
503                }
504                // need to clear and reset qualifiers when determining if a type is managed
505                // ValueGuard< Type::Qualifiers > qualifiers( type->get_qualifiers() );
506                auto tmp = shallowCopy(type);
507                tmp->qualifiers = {};
508                // delete tmp at return
509                ast::ptr<ast::Type> guard = tmp;
510                // a type is managed if it appears in the map of known managed types, or if it contains any polymorphism (is a type variable or generic type containing a type variable)
511                return managedTypes.find( Mangle::mangle( tmp, {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) ) != managedTypes.end() || GenPoly::isPolyType( tmp );
512        }
513
514        bool ManagedTypes_new::isManaged( const ast::ObjectDecl * objDecl ) const {
515                const ast::Type * type = objDecl->type;
516                while ( auto at = dynamic_cast< const ast::ArrayType * >( type ) ) {
517                        // must always construct VLAs with an initializer, since this is an error in C
518                        if ( at->isVarLen && objDecl->init ) return true;
519                        type = at->base;
520                }
521                return isManaged( type );
522        }
523
524        void ManagedTypes_new::handleDWT( const ast::DeclWithType * dwt ) {
525                // if this function is a user-defined constructor or destructor, mark down the type as "managed"
526                if ( ! dwt->linkage.is_overrideable && CodeGen::isCtorDtor( dwt->name ) ) {
527                        auto & params = GenPoly::getFunctionType( dwt->get_type())->params;
528                        assert( ! params.empty() );
529                        // Type * type = InitTweak::getPointerBase( params.front() );
530                        // assert( type );
531                        managedTypes.insert( Mangle::mangle( params.front(), {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) );
532                }
533        }
534
535        void ManagedTypes_new::handleStruct( const ast::StructDecl * aggregateDecl ) {
536                // don't construct members, but need to take note if there is a managed member,
537                // because that means that this type is also managed
538                for ( auto & member : aggregateDecl->members ) {
539                        if ( auto field = member.as<ast::ObjectDecl>() ) {
540                                if ( isManaged( field ) ) {
541                                        // generic parameters should not play a role in determining whether a generic type is constructed - construct all generic types, so that
542                                        // polymorphic constructors make generic types managed types
543                                        ast::StructInstType inst( aggregateDecl );
544                                        managedTypes.insert( Mangle::mangle( &inst, {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) );
545                                        break;
546                                }
547                        }
548                }
549        }
550
551        void ManagedTypes_new::beginScope() { managedTypes.beginScope(); }
552        void ManagedTypes_new::endScope() { managedTypes.endScope(); }
553
554        ImplicitCtorDtorStmt * genCtorDtor( const std::string & fname, ObjectDecl * objDecl, Expression * arg ) {
555                // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor
556                assertf( objDecl, "genCtorDtor passed null objDecl" );
557                std::list< Statement * > stmts;
558                InitExpander_old srcParam( maybeClone( arg ) );
559                SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), fname, back_inserter( stmts ), objDecl );
560                assert( stmts.size() <= 1 );
561                return stmts.size() == 1 ? strict_dynamic_cast< ImplicitCtorDtorStmt * >( stmts.front() ) : nullptr;
562
563        }
564
565        ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg) {
566                assertf(objDecl, "genCtorDtor passed null objDecl");
567                InitExpander_new srcParam(arg);
568                return SymTab::genImplicitCall(srcParam, new ast::VariableExpr(loc, objDecl), loc, fname, objDecl);
569        }
570
571        ConstructorInit * genCtorInit( ObjectDecl * objDecl ) {
572                // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor
573                // for each constructable object
574                std::list< Statement * > ctor;
575                std::list< Statement * > dtor;
576
577                InitExpander_old srcParam( objDecl->get_init() );
578                InitExpander_old nullParam( (Initializer *)NULL );
579                SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), "?{}", back_inserter( ctor ), objDecl );
580                SymTab::genImplicitCall( nullParam, new VariableExpr( objDecl ), "^?{}", front_inserter( dtor ), objDecl, false );
581
582                // Currently genImplicitCall produces a single Statement - a CompoundStmt
583                // which  wraps everything that needs to happen. As such, it's technically
584                // possible to use a Statement ** in the above calls, but this is inherently
585                // unsafe, so instead we take the slightly less efficient route, but will be
586                // immediately informed if somehow the above assumption is broken. In this case,
587                // we could always wrap the list of statements at this point with a CompoundStmt,
588                // but it seems reasonable at the moment for this to be done by genImplicitCall
589                // itself. It is possible that genImplicitCall produces no statements (e.g. if
590                // an array type does not have a dimension). In this case, it's fine to ignore
591                // the object for the purposes of construction.
592                assert( ctor.size() == dtor.size() && ctor.size() <= 1 );
593                if ( ctor.size() == 1 ) {
594                        // need to remember init expression, in case no ctors exist
595                        // if ctor does exist, want to use ctor expression instead of init
596                        // push this decision to the resolver
597                        assert( dynamic_cast< ImplicitCtorDtorStmt * > ( ctor.front() ) && dynamic_cast< ImplicitCtorDtorStmt * > ( dtor.front() ) );
598                        return new ConstructorInit( ctor.front(), dtor.front(), objDecl->get_init() );
599                }
600                return nullptr;
601        }
602
603        void CtorDtor::previsit( ObjectDecl * objDecl ) {
604                managedTypes.handleDWT( objDecl );
605                // hands off if @=, extern, builtin, etc.
606                // even if unmanaged, try to construct global or static if initializer is not constexpr, since this is not legal C
607                if ( tryConstruct( objDecl ) && ( managedTypes.isManaged( objDecl ) || ((! inFunction || objDecl->get_storageClasses().is_static ) && ! isConstExpr( objDecl->get_init() ) ) ) ) {
608                        // constructed objects cannot be designated
609                        if ( isDesignated( objDecl->get_init() ) ) SemanticError( objDecl, "Cannot include designations in the initializer for a managed Object. If this is really what you want, then initialize with @=.\n" );
610                        // constructed objects should not have initializers nested too deeply
611                        if ( ! checkInitDepth( objDecl ) ) SemanticError( objDecl, "Managed object's initializer is too deep " );
612
613                        objDecl->set_init( genCtorInit( objDecl ) );
614                }
615        }
616
617        void CtorDtor::previsit( FunctionDecl *functionDecl ) {
618                visit_children = false;  // do not try and construct parameters or forall parameters
619                GuardValue( inFunction );
620                inFunction = true;
621
622                managedTypes.handleDWT( functionDecl );
623
624                GuardScope( managedTypes );
625                // go through assertions and recursively add seen ctor/dtors
626                for ( auto & tyDecl : functionDecl->get_functionType()->get_forall() ) {
627                        for ( DeclarationWithType *& assertion : tyDecl->get_assertions() ) {
628                                managedTypes.handleDWT( assertion );
629                        }
630                }
631
632                maybeAccept( functionDecl->get_statements(), *visitor );
633        }
634
635        void CtorDtor::previsit( StructDecl *aggregateDecl ) {
636                visit_children = false; // do not try to construct and destruct aggregate members
637
638                managedTypes.handleStruct( aggregateDecl );
639        }
640
641        void CtorDtor::previsit( CompoundStmt * ) {
642                GuardScope( managedTypes );
643        }
644
645ast::ConstructorInit * genCtorInit( const CodeLocation & loc, const ast::ObjectDecl * objDecl ) {
646        // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor for each
647        // constructable object
648        InitExpander_new srcParam{ objDecl->init }, nullParam{ (const ast::Init *)nullptr };
649        ast::ptr< ast::Expr > dstParam = new ast::VariableExpr(loc, objDecl);
650
651        ast::ptr< ast::Stmt > ctor = SymTab::genImplicitCall(
652                srcParam, dstParam, loc, "?{}", objDecl );
653        ast::ptr< ast::Stmt > dtor = SymTab::genImplicitCall(
654                nullParam, dstParam, loc, "^?{}", objDecl,
655                SymTab::LoopBackward );
656
657        // check that either both ctor and dtor are present, or neither
658        assert( (bool)ctor == (bool)dtor );
659
660        if ( ctor ) {
661                // need to remember init expression, in case no ctors exist. If ctor does exist, want to
662                // use ctor expression instead of init.
663                ctor.strict_as< ast::ImplicitCtorDtorStmt >();
664                dtor.strict_as< ast::ImplicitCtorDtorStmt >();
665
666                return new ast::ConstructorInit{ loc, ctor, dtor, objDecl->init };
667        }
668
669        return nullptr;
670}
671
672} // namespace InitTweak
673
674// Local Variables: //
675// tab-width: 4 //
676// mode: c++ //
677// compile-command: "make install" //
678// End: //
Note: See TracBrowser for help on using the repository browser.