Changeset c2931ea for src/InitTweak
- Timestamp:
- Jun 23, 2016, 12:17:31 PM (8 years ago)
- Branches:
- ADT, aaron-thesis, arm-eh, ast-experimental, cleanup-dtors, ctor, deferred_resn, demangler, enum, forall-pointer-decay, gc_noraii, jacob/cs343-translation, jenkins-sandbox, master, memory, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, resolv-new, with_gc
- Children:
- f1ee72e
- Parents:
- 71a145de
- git-author:
- Rob Schluntz <rschlunt@…> (06/23/16 11:37:51)
- git-committer:
- Rob Schluntz <rschlunt@…> (06/23/16 12:17:31)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/InitTweak/FixInit.cc
r71a145de rc2931ea 16 16 #include <stack> 17 17 #include <list> 18 #include <iterator> 19 #include <algorithm> 18 20 #include "FixInit.h" 19 21 #include "InitTweak.h" … … 28 30 #include "SymTab/Indexer.h" 29 31 #include "GenPoly/PolyMutator.h" 32 #include "SynTree/AddStmtVisitor.h" 30 33 31 34 bool ctordtorp = false; 35 bool ctorp = false; 36 bool cpctorp = false; 37 bool dtorp = true; 32 38 #define PRINT( text ) if ( ctordtorp ) { text } 39 #define CP_CTOR_PRINT( text ) if ( ctordtorp || cpctorp ) { text } 40 #define DTOR_PRINT( text ) if ( ctordtorp || dtorp ) { text } 33 41 34 42 namespace InitTweak { … … 36 44 const std::list<Label> noLabels; 37 45 const std::list<Expression*> noDesignators; 38 } 39 40 class InsertImplicitCalls : public GenPoly::PolyMutator { 41 public: 42 /// wrap function application expressions as ImplicitCopyCtorExpr nodes 43 /// so that it is easy to identify which function calls need their parameters 44 /// to be copy constructed 45 static void insert( std::list< Declaration * > & translationUnit ); 46 47 virtual Expression * mutate( ApplicationExpr * appExpr ); 48 }; 49 50 class ResolveCopyCtors : public SymTab::Indexer { 51 public: 52 /// generate temporary ObjectDecls for each argument and return value of each 53 /// ImplicitCopyCtorExpr, generate/resolve copy construction expressions for each, 54 /// and generate/resolve destructors for both arguments and return value temporaries 55 static void resolveImplicitCalls( std::list< Declaration * > & translationUnit ); 56 57 virtual void visit( ImplicitCopyCtorExpr * impCpCtorExpr ); 58 59 /// create and resolve ctor/dtor expression: fname(var, [cpArg]) 60 ApplicationExpr * makeCtorDtor( const std::string & fname, ObjectDecl * var, Expression * cpArg = NULL ); 61 /// true if type does not need to be copy constructed to ensure correctness 62 bool skipCopyConstruct( Type * ); 63 private: 64 TypeSubstitution * env; 65 }; 66 67 class FixInit : public GenPoly::PolyMutator { 68 public: 69 /// expand each object declaration to use its constructor after it is declared. 70 /// insert destructor calls at the appropriate places 71 static void fixInitializers( std::list< Declaration * > &translationUnit ); 72 73 virtual DeclarationWithType * mutate( ObjectDecl *objDecl ); 74 75 virtual CompoundStmt * mutate( CompoundStmt * compoundStmt ); 76 virtual Statement * mutate( ReturnStmt * returnStmt ); 77 virtual Statement * mutate( BranchStmt * branchStmt ); 78 79 private: 80 // stack of list of statements - used to differentiate scopes 81 std::list< std::list< Statement * > > dtorStmts; 82 }; 83 84 class FixCopyCtors : public GenPoly::PolyMutator { 85 public: 86 /// expand ImplicitCopyCtorExpr nodes into the temporary declarations, copy constructors, 87 /// call expression, and destructors 88 static void fixCopyCtors( std::list< Declaration * > &translationUnit ); 89 90 virtual Expression * mutate( ImplicitCopyCtorExpr * impCpCtorExpr ); 91 92 private: 93 // stack of list of statements - used to differentiate scopes 94 std::list< std::list< Statement * > > dtorStmts; 95 }; 46 47 class InsertImplicitCalls : public GenPoly::PolyMutator { 48 public: 49 /// wrap function application expressions as ImplicitCopyCtorExpr nodes 50 /// so that it is easy to identify which function calls need their parameters 51 /// to be copy constructed 52 static void insert( std::list< Declaration * > & translationUnit ); 53 54 virtual Expression * mutate( ApplicationExpr * appExpr ); 55 }; 56 57 class ResolveCopyCtors : public SymTab::Indexer { 58 public: 59 /// generate temporary ObjectDecls for each argument and return value of each 60 /// ImplicitCopyCtorExpr, generate/resolve copy construction expressions for each, 61 /// and generate/resolve destructors for both arguments and return value temporaries 62 static void resolveImplicitCalls( std::list< Declaration * > & translationUnit ); 63 64 virtual void visit( ImplicitCopyCtorExpr * impCpCtorExpr ); 65 66 /// create and resolve ctor/dtor expression: fname(var, [cpArg]) 67 ApplicationExpr * makeCtorDtor( const std::string & fname, ObjectDecl * var, Expression * cpArg = NULL ); 68 /// true if type does not need to be copy constructed to ensure correctness 69 bool skipCopyConstruct( Type * ); 70 private: 71 TypeSubstitution * env; 72 }; 73 74 /// collects constructed object decls - used as a base class 75 class ObjDeclCollector : public AddStmtVisitor { 76 public: 77 typedef AddStmtVisitor Parent; 78 using Parent::visit; 79 typedef std::set< ObjectDecl * > ObjectSet; 80 virtual void visit( CompoundStmt *compoundStmt ); 81 virtual void visit( DeclStmt *stmt ); 82 protected: 83 ObjectSet curVars; 84 }; 85 86 struct printSet { 87 typedef ObjDeclCollector::ObjectSet ObjectSet; 88 printSet( const ObjectSet & objs ) : objs( objs ) {} 89 const ObjectSet & objs; 90 }; 91 std::ostream & operator<<( std::ostream & out, const printSet & set) { 92 out << "{ "; 93 for ( ObjectDecl * obj : set.objs ) { 94 out << obj->get_name() << ", " ; 95 } 96 out << " }"; 97 return out; 98 } 99 100 class LabelFinder : public ObjDeclCollector { 101 public: 102 typedef ObjDeclCollector Parent; 103 typedef std::map< Label, ObjectSet > LabelMap; 104 // map of Label -> live variables at that label 105 LabelMap vars; 106 107 void handleStmt( Statement * stmt ); 108 109 // xxx - This needs to be done better. 110 // allow some generalization among different kinds of nodes with 111 // with similar parentage (e.g. all expressions, all statements, etc.) 112 // important to have this to provide a single entry point so that as 113 // new subclasses are added, there is only one place that the code has 114 // to be updated, rather than ensure that every specialized class knows 115 // about every new kind of statement that might be added. 116 virtual void visit( CompoundStmt *stmt ) { handleStmt( stmt ); return Parent::visit( stmt ); } 117 virtual void visit( ExprStmt *stmt ) { handleStmt( stmt ); return Parent::visit( stmt ); } 118 virtual void visit( AsmStmt *stmt ) { handleStmt( stmt ); return Parent::visit( stmt ); } 119 virtual void visit( IfStmt *stmt ) { handleStmt( stmt ); return Parent::visit( stmt ); } 120 virtual void visit( WhileStmt *stmt ) { handleStmt( stmt ); return Parent::visit( stmt ); } 121 virtual void visit( ForStmt *stmt ) { handleStmt( stmt ); return Parent::visit( stmt ); } 122 virtual void visit( SwitchStmt *stmt ) { handleStmt( stmt ); return Parent::visit( stmt ); } 123 virtual void visit( ChooseStmt *stmt ) { handleStmt( stmt ); return Parent::visit( stmt ); } 124 virtual void visit( FallthruStmt *stmt ) { handleStmt( stmt ); return Parent::visit( stmt ); } 125 virtual void visit( CaseStmt *stmt ) { handleStmt( stmt ); return Parent::visit( stmt ); } 126 virtual void visit( BranchStmt *stmt ) { handleStmt( stmt ); return Parent::visit( stmt ); } 127 virtual void visit( ReturnStmt *stmt ) { handleStmt( stmt ); return Parent::visit( stmt ); } 128 virtual void visit( TryStmt *stmt ) { handleStmt( stmt ); return Parent::visit( stmt ); } 129 virtual void visit( CatchStmt *stmt ) { handleStmt( stmt ); return Parent::visit( stmt ); } 130 virtual void visit( FinallyStmt *stmt ) { handleStmt( stmt ); return Parent::visit( stmt ); } 131 virtual void visit( NullStmt *stmt ) { handleStmt( stmt ); return Parent::visit( stmt ); } 132 virtual void visit( DeclStmt *stmt ) { handleStmt( stmt ); return Parent::visit( stmt ); } 133 virtual void visit( ImplicitCtorDtorStmt *stmt ) { handleStmt( stmt ); return Parent::visit( stmt ); } 134 }; 135 136 class InsertDtors : public ObjDeclCollector { 137 public: 138 /// insert destructor calls at the appropriate places. 139 /// must happen before CtorInit nodes are removed (currently by FixInit) 140 static void insert( std::list< Declaration * > & translationUnit ); 141 142 typedef ObjDeclCollector Parent; 143 typedef std::list< ObjectDecl * > OrderedDecls; 144 typedef std::list< OrderedDecls > OrderedDeclsStack; 145 146 InsertDtors( LabelFinder & finder ) : labelVars( finder.vars ) {} 147 148 virtual void visit( ObjectDecl * objDecl ); 149 150 virtual void visit( CompoundStmt * compoundStmt ); 151 virtual void visit( ReturnStmt * returnStmt ); 152 virtual void visit( BranchStmt * stmt ); 153 private: 154 void handleGoto( BranchStmt * stmt ); 155 156 LabelFinder::LabelMap & labelVars; 157 OrderedDeclsStack reverseDeclOrder; 158 }; 159 160 class FixInit : public GenPoly::PolyMutator { 161 public: 162 /// expand each object declaration to use its constructor after it is declared. 163 static void fixInitializers( std::list< Declaration * > &translationUnit ); 164 165 virtual DeclarationWithType * mutate( ObjectDecl *objDecl ); 166 }; 167 168 class FixCopyCtors : public GenPoly::PolyMutator { 169 public: 170 /// expand ImplicitCopyCtorExpr nodes into the temporary declarations, copy constructors, 171 /// call expression, and destructors 172 static void fixCopyCtors( std::list< Declaration * > &translationUnit ); 173 174 virtual Expression * mutate( ImplicitCopyCtorExpr * impCpCtorExpr ); 175 }; 176 } // namespace 96 177 97 178 void fix( std::list< Declaration * > & translationUnit ) { 98 179 InsertImplicitCalls::insert( translationUnit ); 99 180 ResolveCopyCtors::resolveImplicitCalls( translationUnit ); 181 InsertDtors::insert( translationUnit ); 100 182 FixInit::fixInitializers( translationUnit ); 183 101 184 // FixCopyCtors must happen after FixInit, so that destructors are placed correctly 102 185 FixCopyCtors::fixCopyCtors( translationUnit ); 103 186 } 104 187 105 void InsertImplicitCalls::insert( std::list< Declaration * > & translationUnit ) { 106 InsertImplicitCalls inserter; 107 mutateAll( translationUnit, inserter ); 108 } 109 110 void ResolveCopyCtors::resolveImplicitCalls( std::list< Declaration * > & translationUnit ) { 111 ResolveCopyCtors resolver; 112 acceptAll( translationUnit, resolver ); 113 } 114 115 void FixInit::fixInitializers( std::list< Declaration * > & translationUnit ) { 116 FixInit fixer; 117 mutateAll( translationUnit, fixer ); 118 } 119 120 void FixCopyCtors::fixCopyCtors( std::list< Declaration * > & translationUnit ) { 121 FixCopyCtors fixer; 122 mutateAll( translationUnit, fixer ); 123 } 124 125 Expression * InsertImplicitCalls::mutate( ApplicationExpr * appExpr ) { 126 appExpr = dynamic_cast< ApplicationExpr * >( Mutator::mutate( appExpr ) ); 127 assert( appExpr ); 128 129 if ( VariableExpr * function = dynamic_cast< VariableExpr * > ( appExpr->get_function() ) ) { 130 if ( function->get_var()->get_linkage() == LinkageSpec::Intrinsic ) { 131 // optimization: don't need to copy construct in order to call intrinsic functions 132 return appExpr; 133 } else if ( DeclarationWithType * funcDecl = dynamic_cast< DeclarationWithType * > ( function->get_var() ) ) { 134 FunctionType * ftype = dynamic_cast< FunctionType * >( GenPoly::getFunctionType( funcDecl->get_type() ) ); 135 assert( ftype ); 136 if ( (funcDecl->get_name() == "?{}" || funcDecl->get_name() == "?=?") && ftype->get_parameters().size() == 2 ) { 137 Type * t1 = ftype->get_parameters().front()->get_type(); 138 Type * t2 = ftype->get_parameters().back()->get_type(); 139 PointerType * ptrType = dynamic_cast< PointerType * > ( t1 ); 140 assert( ptrType ); 141 142 if ( ResolvExpr::typesCompatible( ptrType->get_base(), t2, SymTab::Indexer() ) ) { 143 // optimization: don't need to copy construct in order to call a copy constructor or 144 // assignment operator 188 namespace { 189 void InsertImplicitCalls::insert( std::list< Declaration * > & translationUnit ) { 190 InsertImplicitCalls inserter; 191 mutateAll( translationUnit, inserter ); 192 } 193 194 void ResolveCopyCtors::resolveImplicitCalls( std::list< Declaration * > & translationUnit ) { 195 ResolveCopyCtors resolver; 196 acceptAll( translationUnit, resolver ); 197 } 198 199 void FixInit::fixInitializers( std::list< Declaration * > & translationUnit ) { 200 FixInit fixer; 201 mutateAll( translationUnit, fixer ); 202 } 203 204 void InsertDtors::insert( std::list< Declaration * > & translationUnit ) { 205 LabelFinder finder; 206 InsertDtors inserter( finder ); 207 acceptAll( translationUnit, finder ); 208 acceptAll( translationUnit, inserter ); 209 } 210 211 void FixCopyCtors::fixCopyCtors( std::list< Declaration * > & translationUnit ) { 212 FixCopyCtors fixer; 213 mutateAll( translationUnit, fixer ); 214 } 215 216 Expression * InsertImplicitCalls::mutate( ApplicationExpr * appExpr ) { 217 appExpr = dynamic_cast< ApplicationExpr * >( Mutator::mutate( appExpr ) ); 218 assert( appExpr ); 219 220 if ( VariableExpr * function = dynamic_cast< VariableExpr * > ( appExpr->get_function() ) ) { 221 if ( function->get_var()->get_linkage() == LinkageSpec::Intrinsic ) { 222 // optimization: don't need to copy construct in order to call intrinsic functions 223 return appExpr; 224 } else if ( DeclarationWithType * funcDecl = dynamic_cast< DeclarationWithType * > ( function->get_var() ) ) { 225 FunctionType * ftype = dynamic_cast< FunctionType * >( GenPoly::getFunctionType( funcDecl->get_type() ) ); 226 assert( ftype ); 227 if ( (funcDecl->get_name() == "?{}" || funcDecl->get_name() == "?=?") && ftype->get_parameters().size() == 2 ) { 228 Type * t1 = ftype->get_parameters().front()->get_type(); 229 Type * t2 = ftype->get_parameters().back()->get_type(); 230 PointerType * ptrType = dynamic_cast< PointerType * > ( t1 ); 231 assert( ptrType ); 232 233 if ( ResolvExpr::typesCompatible( ptrType->get_base(), t2, SymTab::Indexer() ) ) { 234 // optimization: don't need to copy construct in order to call a copy constructor or 235 // assignment operator 236 return appExpr; 237 } 238 } else if ( funcDecl->get_name() == "^?{}" ) { 239 // correctness: never copy construct arguments to a destructor 145 240 return appExpr; 146 241 } 147 } else if ( funcDecl->get_name() == "^?{}" ) {148 // correctness: never copy construct arguments to a destructor149 return appExpr;150 242 } 151 243 } 152 } 153 PRINT( std::cerr << "InsertImplicitCalls: adding a wrapper " << appExpr << std::endl; ) 154 155 // wrap each function call so that it is easy to identify nodes that have to be copy constructed 156 ImplicitCopyCtorExpr * expr = new ImplicitCopyCtorExpr( appExpr ); 157 // save the type substitution onto the new node so that it is easy to find. 158 // Ensure it is not deleted with the ImplicitCopyCtorExpr by removing it before deletion. 159 // The substitution is needed to obtain the type of temporary variables so that copy constructor 160 // calls can be resolved. Normally this is what PolyMutator is for, but the pass that resolves 161 // copy constructor calls must be an Indexer. We could alternatively make a PolyIndexer which 162 // saves the environment, or compute the types of temporaries here, but it's much simpler to 163 // save the environment here, and more cohesive to compute temporary variables and resolve copy 164 // constructor calls together. 165 assert( env ); 166 expr->set_env( env ); 167 return expr; 168 } 169 170 bool ResolveCopyCtors::skipCopyConstruct( Type * type ) { 171 return dynamic_cast< VarArgsType * >( type ) || GenPoly::getFunctionType( type ); 172 } 173 174 ApplicationExpr * ResolveCopyCtors::makeCtorDtor( const std::string & fname, ObjectDecl * var, Expression * cpArg ) { 175 assert( var ); 176 UntypedExpr * untyped = new UntypedExpr( new NameExpr( fname ) ); 177 untyped->get_args().push_back( new AddressExpr( new VariableExpr( var ) ) ); 178 if (cpArg) untyped->get_args().push_back( cpArg ); 179 180 // resolve copy constructor 181 // should only be one alternative for copy ctor and dtor expressions, since 182 // all arguments are fixed (VariableExpr and already resolved expression) 183 PRINT( std::cerr << "ResolvingCtorDtor " << untyped << std::endl; ) 184 ApplicationExpr * resolved = dynamic_cast< ApplicationExpr * >( ResolvExpr::findVoidExpression( untyped, *this ) ); 185 if ( resolved->get_env() ) { 186 env->add( *resolved->get_env() ); 187 } 188 189 assert( resolved ); 190 delete untyped; 191 return resolved; 192 } 193 194 void ResolveCopyCtors::visit( ImplicitCopyCtorExpr *impCpCtorExpr ) { 195 static UniqueName tempNamer("_tmp_cp"); 196 static UniqueName retNamer("_tmp_cp_ret"); 197 198 PRINT( std::cerr << "ResolveCopyCtors: " << impCpCtorExpr << std::endl; ) 199 Visitor::visit( impCpCtorExpr ); 200 env = impCpCtorExpr->get_env(); // xxx - maybe we really should just have a PolyIndexer... 201 202 ApplicationExpr * appExpr = impCpCtorExpr->get_callExpr(); 203 204 // take each argument and attempt to copy construct it. 205 for ( Expression * & arg : appExpr->get_args() ) { 206 PRINT( std::cerr << "Type Substitution: " << *impCpCtorExpr->get_env() << std::endl; ) 207 // xxx - need to handle tuple arguments 208 assert( ! arg->get_results().empty() ); 209 Type * result = arg->get_results().front(); 210 if ( skipCopyConstruct( result ) ) continue; // skip certain non-copyable types 211 // type may involve type variables, so apply type substitution to get temporary variable's actual type 212 result = result->clone(); 213 impCpCtorExpr->get_env()->apply( result ); 214 ObjectDecl * tmp = new ObjectDecl( tempNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, result, 0 ); 215 tmp->get_type()->set_isConst( false ); 216 217 // create and resolve copy constructor 218 PRINT( std::cerr << "makeCtorDtor for an argument" << std::endl; ) 219 ApplicationExpr * cpCtor = makeCtorDtor( "?{}", tmp, arg ); 220 221 // if the chosen constructor is intrinsic, the copy is unnecessary, so 222 // don't create the temporary and don't call the copy constructor 223 VariableExpr * function = dynamic_cast< VariableExpr * >( cpCtor->get_function() ); 224 assert( function ); 225 if ( function->get_var()->get_linkage() != LinkageSpec::Intrinsic ) { 226 // replace argument to function call with temporary 227 arg = new CommaExpr( cpCtor, new VariableExpr( tmp ) ); 228 impCpCtorExpr->get_tempDecls().push_back( tmp ); 229 impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", tmp ) ); 230 } 231 } 232 233 // each return value from the call needs to be connected with an ObjectDecl 234 // at the call site, which is initialized with the return value and is destructed 235 // later 236 // xxx - handle multiple return values 237 ApplicationExpr * callExpr = impCpCtorExpr->get_callExpr(); 238 // xxx - is this right? callExpr may not have the right environment, because it was attached 239 // at a higher level. Trying to pass that environment along. 240 callExpr->set_env( impCpCtorExpr->get_env()->clone() ); 241 for ( Type * result : appExpr->get_results() ) { 242 result = result->clone(); 243 impCpCtorExpr->get_env()->apply( result ); 244 ObjectDecl * ret = new ObjectDecl( retNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, result, 0 ); 245 ret->get_type()->set_isConst( false ); 246 impCpCtorExpr->get_returnDecls().push_back( ret ); 247 PRINT( std::cerr << "makeCtorDtor for a return" << std::endl; ) 248 impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", ret ) ); 249 } 250 PRINT( std::cerr << "after Resolving: " << impCpCtorExpr << std::endl; ) 251 } 252 253 254 Expression * FixCopyCtors::mutate( ImplicitCopyCtorExpr * impCpCtorExpr ) { 255 PRINT( std::cerr << "FixCopyCtors: " << impCpCtorExpr << std::endl; ) 256 257 impCpCtorExpr = dynamic_cast< ImplicitCopyCtorExpr * >( Mutator::mutate( impCpCtorExpr ) ); 258 assert( impCpCtorExpr ); 259 260 std::list< ObjectDecl * > & tempDecls = impCpCtorExpr->get_tempDecls(); 261 std::list< ObjectDecl * > & returnDecls = impCpCtorExpr->get_returnDecls(); 262 std::list< Expression * > & dtors = impCpCtorExpr->get_dtors(); 263 264 // add all temporary declarations and their constructors 265 for ( ObjectDecl * obj : tempDecls ) { 266 stmtsToAdd.push_back( new DeclStmt( noLabels, obj ) ); 267 } 268 for ( ObjectDecl * obj : returnDecls ) { 269 stmtsToAdd.push_back( new DeclStmt( noLabels, obj ) ); 270 } 271 272 // add destructors after current statement 273 for ( Expression * dtor : dtors ) { 274 stmtsToAddAfter.push_back( new ExprStmt( noLabels, dtor ) ); 275 } 276 277 // xxx - update to work with multiple return values 278 ObjectDecl * returnDecl = returnDecls.empty() ? NULL : returnDecls.front(); 279 Expression * callExpr = impCpCtorExpr->get_callExpr(); 280 281 PRINT( std::cerr << "Coming out the back..." << impCpCtorExpr << std::endl; ) 282 283 // detach fields from wrapper node so that it can be deleted without deleting too much 284 dtors.clear(); 285 tempDecls.clear(); 286 returnDecls.clear(); 287 impCpCtorExpr->set_callExpr( NULL ); 288 impCpCtorExpr->set_env( NULL ); 289 delete impCpCtorExpr; 290 291 if ( returnDecl ) { 292 UntypedExpr * assign = new UntypedExpr( new NameExpr( "?=?" ) ); 293 assign->get_args().push_back( new VariableExpr( returnDecl ) ); 294 assign->get_args().push_back( callExpr ); 295 // know the result type of the assignment is the type of the LHS (minus the pointer), so 296 // add that onto the assignment expression so that later steps have the necessary information 297 assign->add_result( returnDecl->get_type()->clone() ); 298 299 Expression * retExpr = new CommaExpr( assign, new VariableExpr( returnDecl ) ); 300 if ( callExpr->get_results().front()->get_isLvalue() ) { 301 // lvalue returning functions are funny. Lvalue.cc inserts a *? in front of any 302 // lvalue returning non-intrinsic function. Add an AddressExpr to the call to negate 303 // the derefence and change the type of the return temporary from T to T* to properly 304 // capture the return value. Then dereference the result of the comma expression, since 305 // the lvalue returning call was originally wrapped with an AddressExpr. 306 // Effectively, this turns 307 // lvalue T f(); 308 // &*f() 309 // into 310 // T * tmp_cp_retN; 311 // tmp_cp_ret_N = &*(tmp_cp_ret_N = &*f(), tmp_cp_ret); 312 // which work out in terms of types, but is pretty messy. It would be nice to find a better way. 313 assign->get_args().back() = new AddressExpr( assign->get_args().back() ); 314 315 Type * resultType = returnDecl->get_type()->clone(); 316 returnDecl->set_type( new PointerType( Type::Qualifiers(), returnDecl->get_type() ) ); 317 UntypedExpr * deref = new UntypedExpr( new NameExpr( "*?" ) ); 318 deref->get_args().push_back( retExpr ); 319 deref->add_result( resultType ); 320 retExpr = deref; 321 } 322 // xxx - might need to set env on retExpr... 323 // retExpr->set_env( env->clone() ); 324 return retExpr; 325 } else { 326 return callExpr; 327 } 328 } 329 330 DeclarationWithType *FixInit::mutate( ObjectDecl *objDecl ) { 331 // first recursively handle pieces of ObjectDecl so that they aren't missed by other visitors 332 // when the init is removed from the ObjectDecl 333 objDecl = dynamic_cast< ObjectDecl * >( Mutator::mutate( objDecl ) ); 334 335 if ( ConstructorInit * ctorInit = dynamic_cast< ConstructorInit * >( objDecl->get_init() ) ) { 336 // a decision should have been made by the resolver, so ctor and init are not both non-NULL 337 assert( ! ctorInit->get_ctor() || ! ctorInit->get_init() ); 338 if ( Statement * ctor = ctorInit->get_ctor() ) { 339 if ( objDecl->get_storageClass() == DeclarationNode::Static ) { 340 // generate: 341 // static bool __objName_uninitialized = true; 342 // if (__objName_uninitialized) { 343 // __ctor(__objName); 344 // void dtor_atexit() { 345 // __dtor(__objName); 346 // } 347 // on_exit(dtorOnExit, &__objName); 348 // __objName_uninitialized = false; 349 // } 350 351 // generate first line 352 BasicType * boolType = new BasicType( Type::Qualifiers(), BasicType::Bool ); 353 SingleInit * boolInitExpr = new SingleInit( new ConstantExpr( Constant( boolType->clone(), "1" ) ), noDesignators ); 354 ObjectDecl * isUninitializedVar = new ObjectDecl( objDecl->get_mangleName() + "_uninitialized", DeclarationNode::Static, LinkageSpec::Cforall, 0, boolType, boolInitExpr ); 355 isUninitializedVar->fixUniqueId(); 356 357 // void dtor_atexit(...) {...} 358 FunctionDecl * dtorCaller = new FunctionDecl( objDecl->get_mangleName() + "_dtor_atexit", DeclarationNode::NoStorageClass, LinkageSpec::C, new FunctionType( Type::Qualifiers(), false ), new CompoundStmt( noLabels ), false, false ); 359 dtorCaller->fixUniqueId(); 360 dtorCaller->get_statements()->get_kids().push_back( ctorInit->get_dtor() ); 361 362 // on_exit(dtor_atexit); 363 UntypedExpr * callAtexit = new UntypedExpr( new NameExpr( "atexit" ) ); 364 callAtexit->get_args().push_back( new VariableExpr( dtorCaller ) ); 365 366 // __objName_uninitialized = false; 367 UntypedExpr * setTrue = new UntypedExpr( new NameExpr( "?=?" ) ); 368 setTrue->get_args().push_back( new VariableExpr( isUninitializedVar ) ); 369 setTrue->get_args().push_back( new ConstantExpr( Constant( boolType->clone(), "0" ) ) ); 370 371 // generate body of if 372 CompoundStmt * initStmts = new CompoundStmt( noLabels ); 373 std::list< Statement * > & body = initStmts->get_kids(); 374 body.push_back( ctor ); 375 body.push_back( new DeclStmt( noLabels, dtorCaller ) ); 376 body.push_back( new ExprStmt( noLabels, callAtexit ) ); 377 body.push_back( new ExprStmt( noLabels, setTrue ) ); 378 379 // put it all together 380 IfStmt * ifStmt = new IfStmt( noLabels, new VariableExpr( isUninitializedVar ), initStmts, 0 ); 381 stmtsToAddAfter.push_back( new DeclStmt( noLabels, isUninitializedVar ) ); 382 stmtsToAddAfter.push_back( ifStmt ); 244 CP_CTOR_PRINT( std::cerr << "InsertImplicitCalls: adding a wrapper " << appExpr << std::endl; ) 245 246 // wrap each function call so that it is easy to identify nodes that have to be copy constructed 247 ImplicitCopyCtorExpr * expr = new ImplicitCopyCtorExpr( appExpr ); 248 // save the type substitution onto the new node so that it is easy to find. 249 // Ensure it is not deleted with the ImplicitCopyCtorExpr by removing it before deletion. 250 // The substitution is needed to obtain the type of temporary variables so that copy constructor 251 // calls can be resolved. Normally this is what PolyMutator is for, but the pass that resolves 252 // copy constructor calls must be an Indexer. We could alternatively make a PolyIndexer which 253 // saves the environment, or compute the types of temporaries here, but it's much simpler to 254 // save the environment here, and more cohesive to compute temporary variables and resolve copy 255 // constructor calls together. 256 assert( env ); 257 expr->set_env( env ); 258 return expr; 259 } 260 261 bool ResolveCopyCtors::skipCopyConstruct( Type * type ) { 262 return dynamic_cast< VarArgsType * >( type ) || GenPoly::getFunctionType( type ); 263 } 264 265 ApplicationExpr * ResolveCopyCtors::makeCtorDtor( const std::string & fname, ObjectDecl * var, Expression * cpArg ) { 266 assert( var ); 267 UntypedExpr * untyped = new UntypedExpr( new NameExpr( fname ) ); 268 untyped->get_args().push_back( new AddressExpr( new VariableExpr( var ) ) ); 269 if (cpArg) untyped->get_args().push_back( cpArg ); 270 271 // resolve copy constructor 272 // should only be one alternative for copy ctor and dtor expressions, since 273 // all arguments are fixed (VariableExpr and already resolved expression) 274 CP_CTOR_PRINT( std::cerr << "ResolvingCtorDtor " << untyped << std::endl; ) 275 ApplicationExpr * resolved = dynamic_cast< ApplicationExpr * >( ResolvExpr::findVoidExpression( untyped, *this ) ); 276 if ( resolved->get_env() ) { 277 env->add( *resolved->get_env() ); 278 } 279 280 assert( resolved ); 281 delete untyped; 282 return resolved; 283 } 284 285 void ResolveCopyCtors::visit( ImplicitCopyCtorExpr *impCpCtorExpr ) { 286 static UniqueName tempNamer("_tmp_cp"); 287 static UniqueName retNamer("_tmp_cp_ret"); 288 289 CP_CTOR_PRINT( std::cerr << "ResolveCopyCtors: " << impCpCtorExpr << std::endl; ) 290 Visitor::visit( impCpCtorExpr ); 291 env = impCpCtorExpr->get_env(); // xxx - maybe we really should just have a PolyIndexer... 292 293 ApplicationExpr * appExpr = impCpCtorExpr->get_callExpr(); 294 295 // take each argument and attempt to copy construct it. 296 for ( Expression * & arg : appExpr->get_args() ) { 297 CP_CTOR_PRINT( std::cerr << "Type Substitution: " << *impCpCtorExpr->get_env() << std::endl; ) 298 // xxx - need to handle tuple arguments 299 assert( ! arg->get_results().empty() ); 300 Type * result = arg->get_results().front(); 301 if ( skipCopyConstruct( result ) ) continue; // skip certain non-copyable types 302 // type may involve type variables, so apply type substitution to get temporary variable's actual type 303 result = result->clone(); 304 impCpCtorExpr->get_env()->apply( result ); 305 ObjectDecl * tmp = new ObjectDecl( tempNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, result, 0 ); 306 tmp->get_type()->set_isConst( false ); 307 308 // create and resolve copy constructor 309 CP_CTOR_PRINT( std::cerr << "makeCtorDtor for an argument" << std::endl; ) 310 ApplicationExpr * cpCtor = makeCtorDtor( "?{}", tmp, arg ); 311 312 // if the chosen constructor is intrinsic, the copy is unnecessary, so 313 // don't create the temporary and don't call the copy constructor 314 VariableExpr * function = dynamic_cast< VariableExpr * >( cpCtor->get_function() ); 315 assert( function ); 316 if ( function->get_var()->get_linkage() != LinkageSpec::Intrinsic ) { 317 // replace argument to function call with temporary 318 arg = new CommaExpr( cpCtor, new VariableExpr( tmp ) ); 319 impCpCtorExpr->get_tempDecls().push_back( tmp ); 320 impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", tmp ) ); 321 } 322 } 323 324 // each return value from the call needs to be connected with an ObjectDecl 325 // at the call site, which is initialized with the return value and is destructed 326 // later 327 // xxx - handle multiple return values 328 ApplicationExpr * callExpr = impCpCtorExpr->get_callExpr(); 329 // xxx - is this right? callExpr may not have the right environment, because it was attached 330 // at a higher level. Trying to pass that environment along. 331 callExpr->set_env( impCpCtorExpr->get_env()->clone() ); 332 for ( Type * result : appExpr->get_results() ) { 333 result = result->clone(); 334 impCpCtorExpr->get_env()->apply( result ); 335 ObjectDecl * ret = new ObjectDecl( retNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, result, 0 ); 336 ret->get_type()->set_isConst( false ); 337 impCpCtorExpr->get_returnDecls().push_back( ret ); 338 CP_CTOR_PRINT( std::cerr << "makeCtorDtor for a return" << std::endl; ) 339 impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", ret ) ); 340 } 341 CP_CTOR_PRINT( std::cerr << "after Resolving: " << impCpCtorExpr << std::endl; ) 342 } 343 344 345 Expression * FixCopyCtors::mutate( ImplicitCopyCtorExpr * impCpCtorExpr ) { 346 CP_CTOR_PRINT( std::cerr << "FixCopyCtors: " << impCpCtorExpr << std::endl; ) 347 348 impCpCtorExpr = dynamic_cast< ImplicitCopyCtorExpr * >( Mutator::mutate( impCpCtorExpr ) ); 349 assert( impCpCtorExpr ); 350 351 std::list< ObjectDecl * > & tempDecls = impCpCtorExpr->get_tempDecls(); 352 std::list< ObjectDecl * > & returnDecls = impCpCtorExpr->get_returnDecls(); 353 std::list< Expression * > & dtors = impCpCtorExpr->get_dtors(); 354 355 // add all temporary declarations and their constructors 356 for ( ObjectDecl * obj : tempDecls ) { 357 stmtsToAdd.push_back( new DeclStmt( noLabels, obj ) ); 358 } 359 for ( ObjectDecl * obj : returnDecls ) { 360 stmtsToAdd.push_back( new DeclStmt( noLabels, obj ) ); 361 } 362 363 // add destructors after current statement 364 for ( Expression * dtor : dtors ) { 365 stmtsToAddAfter.push_back( new ExprStmt( noLabels, dtor ) ); 366 } 367 368 // xxx - update to work with multiple return values 369 ObjectDecl * returnDecl = returnDecls.empty() ? NULL : returnDecls.front(); 370 Expression * callExpr = impCpCtorExpr->get_callExpr(); 371 372 CP_CTOR_PRINT( std::cerr << "Coming out the back..." << impCpCtorExpr << std::endl; ) 373 374 // detach fields from wrapper node so that it can be deleted without deleting too much 375 dtors.clear(); 376 tempDecls.clear(); 377 returnDecls.clear(); 378 impCpCtorExpr->set_callExpr( NULL ); 379 impCpCtorExpr->set_env( NULL ); 380 delete impCpCtorExpr; 381 382 if ( returnDecl ) { 383 UntypedExpr * assign = new UntypedExpr( new NameExpr( "?=?" ) ); 384 assign->get_args().push_back( new VariableExpr( returnDecl ) ); 385 assign->get_args().push_back( callExpr ); 386 // know the result type of the assignment is the type of the LHS (minus the pointer), so 387 // add that onto the assignment expression so that later steps have the necessary information 388 assign->add_result( returnDecl->get_type()->clone() ); 389 390 Expression * retExpr = new CommaExpr( assign, new VariableExpr( returnDecl ) ); 391 if ( callExpr->get_results().front()->get_isLvalue() ) { 392 // lvalue returning functions are funny. Lvalue.cc inserts a *? in front of any 393 // lvalue returning non-intrinsic function. Add an AddressExpr to the call to negate 394 // the derefence and change the type of the return temporary from T to T* to properly 395 // capture the return value. Then dereference the result of the comma expression, since 396 // the lvalue returning call was originally wrapped with an AddressExpr. 397 // Effectively, this turns 398 // lvalue T f(); 399 // &*f() 400 // into 401 // T * tmp_cp_retN; 402 // tmp_cp_ret_N = &*(tmp_cp_ret_N = &*f(), tmp_cp_ret); 403 // which work out in terms of types, but is pretty messy. It would be nice to find a better way. 404 assign->get_args().back() = new AddressExpr( assign->get_args().back() ); 405 406 Type * resultType = returnDecl->get_type()->clone(); 407 returnDecl->set_type( new PointerType( Type::Qualifiers(), returnDecl->get_type() ) ); 408 UntypedExpr * deref = new UntypedExpr( new NameExpr( "*?" ) ); 409 deref->get_args().push_back( retExpr ); 410 deref->add_result( resultType ); 411 retExpr = deref; 412 } 413 // xxx - might need to set env on retExpr... 414 // retExpr->set_env( env->clone() ); 415 return retExpr; 416 } else { 417 return callExpr; 418 } 419 } 420 421 DeclarationWithType *FixInit::mutate( ObjectDecl *objDecl ) { 422 // first recursively handle pieces of ObjectDecl so that they aren't missed by other visitors 423 // when the init is removed from the ObjectDecl 424 objDecl = dynamic_cast< ObjectDecl * >( Mutator::mutate( objDecl ) ); 425 426 if ( ConstructorInit * ctorInit = dynamic_cast< ConstructorInit * >( objDecl->get_init() ) ) { 427 // a decision should have been made by the resolver, so ctor and init are not both non-NULL 428 assert( ! ctorInit->get_ctor() || ! ctorInit->get_init() ); 429 if ( Statement * ctor = ctorInit->get_ctor() ) { 430 if ( objDecl->get_storageClass() == DeclarationNode::Static ) { 431 // generate: 432 // static bool __objName_uninitialized = true; 433 // if (__objName_uninitialized) { 434 // __ctor(__objName); 435 // void dtor_atexit() { 436 // __dtor(__objName); 437 // } 438 // on_exit(dtorOnExit, &__objName); 439 // __objName_uninitialized = false; 440 // } 441 442 // generate first line 443 BasicType * boolType = new BasicType( Type::Qualifiers(), BasicType::Bool ); 444 SingleInit * boolInitExpr = new SingleInit( new ConstantExpr( Constant( boolType->clone(), "1" ) ), noDesignators ); 445 ObjectDecl * isUninitializedVar = new ObjectDecl( objDecl->get_mangleName() + "_uninitialized", DeclarationNode::Static, LinkageSpec::Cforall, 0, boolType, boolInitExpr ); 446 isUninitializedVar->fixUniqueId(); 447 448 // void dtor_atexit(...) {...} 449 FunctionDecl * dtorCaller = new FunctionDecl( objDecl->get_mangleName() + "_dtor_atexit", DeclarationNode::NoStorageClass, LinkageSpec::C, new FunctionType( Type::Qualifiers(), false ), new CompoundStmt( noLabels ), false, false ); 450 dtorCaller->fixUniqueId(); 451 dtorCaller->get_statements()->get_kids().push_back( ctorInit->get_dtor() ); 452 453 // on_exit(dtor_atexit); 454 UntypedExpr * callAtexit = new UntypedExpr( new NameExpr( "atexit" ) ); 455 callAtexit->get_args().push_back( new VariableExpr( dtorCaller ) ); 456 457 // __objName_uninitialized = false; 458 UntypedExpr * setTrue = new UntypedExpr( new NameExpr( "?=?" ) ); 459 setTrue->get_args().push_back( new VariableExpr( isUninitializedVar ) ); 460 setTrue->get_args().push_back( new ConstantExpr( Constant( boolType->clone(), "0" ) ) ); 461 462 // generate body of if 463 CompoundStmt * initStmts = new CompoundStmt( noLabels ); 464 std::list< Statement * > & body = initStmts->get_kids(); 465 body.push_back( ctor ); 466 body.push_back( new DeclStmt( noLabels, dtorCaller ) ); 467 body.push_back( new ExprStmt( noLabels, callAtexit ) ); 468 body.push_back( new ExprStmt( noLabels, setTrue ) ); 469 470 // put it all together 471 IfStmt * ifStmt = new IfStmt( noLabels, new VariableExpr( isUninitializedVar ), initStmts, 0 ); 472 stmtsToAddAfter.push_back( new DeclStmt( noLabels, isUninitializedVar ) ); 473 stmtsToAddAfter.push_back( ifStmt ); 474 } else { 475 stmtsToAddAfter.push_back( ctor ); 476 } 477 objDecl->set_init( NULL ); 478 ctorInit->set_ctor( NULL ); 479 } else if ( Initializer * init = ctorInit->get_init() ) { 480 objDecl->set_init( init ); 481 ctorInit->set_init( NULL ); 383 482 } else { 384 stmtsToAddAfter.push_back( ctor );385 dtorStmts.back().push_front( ctorInit->get_dtor());483 // no constructor and no initializer, which is okay 484 objDecl->set_init( NULL ); 386 485 } 387 objDecl->set_init( NULL ); 388 ctorInit->set_ctor( NULL ); 389 ctorInit->set_dtor( NULL ); // xxx - only destruct when constructing? Probably not? 390 } else if ( Initializer * init = ctorInit->get_init() ) { 391 objDecl->set_init( init ); 392 ctorInit->set_init( NULL ); 393 } else { 394 // no constructor and no initializer, which is okay 395 objDecl->set_init( NULL ); 396 } 397 delete ctorInit; 398 } 399 return objDecl; 400 } 401 402 namespace { 486 delete ctorInit; 487 } 488 return objDecl; 489 } 490 491 void ObjDeclCollector::visit( CompoundStmt *compoundStmt ) { 492 std::set< ObjectDecl * > prevVars = curVars; 493 Parent::visit( compoundStmt ); 494 curVars = prevVars; 495 } 496 497 void ObjDeclCollector::visit( DeclStmt *stmt ) { 498 if ( ObjectDecl * objDecl = dynamic_cast< ObjectDecl * > ( stmt->get_decl() ) ) { 499 curVars.insert( objDecl ); 500 } 501 return Parent::visit( stmt ); 502 } 503 504 void LabelFinder::handleStmt( Statement * stmt ) { 505 for ( Label l : stmt->get_labels() ) { 506 vars[l] = curVars; 507 } 508 } 509 403 510 template<typename Iterator, typename OutputIterator> 404 511 void insertDtors( Iterator begin, Iterator end, OutputIterator out ) { 405 512 for ( Iterator it = begin ; it != end ; ++it ) { 406 // remove if instrinsic destructor statement. Note that this is only called 407 // on lists of implicit dtors, so if the user manually calls an intrinsic 408 // dtor then the call must (and will) still be generated since the argument 409 // may contain side effects. 410 if ( ! isInstrinsicSingleArgCallStmt( *it ) ) { 411 // don't need to call intrinsic dtor, because it does nothing, but 412 // non-intrinsic dtors must be called 413 *out++ = (*it)->clone(); 513 // extract destructor statement from the object decl and 514 // insert it into the output. Note that this is only called 515 // on lists of non-static objects with implicit non-intrinsic 516 // dtors, so if the user manually calls an intrinsic dtor 517 // then the call must (and will) still be generated since 518 // the argument may contain side effects. 519 ObjectDecl * objDecl = *it; 520 ConstructorInit * ctorInit = dynamic_cast< ConstructorInit * >( objDecl->get_init() ); 521 assert( ctorInit && ctorInit->get_dtor() ); 522 *out++ = ctorInit->get_dtor()->clone(); 523 } 524 } 525 526 void InsertDtors::visit( ObjectDecl * objDecl ) { 527 // remember non-static destructed objects so that their destructors can be inserted later 528 if ( objDecl->get_storageClass() != DeclarationNode::Static ) { 529 if ( ConstructorInit * ctorInit = dynamic_cast< ConstructorInit * >( objDecl->get_init() ) ) { 530 // a decision should have been made by the resolver, so ctor and init are not both non-NULL 531 assert( ! ctorInit->get_ctor() || ! ctorInit->get_init() ); 532 Statement * dtor = ctorInit->get_dtor(); 533 if ( dtor && ! isInstrinsicSingleArgCallStmt( dtor ) ) { 534 // don't need to call intrinsic dtor, because it does nothing, but 535 // non-intrinsic dtors must be called 536 reverseDeclOrder.front().push_front( objDecl ); 537 } 414 538 } 415 539 } 416 } 417 } 418 419 CompoundStmt * FixInit::mutate( CompoundStmt * compoundStmt ) { 420 // mutate statements - this will also populate dtorStmts list. 421 // don't want to dump all destructors when block is left, 422 // just the destructors associated with variables defined in this block, 423 // so push a new list to the top of the stack so that we can differentiate scopes 424 dtorStmts.push_back( std::list<Statement *>() ); 425 426 compoundStmt = PolyMutator::mutate( compoundStmt ); 427 std::list< Statement * > & statements = compoundStmt->get_kids(); 428 429 insertDtors( dtorStmts.back().begin(), dtorStmts.back().end(), back_inserter( statements ) ); 430 431 deleteAll( dtorStmts.back() ); 432 dtorStmts.pop_back(); 433 return compoundStmt; 434 } 435 436 Statement * FixInit::mutate( ReturnStmt * returnStmt ) { 437 for ( std::list< std::list< Statement * > >::reverse_iterator list = dtorStmts.rbegin(); list != dtorStmts.rend(); ++list ) { 438 insertDtors( list->begin(), list->end(), back_inserter( stmtsToAdd ) ); 439 } 440 return Mutator::mutate( returnStmt ); 441 } 442 443 Statement * FixInit::mutate( BranchStmt * branchStmt ) { 444 // TODO: adding to the end of a block isn't sufficient, since 445 // return/break/goto should trigger destructor when block is left. 446 switch( branchStmt->get_type() ) { 447 case BranchStmt::Continue: 448 case BranchStmt::Break: 449 insertDtors( dtorStmts.back().begin(), dtorStmts.back().end(), back_inserter( stmtsToAdd ) ); 450 break; 451 case BranchStmt::Goto: 452 // xxx 453 // if goto leaves a block, generate dtors for every block it leaves 454 // if goto is in same block but earlier statement, destruct every object that was defined after the statement 455 break; 456 default: 457 assert( false ); 458 } 459 return Mutator::mutate( branchStmt ); 460 } 461 462 540 Parent::visit( objDecl ); 541 } 542 543 void InsertDtors::visit( CompoundStmt * compoundStmt ) { 544 // visit statements - this will also populate reverseDeclOrder list. 545 // don't want to dump all destructors when block is left, 546 // just the destructors associated with variables defined in this block, 547 // so push a new list to the top of the stack so that we can differentiate scopes 548 reverseDeclOrder.push_front( OrderedDecls() ); 549 Parent::visit( compoundStmt ); 550 551 std::list< Statement * > & statements = compoundStmt->get_kids(); 552 insertDtors( reverseDeclOrder.front().begin(), reverseDeclOrder.front().end(), back_inserter( statements ) ); 553 554 // xxx - ?? 555 // deleteAll( dtorStmts.back() ); 556 reverseDeclOrder.pop_front(); 557 } 558 559 void InsertDtors::visit( ReturnStmt * returnStmt ) { 560 for ( OrderedDecls & od : reverseDeclOrder ) { 561 insertDtors( od.begin(), od.end(), back_inserter( stmtsToAdd ) ); 562 } 563 } 564 565 void InsertDtors::handleGoto( BranchStmt * stmt ) { 566 assert( stmt->get_type() == BranchStmt::Goto ); 567 // S_L = lvars = set of objects in scope at label definition 568 // S_G = curVars = set of objects in scope at goto statement 569 ObjectSet & lvars = labelVars[ stmt->get_target() ]; 570 571 DTOR_PRINT( 572 std::cerr << "at goto label: " << stmt->get_target().get_name() << std::endl; 573 std::cerr << "S_G = " << printSet( curVars ) << std::endl; 574 std::cerr << "S_L = " << printSet( lvars ) << std::endl; 575 ) 576 577 ObjectSet diff; 578 // S_L-S_G results in set of objects whose construction is skipped - it's an error if this set is non-empty 579 std::set_difference( lvars.begin(), lvars.end(), curVars.begin(), curVars.end(), std::inserter( diff, diff.begin() ) ); 580 DTOR_PRINT( 581 std::cerr << "S_L-S_G = " << printSet( diff ) << std::endl; 582 ) 583 if ( ! diff.empty() ) { 584 throw SemanticError( std::string("jump to label '") + stmt->get_target().get_name() + "' crosses initialization of " + (*diff.begin())->get_name() + " ", stmt ); 585 } 586 // S_G-S_L results in set of objects that must be destructed 587 diff.clear(); 588 std::set_difference( curVars.begin(), curVars.end(), lvars.begin(), lvars.end(), std::inserter( diff, diff.end() ) ); 589 DTOR_PRINT( 590 std::cerr << "S_G-S_L = " << printSet( diff ) << std::endl; 591 ) 592 if ( ! diff.empty() ) { 593 // go through decl ordered list of objectdecl. for each element that occurs in diff, output destructor 594 OrderedDecls ordered; 595 for ( OrderedDecls & rdo : reverseDeclOrder ) { 596 // add elements from reverseDeclOrder into ordered if they occur in diff - it is key that this happens in reverse declaration order. 597 copy_if( rdo.begin(), rdo.end(), back_inserter( ordered ), [&]( ObjectDecl * objDecl ) { return diff.count( objDecl ); } ); 598 } 599 insertDtors( ordered.begin(), ordered.end(), back_inserter( stmtsToAdd ) ); 600 } 601 } 602 603 void InsertDtors::visit( BranchStmt * stmt ) { 604 // TODO: adding to the end of a block isn't sufficient, since 605 // return/break/goto should trigger destructor when block is left. 606 switch( stmt->get_type() ) { 607 case BranchStmt::Continue: 608 case BranchStmt::Break: 609 // xxx - easiest thing to do: generate a label for every break/continue 610 // this label is unused, so attach unused attribute to it 611 // finally, all of these cases can be the same (this is less efficient than it could be, 612 // because the S_L-S_G check is unnecessary [the set should always be empty], but this 613 // serves as a bit of a sanity check, so I'm okay with it.) 614 // xxx - this is insufficient, because multiple blocks can be opened in a switch or loop 615 insertDtors( reverseDeclOrder.front().begin(), reverseDeclOrder.front().end(), back_inserter( stmtsToAdd ) ); 616 break; 617 case BranchStmt::Goto: 618 handleGoto( stmt ); 619 break; 620 default: 621 assert( false ); 622 } 623 } 624 } // namespace 463 625 } // namespace InitTweak 464 626
Note: See TracChangeset
for help on using the changeset viewer.