Changes in src/InitTweak/GenInit.cc [62e5546:9facf3b]
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/InitTweak/GenInit.cc
r62e5546 r9facf3b 29 29 #include "GenPoly/DeclMutator.h" 30 30 #include "GenPoly/ScopedSet.h" 31 #include "ResolvExpr/typeops.h" 31 32 32 33 namespace InitTweak { … … 45 46 ReturnFixer(); 46 47 47 using GenPoly::PolyMutator::mutate; 48 typedef GenPoly::PolyMutator Parent; 49 using Parent::mutate; 48 50 virtual DeclarationWithType * mutate( FunctionDecl *functionDecl ) override; 49 51 virtual Statement * mutate( ReturnStmt * returnStmt ) override; 50 52 51 53 protected: 52 std::list<DeclarationWithType*> returnVals; 53 UniqueName tempNamer; 54 FunctionType * ftype; 54 55 std::string funcName; 55 56 }; … … 86 87 87 88 bool isManaged( ObjectDecl * objDecl ) const ; // determine if object is managed 89 bool isManaged( Type * type ) const; // determine if type is managed 88 90 void handleDWT( DeclarationWithType * dwt ); // add type to managed if ctor/dtor 89 91 GenPoly::ScopedSet< std::string > managedTypes; … … 133 135 } 134 136 135 ReturnFixer::ReturnFixer() : tempNamer( "_retVal" ){}137 ReturnFixer::ReturnFixer() {} 136 138 137 139 Statement *ReturnFixer::mutate( ReturnStmt *returnStmt ) { 138 // update for multiple return values140 std::list< DeclarationWithType * > & returnVals = ftype->get_returnVals(); 139 141 assert( returnVals.size() == 0 || returnVals.size() == 1 ); 140 142 // hands off if the function returns an lvalue - we don't want to allocate a temporary if a variable's address 141 143 // is being returned 144 // Note: under the assumption that assignments return *this, checking for ?=? here is an optimization, since it shouldn't be necessary to copy construct `this`. This is a temporary optimization until reference types are added, at which point this should be removed, along with the analogous optimization in copy constructor generation. 142 145 if ( returnStmt->get_expr() && returnVals.size() == 1 && funcName != "?=?" && ! returnVals.front()->get_type()->get_isLvalue() ) { 143 // ensure return value is not destructed by explicitly creating 144 // an empty SingleInit node wherein maybeConstruct is false 145 ObjectDecl *newObj = new ObjectDecl( tempNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, returnVals.front()->get_type()->clone(), new ListInit( std::list<Initializer*>(), noDesignators, false ) ); 146 stmtsToAdd.push_back( new DeclStmt( noLabels, newObj ) ); 147 148 // and explicitly create the constructor expression separately 146 // explicitly construct the return value using the return expression and the retVal object 147 assertf( returnVals.front()->get_name() != "", "Function %s has unnamed return value\n", funcName.c_str() ); 149 148 UntypedExpr *construct = new UntypedExpr( new NameExpr( "?{}" ) ); 150 construct->get_args().push_back( new AddressExpr( new VariableExpr( newObj) ) );149 construct->get_args().push_back( new AddressExpr( new VariableExpr( returnVals.front() ) ) ); 151 150 construct->get_args().push_back( returnStmt->get_expr() ); 152 151 stmtsToAdd.push_back(new ExprStmt(noLabels, construct)); 153 152 154 returnStmt->set_expr( new VariableExpr( newObj ) ); 153 // return the retVal object 154 returnStmt->set_expr( new VariableExpr( returnVals.front() ) ); 155 155 } // if 156 156 return returnStmt; … … 158 158 159 159 DeclarationWithType* ReturnFixer::mutate( FunctionDecl *functionDecl ) { 160 ValueGuard< std::list<DeclarationWithType*> > oldReturnVals( returnVals);160 ValueGuard< FunctionType * > oldFtype( ftype ); 161 161 ValueGuard< std::string > oldFuncName( funcName ); 162 162 163 FunctionType * type = functionDecl->get_functionType(); 164 returnVals = type->get_returnVals(); 163 ftype = functionDecl->get_functionType(); 165 164 funcName = functionDecl->get_name(); 166 DeclarationWithType * decl = Mutator::mutate( functionDecl ); 167 return decl; 165 return Parent::mutate( functionDecl ); 168 166 } 169 167 … … 222 220 } 223 221 222 bool CtorDtor::isManaged( Type * type ) const { 223 if ( TupleType * tupleType = dynamic_cast< TupleType * > ( type ) ) { 224 // tuple is also managed if any of its components are managed 225 if ( std::any_of( tupleType->get_types().begin(), tupleType->get_types().end(), [&](Type * type) { return isManaged( type ); }) ) { 226 return true; 227 } 228 } 229 // 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) 230 return managedTypes.find( SymTab::Mangler::mangle( type ) ) != managedTypes.end() || GenPoly::isPolyType( type ); 231 } 232 224 233 bool CtorDtor::isManaged( ObjectDecl * objDecl ) const { 225 234 Type * type = objDecl->get_type(); … … 227 236 type = at->get_base(); 228 237 } 229 return managedTypes.find( SymTab::Mangler::mangle( type ) ) != managedTypes.end();238 return isManaged( type ); 230 239 } 231 240 … … 238 247 managedTypes.insert( SymTab::Mangler::mangle( type->get_base() ) ); 239 248 } 249 } 250 251 ConstructorInit * genCtorInit( ObjectDecl * objDecl ) { 252 // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor 253 // for each constructable object 254 std::list< Statement * > ctor; 255 std::list< Statement * > dtor; 256 257 InitExpander srcParam( objDecl->get_init() ); 258 InitExpander nullParam( (Initializer *)NULL ); 259 SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), "?{}", back_inserter( ctor ), objDecl ); 260 SymTab::genImplicitCall( nullParam, new VariableExpr( objDecl ), "^?{}", front_inserter( dtor ), objDecl, false ); 261 262 // Currently genImplicitCall produces a single Statement - a CompoundStmt 263 // which wraps everything that needs to happen. As such, it's technically 264 // possible to use a Statement ** in the above calls, but this is inherently 265 // unsafe, so instead we take the slightly less efficient route, but will be 266 // immediately informed if somehow the above assumption is broken. In this case, 267 // we could always wrap the list of statements at this point with a CompoundStmt, 268 // but it seems reasonable at the moment for this to be done by genImplicitCall 269 // itself. It is possible that genImplicitCall produces no statements (e.g. if 270 // an array type does not have a dimension). In this case, it's fine to ignore 271 // the object for the purposes of construction. 272 assert( ctor.size() == dtor.size() && ctor.size() <= 1 ); 273 if ( ctor.size() == 1 ) { 274 // need to remember init expression, in case no ctors exist 275 // if ctor does exist, want to use ctor expression instead of init 276 // push this decision to the resolver 277 assert( dynamic_cast< ImplicitCtorDtorStmt * > ( ctor.front() ) && dynamic_cast< ImplicitCtorDtorStmt * > ( dtor.front() ) ); 278 return new ConstructorInit( ctor.front(), dtor.front(), objDecl->get_init() ); 279 } 280 return nullptr; 240 281 } 241 282 … … 250 291 if ( ! checkInitDepth( objDecl ) ) throw SemanticError( "Managed object's initializer is too deep ", objDecl ); 251 292 252 // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor 253 // for each constructable object 254 std::list< Statement * > ctor; 255 std::list< Statement * > dtor; 256 257 InitExpander srcParam( objDecl->get_init() ); 258 InitExpander nullParam( (Initializer *)NULL ); 259 SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), "?{}", back_inserter( ctor ), objDecl ); 260 SymTab::genImplicitCall( nullParam, new VariableExpr( objDecl ), "^?{}", front_inserter( dtor ), objDecl, false ); 261 262 // Currently genImplicitCall produces a single Statement - a CompoundStmt 263 // which wraps everything that needs to happen. As such, it's technically 264 // possible to use a Statement ** in the above calls, but this is inherently 265 // unsafe, so instead we take the slightly less efficient route, but will be 266 // immediately informed if somehow the above assumption is broken. In this case, 267 // we could always wrap the list of statements at this point with a CompoundStmt, 268 // but it seems reasonable at the moment for this to be done by genImplicitCall 269 // itself. It is possible that genImplicitCall produces no statements (e.g. if 270 // an array type does not have a dimension). In this case, it's fine to ignore 271 // the object for the purposes of construction. 272 assert( ctor.size() == dtor.size() && ctor.size() <= 1 ); 273 if ( ctor.size() == 1 ) { 274 // need to remember init expression, in case no ctors exist 275 // if ctor does exist, want to use ctor expression instead of init 276 // push this decision to the resolver 277 assert( dynamic_cast< ImplicitCtorDtorStmt * > ( ctor.front() ) && dynamic_cast< ImplicitCtorDtorStmt * > ( dtor.front() ) ); 278 objDecl->set_init( new ConstructorInit( ctor.front(), dtor.front(), objDecl->get_init() ) ); 279 } 293 objDecl->set_init( genCtorInit( objDecl ) ); 280 294 } 281 295 return Parent::mutate( objDecl ); … … 290 304 managedTypes.beginScope(); 291 305 // go through assertions and recursively add seen ctor/dtors 292 for ( TypeDecl *tyDecl : functionDecl->get_functionType()->get_forall() ) {306 for ( auto & tyDecl : functionDecl->get_functionType()->get_forall() ) { 293 307 for ( DeclarationWithType *& assertion : tyDecl->get_assertions() ) { 294 308 assertion = assertion->acceptMutator( *this );
Note: See TracChangeset
for help on using the changeset viewer.