Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/InitTweak/FixInit.cc

    r1be845b rf9feab8  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // FixInit.cc --
     7// FixInit.h --
    88//
    99// Author           : Rob Schluntz
     
    5454#include "SynTree/Type.h"              // for Type, Type::StorageClasses
    5555#include "SynTree/TypeSubstitution.h"  // for TypeSubstitution, operator<<
     56#include "SynTree/VarExprReplacer.h"   // for VarExprReplacer
    5657#include "SynTree/Visitor.h"           // for acceptAll, maybeAccept
    5758
     
    6768        namespace {
    6869                typedef std::unordered_map< int, int > UnqCount;
    69 
    70                 struct SelfAssignChecker {
    71                         void previsit( ApplicationExpr * appExpr );
    72                 };
    7370
    7471                struct InsertImplicitCalls : public WithTypeSubstitution {
     
    162159                        using Parent::previsit;
    163160
    164                         void previsit( ObjectDecl * objDecl );
    165161                        void previsit( FunctionDecl * funcDecl );
    166162
    167                         void previsit( CompoundStmt * compoundStmt );
    168                         void postvisit( CompoundStmt * compoundStmt );
    169                         void previsit( ReturnStmt * returnStmt );
    170163                        void previsit( BranchStmt * stmt );
    171164                private:
     
    187180                };
    188181
    189                 class FixCopyCtors final : public WithStmtsToAdd, public WithShortCircuiting, public WithVisitorRef<FixCopyCtors>, public WithTypeSubstitution {
     182                class FixCopyCtors final : public WithStmtsToAdd, public WithShortCircuiting, public WithVisitorRef<FixCopyCtors> {
    190183                  public:
    191184                        FixCopyCtors( UnqCount & unqCount ) : unqCount( unqCount ){}
     
    201194                };
    202195
    203                 struct GenStructMemberCalls final : public WithGuards, public WithShortCircuiting, public WithIndexer, public WithVisitorRef<GenStructMemberCalls> {
     196                struct GenStructMemberCalls final : public WithGuards, public WithShortCircuiting, public WithIndexer {
    204197                        /// generate default/copy ctor and dtor calls for user-defined struct ctor/dtors
    205198                        /// for any member that is missing a corresponding ctor/dtor call.
     
    207200                        static void generate( std::list< Declaration * > & translationUnit );
    208201
    209                         void premutate( FunctionDecl * funcDecl );
    210                         DeclarationWithType * postmutate( FunctionDecl * funcDecl );
    211 
    212                         void premutate( MemberExpr * memberExpr );
    213                         void premutate( ApplicationExpr * appExpr );
    214 
    215                         /// Note: this post mutate used to be in a separate visitor. If this pass breaks, one place to examine is whether it is
    216                         /// okay for this part of the recursion to occur alongside the rest.
    217                         Expression * postmutate( UntypedExpr * expr );
    218 
    219                         SemanticErrorException errors;
     202                        void previsit( StructDecl * structDecl );
     203
     204                        void previsit( FunctionDecl * funcDecl );
     205                        void postvisit( FunctionDecl * funcDecl );
     206
     207                        void previsit( MemberExpr * memberExpr );
     208                        void previsit( ApplicationExpr * appExpr );
     209
     210                        SemanticError errors;
    220211                  private:
    221212                        template< typename... Params >
     
    228219                        bool isCtor = false; // true if current function is a constructor
    229220                        StructDecl * structDecl = nullptr;
     221
     222                        // special built-in functions necessary for this to work
     223                        StructDecl * dtorStruct = nullptr;
     224                        FunctionDecl * dtorStructDestroy = nullptr;
     225                };
     226
     227                // very simple resolver-like mutator class - used to
     228                // resolve UntypedExprs that are found within newly
     229                // generated constructor/destructor calls
     230                class MutatingResolver final : public Mutator {
     231                  public:
     232                        MutatingResolver( SymTab::Indexer & indexer ) : indexer( indexer ) {}
     233
     234                        using Mutator::mutate;
     235                        virtual DeclarationWithType* mutate( ObjectDecl *objectDecl ) override;
     236                        virtual Expression* mutate( UntypedExpr *untypedExpr ) override;
     237
     238                  private:
     239                        SymTab::Indexer & indexer;
    230240                };
    231241
     
    238248        } // namespace
    239249
    240         void fix( std::list< Declaration * > & translationUnit, bool inLibrary ) {
    241                 PassVisitor<SelfAssignChecker> checker;
    242                 acceptAll( translationUnit, checker );
    243 
     250        void fix( std::list< Declaration * > & translationUnit, const std::string & filename, bool inLibrary ) {
    244251                // fixes ConstructorInit for global variables. should happen before fixInitializers.
    245                 InitTweak::fixGlobalInit( translationUnit, inLibrary );
     252                InitTweak::fixGlobalInit( translationUnit, filename, inLibrary );
    246253
    247254                UnqCount unqCount;
     
    283290                        // can't use mutateAll, because need to insert declarations at top-level
    284291                        // can't use DeclMutator, because sometimes need to insert IfStmt, etc.
    285                         SemanticErrorException errors;
     292                        SemanticError errors;
    286293                        for ( std::list< Declaration * >::iterator i = translationUnit.begin(); i != translationUnit.end(); ++i ) {
    287294                                try {
    288295                                        maybeMutate( *i, fixer );
    289296                                        translationUnit.splice( i, fixer.pass.staticDtorDecls );
    290                                 } catch( SemanticErrorException &e ) {
     297                                } catch( SemanticError &e ) {
     298                                        e.set_location( (*i)->location );
    291299                                        errors.append( e );
    292300                                } // try
     
    310318                void GenStructMemberCalls::generate( std::list< Declaration * > & translationUnit ) {
    311319                        PassVisitor<GenStructMemberCalls> warner;
    312                         mutateAll( translationUnit, warner );
     320                        acceptAll( translationUnit, warner );
    313321                }
    314322
     
    316324                        PassVisitor<FixCtorExprs> fixer;
    317325                        mutateAll( translationUnit, fixer );
    318                 }
    319 
    320                 namespace {
    321                         // Relatively simple structural comparison for expressions, needed to determine
    322                         // if two expressions are "the same" (used to determine if self assignment occurs)
    323                         struct StructuralChecker {
    324                                 Expression * stripCasts( Expression * expr ) {
    325                                         // this might be too permissive. It's possible that only particular casts are relevant.
    326                                         while ( CastExpr * cast = dynamic_cast< CastExpr * >( expr ) ) {
    327                                                 expr = cast->arg;
    328                                         }
    329                                         return expr;
    330                                 }
    331 
    332                                 void previsit( Expression * ) {
    333                                         // anything else does not qualify
    334                                         isSimilar = false;
    335                                 }
    336 
    337                                 template<typename T>
    338                                 T * cast( Expression * node ) {
    339                                         // all expressions need to ignore casts, so this bit has been factored out
    340                                         return dynamic_cast< T * >( stripCasts( node ) );
    341                                 }
    342 
    343                                 // ignore casts
    344                                 void previsit( CastExpr * ) {}
    345 
    346                                 void previsit( MemberExpr * memExpr ) {
    347                                         if ( MemberExpr * otherMember = cast< MemberExpr >( other ) ) {
    348                                                 if ( otherMember->member == memExpr->member ) {
    349                                                         other = otherMember->aggregate;
    350                                                         return;
    351                                                 }
    352                                         }
    353                                         isSimilar = false;
    354                                 }
    355 
    356                                 void previsit( VariableExpr * varExpr ) {
    357                                         if ( VariableExpr * otherVar = cast< VariableExpr >( other ) ) {
    358                                                 if ( otherVar->var == varExpr->var ) {
    359                                                         return;
    360                                                 }
    361                                         }
    362                                         isSimilar = false;
    363                                 }
    364 
    365                                 void previsit( AddressExpr * ) {
    366                                         if ( AddressExpr * addrExpr = cast< AddressExpr >( other ) ) {
    367                                                 other = addrExpr->arg;
    368                                                 return;
    369                                         }
    370                                         isSimilar = false;
    371                                 }
    372 
    373                                 Expression * other = nullptr;
    374                                 bool isSimilar = true;
    375                         };
    376 
    377                         bool structurallySimilar( Expression * e1, Expression * e2 ) {
    378                                 PassVisitor<StructuralChecker> checker;
    379                                 checker.pass.other = e2;
    380                                 e1->accept( checker );
    381                                 return checker.pass.isSimilar;
    382                         }
    383                 }
    384 
    385                 void SelfAssignChecker::previsit( ApplicationExpr * appExpr ) {
    386                         DeclarationWithType * function = getFunction( appExpr );
    387                         if ( function->name == "?=?" ) { // doesn't use isAssignment, because ?+=?, etc. should not count as self-assignment
    388                                 if ( appExpr->args.size() == 2 ) {
    389                                         // check for structural similarity (same variable use, ignore casts, etc. - but does not look too deeply, anything looking like a function is off limits)
    390                                         if ( structurallySimilar( appExpr->args.front(), appExpr->args.back() ) ) {
    391                                                 SemanticWarning( appExpr->location, Warning::SelfAssignment, toCString( appExpr->args.front() ) );
    392                                         }
    393                                 }
    394                         }
    395326                }
    396327
     
    437368                        // arrays are not copy constructed, so this should always be an ExprStmt
    438369                        ImplicitCtorDtorStmt * stmt = genCtorDtor( fname, var, cpArg );
    439                         assertf( stmt, "ResolveCopyCtors: genCtorDtor returned nullptr: %s / %s / %s", fname.c_str(), toString( var ).c_str(), toString( cpArg ).c_str() );
    440                         ExprStmt * exprStmt = strict_dynamic_cast< ExprStmt * >( stmt->callStmt );
     370                        ExprStmt * exprStmt = strict_dynamic_cast< ExprStmt * >( stmt->get_callStmt() );
    441371                        Expression * resolved = exprStmt->expr;
    442372                        exprStmt->expr = nullptr; // take ownership of expr
     
    448378                        ResolvExpr::findVoidExpression( resolved, indexer );
    449379                        assert( resolved );
    450                         if ( resolved->env ) {
     380                        if ( resolved->get_env() ) {
    451381                                // Extract useful information and discard new environments. Keeping them causes problems in PolyMutator passes.
    452                                 env->add( *resolved->env );
    453                                 delete resolved->env;
    454                                 resolved->env = nullptr;
     382                                env->add( *resolved->get_env() );
     383                                delete resolved->get_env();
     384                                resolved->set_env( nullptr );
    455385                        } // if
    456386                        delete stmt;
    457                         if ( TupleAssignExpr * assign = dynamic_cast< TupleAssignExpr * >( resolved ) ) {
    458                                 // fix newly generated StmtExpr
    459                                 postvisit( assign->stmtExpr );
    460                         }
    461387                        return resolved;
    462388                }
     
    552478                                static UniqueName retNamer("_tmp_stmtexpr_ret");
    553479
     480                                // create variable that will hold the result of the stmt expr
    554481                                result = result->clone();
    555482                                env->apply( result );
    556                                 if ( ! InitTweak::isConstructable( result ) ) {
    557                                         delete result;
    558                                         return;
    559                                 }
    560 
    561                                 // create variable that will hold the result of the stmt expr
    562483                                ObjectDecl * ret = ObjectDecl::newObject( retNamer.newName(), result, nullptr );
    563                                 ret->type->set_const( false );
    564                                 stmtExpr->returnDecls.push_front( ret );
     484                                ret->get_type()->set_const( false );
     485                                stmtExpr->get_returnDecls().push_front( ret );
    565486
    566487                                // must have a non-empty body, otherwise it wouldn't have a result
    567                                 CompoundStmt * body = stmtExpr->statements;
     488                                CompoundStmt * body = stmtExpr->get_statements();
    568489                                assert( ! body->get_kids().empty() );
    569490                                // must be an ExprStmt, otherwise it wouldn't have a result
    570491                                ExprStmt * last = strict_dynamic_cast< ExprStmt * >( body->get_kids().back() );
    571                                 last->expr = makeCtorDtor( "?{}", ret, last->get_expr() );
    572 
    573                                 stmtExpr->dtors.push_front( makeCtorDtor( "^?{}", ret ) );
     492                                last->set_expr( makeCtorDtor( "?{}", ret, last->get_expr() ) );
     493
     494                                stmtExpr->get_dtors().push_front( makeCtorDtor( "^?{}", ret ) );
    574495                        } // if
    575496                }
     
    634555                        // add destructors after current statement
    635556                        for ( Expression * dtor : dtors ) {
    636                                 // take relevant bindings from environment
    637                                 assert( ! dtor->env );
    638                                 dtor->env =  maybeClone( env );
    639557                                stmtsToAddAfter.push_back( new ExprStmt( dtor ) );
    640558                        } // for
     
    675593                        // to the outer context, rather than inside of the statement expression.
    676594                        visit_children = false;
    677                         std::list< Statement * > & stmts = stmtExpr->statements->get_kids();
     595                        std::list< Statement * > & stmts = stmtExpr->get_statements()->get_kids();
    678596                        for ( Statement *& stmt : stmts ) {
    679597                                stmt = stmt->acceptMutator( *visitor );
    680598                        } // for
    681                         assert( stmtExpr->result );
    682                         Type * result = stmtExpr->result;
     599                        assert( stmtExpr->get_result() );
     600                        Type * result = stmtExpr->get_result();
    683601                        if ( ! result->isVoid() ) {
    684                                 for ( ObjectDecl * obj : stmtExpr->returnDecls ) {
     602                                for ( ObjectDecl * obj : stmtExpr->get_returnDecls() ) {
    685603                                        stmtsToAddBefore.push_back( new DeclStmt( obj ) );
    686604                                } // for
    687605                                // add destructors after current statement
    688                                 for ( Expression * dtor : stmtExpr->dtors ) {
     606                                for ( Expression * dtor : stmtExpr->get_dtors() ) {
    689607                                        stmtsToAddAfter.push_back( new ExprStmt( dtor ) );
    690608                                } // for
    691609                                // must have a non-empty body, otherwise it wouldn't have a result
    692610                                assert( ! stmts.empty() );
    693                                 assertf( ! stmtExpr->returnDecls.empty() || stmtExpr->dtors.empty(), "StmtExpr returns non-void, but no return decls: %s", toString( stmtExpr ).c_str() );
    694                                 // if there is a return decl, add a use as the last statement; will not have return decl on non-constructable returns
    695                                 if ( ! stmtExpr->returnDecls.empty() ) {
    696                                         stmts.push_back( new ExprStmt( new VariableExpr( stmtExpr->returnDecls.front() ) ) );
    697                                 }
    698                                 stmtExpr->returnDecls.clear();
    699                                 stmtExpr->dtors.clear();
    700                         }
    701                         assert( stmtExpr->returnDecls.empty() );
    702                         assert( stmtExpr->dtors.empty() );
     611                                assert( ! stmtExpr->get_returnDecls().empty() );
     612                                stmts.push_back( new ExprStmt( new VariableExpr( stmtExpr->get_returnDecls().front() ) ) );
     613                                stmtExpr->get_returnDecls().clear();
     614                                stmtExpr->get_dtors().clear();
     615                        }
     616                        assert( stmtExpr->get_returnDecls().empty() );
     617                        assert( stmtExpr->get_dtors().empty() );
    703618                }
    704619
     
    730645                        }
    731646                        return;
     647                }
     648
     649                DeclarationWithType * getDtorFunc( ObjectDecl * objDecl, Statement * input, std::list< Statement * > & stmtsToAdd ) {
     650                        // unwrap implicit statement wrapper
     651                        Statement * dtor = input;
     652                        if ( ImplicitCtorDtorStmt * implicit = dynamic_cast< ImplicitCtorDtorStmt * >( input ) ) {
     653                                // dtor = implicit->callStmt;
     654                                // implicit->callStmt = nullptr;
     655                        }
     656                        assert( dtor );
     657                        std::list< Expression * > matches;
     658                        collectCtorDtorCalls( dtor, matches );
     659
     660                        if ( dynamic_cast< ExprStmt * >( dtor ) ) {
     661                                // only one destructor call in the expression
     662                                if ( matches.size() == 1 ) {
     663                                        DeclarationWithType * func = getFunction( matches.front() );
     664                                        assertf( func, "getFunction failed to find function in %s", toString( matches.front() ).c_str() );
     665
     666                                        // cleanup argument must be a function, not an object (including function pointer)
     667                                        if ( FunctionDecl * dtorFunc = dynamic_cast< FunctionDecl * > ( func ) ) {
     668                                                if ( dtorFunc->type->forall.empty() ) {
     669                                                        // simple case where the destructor is a monomorphic function call - can simply
     670                                                        // use that function as the cleanup function.
     671                                                        delete dtor;
     672                                                        return func;
     673                                                }
     674                                        }
     675                                }
     676                        }
     677
     678                        // otherwise the cleanup is more complicated - need to build a single argument cleanup function that
     679                        // wraps the more complicated code.
     680                        static UniqueName dtorNamer( "__cleanup_dtor" );
     681                        FunctionDecl * dtorFunc = FunctionDecl::newFunction( dtorNamer.newName(), SymTab::genDefaultType( objDecl->type->stripReferences(), false ), new CompoundStmt() );
     682                        stmtsToAdd.push_back( new DeclStmt( dtorFunc ) );
     683
     684                        // the original code contains uses of objDecl - replace them with the newly generated 'this' parameter.
     685                        ObjectDecl * thisParam = getParamThis( dtorFunc->type );
     686                        Expression * replacement = new VariableExpr( thisParam );
     687
     688                        Type * base = replacement->result->stripReferences();
     689                        if ( dynamic_cast< ArrayType * >( base ) || dynamic_cast< TupleType * > ( base ) ) {
     690                                // need to cast away reference for array types, since the destructor is generated without the reference type,
     691                                // and for tuple types since tuple indexing does not work directly on a reference
     692                                replacement = new CastExpr( replacement, base->clone() );
     693                        }
     694                        VarExprReplacer::replace( dtor, { std::make_pair( objDecl, replacement ) } );
     695                        dtorFunc->statements->push_back( dtor );
     696
     697                        return dtorFunc;
    732698                }
    733699
     
    844810                                                        ctorInit->ctor = nullptr;
    845811                                                }
     812
     813                                                Statement * dtor = ctorInit->dtor;
     814                                                if ( dtor ) {
     815                                                        ImplicitCtorDtorStmt * implicit = strict_dynamic_cast< ImplicitCtorDtorStmt * >( dtor );
     816                                                        Statement * dtorStmt = implicit->callStmt;
     817
     818                                                        // don't need to call intrinsic dtor, because it does nothing, but
     819                                                        // non-intrinsic dtors must be called
     820                                                        if ( ! isIntrinsicSingleArgCallStmt( dtorStmt ) ) {
     821                                                                // set dtor location to the object's location for error messages
     822                                                                DeclarationWithType * dtorFunc = getDtorFunc( objDecl, dtorStmt, stmtsToAddBefore );
     823                                                                objDecl->attributes.push_back( new Attribute( "cleanup", { new VariableExpr( dtorFunc ) } ) );
     824                                                                ctorInit->dtor = nullptr;
     825                                                        } // if
     826                                                }
    846827                                        } // if
    847828                                } else if ( Initializer * init = ctorInit->init ) {
     
    886867
    887868
    888                 template<typename Iterator, typename OutputIterator>
    889                 void insertDtors( Iterator begin, Iterator end, OutputIterator out ) {
    890                         for ( Iterator it = begin ; it != end ; ++it ) {
    891                                 // extract destructor statement from the object decl and insert it into the output. Note that this is
    892                                 // only called on lists of non-static objects with implicit non-intrinsic dtors, so if the user manually
    893                                 // calls an intrinsic dtor then the call must (and will) still be generated since the argument may
    894                                 // contain side effects.
    895                                 ObjectDecl * objDecl = *it;
    896                                 ConstructorInit * ctorInit = dynamic_cast< ConstructorInit * >( objDecl->get_init() );
    897                                 assert( ctorInit && ctorInit->get_dtor() );
    898                                 *out++ = ctorInit->get_dtor()->clone();
    899                         } // for
    900                 }
    901 
    902                 void InsertDtors::previsit( ObjectDecl * objDecl ) {
    903                         // remember non-static destructed objects so that their destructors can be inserted later
    904                         if ( ! objDecl->get_storageClasses().is_static ) {
    905                                 if ( ConstructorInit * ctorInit = dynamic_cast< ConstructorInit * >( objDecl->get_init() ) ) {
    906                                         // a decision should have been made by the resolver, so ctor and init are not both non-NULL
    907                                         assert( ! ctorInit->get_ctor() || ! ctorInit->get_init() );
    908                                         Statement * dtor = ctorInit->get_dtor();
    909                                         // don't need to call intrinsic dtor, because it does nothing, but
    910                                         // non-intrinsic dtors must be called
    911                                         if ( dtor && ! isIntrinsicSingleArgCallStmt( dtor ) ) {
    912                                                 // set dtor location to the object's location for error messages
    913                                                 ctorInit->dtor->location = objDecl->location;
    914                                                 reverseDeclOrder.front().push_front( objDecl );
    915                                         } // if
    916                                 } // if
    917                         } // if
    918                 }
    919 
    920869                void InsertDtors::previsit( FunctionDecl * funcDecl ) {
    921870                        // each function needs to have its own set of labels
     
    930879                }
    931880
    932                 void InsertDtors::previsit( CompoundStmt * compoundStmt ) {
    933                         // visit statements - this will also populate reverseDeclOrder list.  don't want to dump all destructors
    934                         // when block is left, just the destructors associated with variables defined in this block, so push a new
    935                         // list to the top of the stack so that we can differentiate scopes
    936                         reverseDeclOrder.push_front( OrderedDecls() );
    937                         Parent::previsit( compoundStmt );
    938                 }
    939 
    940                 void InsertDtors::postvisit( CompoundStmt * compoundStmt ) {
    941                         // add destructors for the current scope that we're exiting, unless the last statement is a return, which
    942                         // causes unreachable code warnings
    943                         std::list< Statement * > & statements = compoundStmt->get_kids();
    944                         if ( ! statements.empty() && ! dynamic_cast< ReturnStmt * >( statements.back() ) ) {
    945                                 insertDtors( reverseDeclOrder.front().begin(), reverseDeclOrder.front().end(), back_inserter( statements ) );
    946                         }
    947                         reverseDeclOrder.pop_front();
    948                 }
    949 
    950                 void InsertDtors::previsit( ReturnStmt * ) {
    951                         // return exits all scopes, so dump destructors for all scopes
    952                         for ( OrderedDecls & od : reverseDeclOrder ) {
    953                                 insertDtors( od.begin(), od.end(), back_inserter( stmtsToAddBefore ) );
    954                         } // for
    955                 }
    956 
    957881                // Handle break/continue/goto in the same manner as C++.  Basic idea: any objects that are in scope at the
    958882                // BranchStmt but not at the labelled (target) statement must be destructed.  If there are any objects in scope
     
    981905                        )
    982906                        if ( ! diff.empty() ) {
    983                                 SemanticError( stmt, std::string("jump to label '") + stmt->get_target().get_name() + "' crosses initialization of " + (*diff.begin())->get_name() + " " );
    984                         } // if
    985                         // S_G-S_L results in set of objects that must be destructed
    986                         diff.clear();
    987                         std::set_difference( curVars.begin(), curVars.end(), lvars.begin(), lvars.end(), std::inserter( diff, diff.end() ) );
    988                         DTOR_PRINT(
    989                                 std::cerr << "S_G-S_L = " << printSet( diff ) << std::endl;
    990                         )
    991                         if ( ! diff.empty() ) {
    992                                 // create an auxilliary set for fast lookup -- can't make diff a set, because diff ordering should be consistent for error messages.
    993                                 std::unordered_set<ObjectDecl *> needsDestructor( diff.begin(), diff.end() );
    994 
    995                                 // go through decl ordered list of objectdecl. for each element that occurs in diff, output destructor
    996                                 OrderedDecls ordered;
    997                                 for ( OrderedDecls & rdo : reverseDeclOrder ) {
    998                                         // add elements from reverseDeclOrder into ordered if they occur in diff - it is key that this happens in reverse declaration order.
    999                                         copy_if( rdo.begin(), rdo.end(), back_inserter( ordered ), [&]( ObjectDecl * objDecl ) { return needsDestructor.count( objDecl ); } );
    1000                                 } // for
    1001                                 insertDtors( ordered.begin(), ordered.end(), back_inserter( stmtsToAddBefore ) );
     907                                throw SemanticError( std::string("jump to label '") + stmt->get_target().get_name() + "' crosses initialization of " + (*diff.begin())->get_name() + " ", stmt );
    1002908                        } // if
    1003909                }
     
    1025931                }
    1026932
    1027                 void GenStructMemberCalls::premutate( FunctionDecl * funcDecl ) {
     933                void GenStructMemberCalls::previsit( StructDecl * structDecl ) {
     934                        if ( ! dtorStruct && structDecl->name == "__Destructor" ) {
     935                                dtorStruct = structDecl;
     936                        }
     937                }
     938
     939                void GenStructMemberCalls::previsit( FunctionDecl * funcDecl ) {
    1028940                        GuardValue( function );
    1029941                        GuardValue( unhandled );
     
    1032944                        GuardValue( isCtor );
    1033945                        GuardValue( structDecl );
    1034                         errors = SemanticErrorException();  // clear previous errors
     946                        errors = SemanticError();  // clear previous errors
    1035947
    1036948                        // need to start with fresh sets
    1037949                        unhandled.clear();
    1038950                        usedUninit.clear();
     951
     952                        if ( ! dtorStructDestroy && funcDecl->name == "__destroy_Destructor" ) {
     953                                dtorStructDestroy = funcDecl;
     954                                return;
     955                        }
    1039956
    1040957                        function = funcDecl;
     
    1048965                                if ( structType ) {
    1049966                                        structDecl = structType->get_baseStruct();
     967                                        if ( structDecl == dtorStruct ) return;
    1050968                                        for ( Declaration * member : structDecl->get_members() ) {
    1051969                                                if ( ObjectDecl * field = dynamic_cast< ObjectDecl * >( member ) ) {
     
    1059977                }
    1060978
    1061                 DeclarationWithType * GenStructMemberCalls::postmutate( FunctionDecl * funcDecl ) {
     979                void GenStructMemberCalls::postvisit( FunctionDecl * funcDecl ) {
    1062980                        // remove the unhandled objects from usedUninit, because a call is inserted
    1063981                        // to handle them - only objects that are later constructed are used uninitialized.
     
    11131031                                                Statement * callStmt = stmt.front();
    11141032
     1033                                                MutatingResolver resolver( indexer );
    11151034                                                try {
    1116                                                         callStmt->acceptMutator( *visitor );
     1035                                                        callStmt->acceptMutator( resolver );
    11171036                                                        if ( isCtor ) {
    1118                                                                 function->get_statements()->push_front( callStmt );
     1037                                                                function->statements->push_front( callStmt );
    11191038                                                        } else {
    11201039                                                                // destructor statements should be added at the end
    1121                                                                 function->get_statements()->push_back( callStmt );
     1040                                                                // function->get_statements()->push_back( callStmt );
     1041
     1042                                                                // Destructor _dtor0 = { &b.a1, (void (*)(void *)_destroy_A };
     1043                                                                std::list< Statement * > stmtsToAdd;
     1044
     1045                                                                static UniqueName memberDtorNamer = { "__memberDtor" };
     1046                                                                assertf( dtorStruct, "builtin __Destructor not found." );
     1047                                                                assertf( dtorStructDestroy, "builtin __destroy_Destructor not found." );
     1048
     1049                                                                Expression * thisExpr = new AddressExpr( new VariableExpr( thisParam ) );
     1050                                                                Expression * dtorExpr = new VariableExpr( getDtorFunc( thisParam, callStmt, stmtsToAdd ) );
     1051
     1052                                                                // cast destructor pointer to void (*)(void *), to silence GCC incompatible pointer warnings
     1053                                                                FunctionType * dtorFtype = new FunctionType( Type::Qualifiers(), false );
     1054                                                                dtorFtype->parameters.push_back( ObjectDecl::newObject( "", new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ), nullptr ) );
     1055                                                                Type * dtorType = new PointerType( Type::Qualifiers(), dtorFtype );
     1056
     1057                                                                ObjectDecl * destructor = ObjectDecl::newObject( memberDtorNamer.newName(), new StructInstType( Type::Qualifiers(), dtorStruct ), new ListInit( { new SingleInit( thisExpr ), new SingleInit( new CastExpr( dtorExpr, dtorType ) ) } ) );
     1058                                                                function->statements->push_front( new DeclStmt( destructor ) );
     1059                                                                destructor->attributes.push_back( new Attribute( "cleanup", { new VariableExpr( dtorStructDestroy ) } ) );
     1060
     1061                                                                function->statements->kids.splice( function->statements->kids.begin(), stmtsToAdd );
    11221062                                                        }
    1123                                                 } catch ( SemanticErrorException & error ) {
     1063                                                } catch ( SemanticError & error ) {
    11241064                                                        emit( funcDecl->location, "in ", CodeGen::genPrettyType( function->get_functionType(), function->get_name() ), ", field ", field->get_name(), " not explicitly ", isCtor ? "constructed" : "destructed",  " and no ", isCtor ? "default constructor" : "destructor", " found" );
    11251065                                                }
     
    11301070                                throw errors;
    11311071                        }
    1132                         return funcDecl;
    11331072                }
    11341073
     
    11561095                }
    11571096
    1158                 void GenStructMemberCalls::premutate( ApplicationExpr * appExpr ) {
     1097                void GenStructMemberCalls::previsit( ApplicationExpr * appExpr ) {
    11591098                        if ( ! checkWarnings( function ) ) {
    11601099                                visit_children = false;
     
    11631102
    11641103                        std::string fname = getFunctionName( appExpr );
    1165                         if ( fname == function->name ) {
     1104                        if ( fname == function->get_name() ) {
    11661105                                // call to same kind of function
    1167                                 Expression * firstParam = appExpr->args.front();
     1106                                Expression * firstParam = appExpr->get_args().front();
    11681107
    11691108                                if ( isThisExpression( firstParam, thisParam ) ) {
     
    11741113                                        // if first parameter is a member expression on the this parameter,
    11751114                                        // then remove the member from unhandled set.
    1176                                         if ( isThisExpression( memberExpr->aggregate, thisParam ) ) {
    1177                                                 unhandled.erase( memberExpr->member );
     1115                                        if ( isThisExpression( memberExpr->get_aggregate(), thisParam ) ) {
     1116                                                unhandled.erase( memberExpr->get_member() );
    11781117                                        }
    11791118                                }
     
    11811120                }
    11821121
    1183                 void GenStructMemberCalls::premutate( MemberExpr * memberExpr ) {
     1122                void GenStructMemberCalls::previsit( MemberExpr * memberExpr ) {
    11841123                        if ( ! checkWarnings( function ) || ! isCtor ) {
    11851124                                visit_children = false;
     
    11971136                template< typename Visitor, typename... Params >
    11981137                void error( Visitor & v, CodeLocation loc, const Params &... params ) {
    1199                         SemanticErrorException err( loc, toString( params... ) );
     1138                        SemanticError err( toString( params... ) );
     1139                        err.set_location( loc );
    12001140                        v.errors.append( err );
    12011141                }
     
    12081148                }
    12091149
    1210                 Expression * GenStructMemberCalls::postmutate( UntypedExpr * untypedExpr ) {
     1150                DeclarationWithType * MutatingResolver::mutate( ObjectDecl * objectDecl ) {
     1151                        // add object to the indexer assumes that there will be no name collisions
     1152                        // in generated code. If this changes, add mutate methods for entities with
     1153                        // scope and call {enter,leave}Scope explicitly.
     1154                        indexer.addId( objectDecl );
     1155                        return objectDecl;
     1156                }
     1157
     1158                Expression * MutatingResolver::mutate( UntypedExpr * untypedExpr ) {
    12111159                        Expression * newExpr = untypedExpr;
    12121160                        ResolvExpr::findVoidExpression( newExpr, indexer );
Note: See TracChangeset for help on using the changeset viewer.