Changes in src/InitTweak/GenInit.cc [cad355a:f9cebb5]
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/InitTweak/GenInit.cc
rcad355a rf9cebb5 26 26 #include "SymTab/Autogen.h" 27 27 #include "GenPoly/PolyMutator.h" 28 #include "GenPoly/DeclMutator.h" 28 29 29 30 namespace InitTweak { … … 55 56 public: 56 57 /// create constructor and destructor statements for object declarations. 57 /// Destructors are inserted directly into the code, whereas constructors58 /// will be added in after the resolver has run so that the initializer expression59 /// is only removed if a constructor is found58 /// the actual call statements will be added in after the resolver has run 59 /// so that the initializer expression is only removed if a constructor is found 60 /// and the same destructor call is inserted in all of the appropriate locations. 60 61 static void generateCtorDtor( std::list< Declaration * > &translationUnit ); 61 62 CtorDtor() : inFunction( false ) {}63 62 64 63 virtual DeclarationWithType * mutate( ObjectDecl * ); 65 64 virtual DeclarationWithType * mutate( FunctionDecl *functionDecl ); 66 virtual Declaration* mutate( StructDecl *aggregateDecl ); 67 virtual Declaration* mutate( UnionDecl *aggregateDecl ); 68 virtual Declaration* mutate( EnumDecl *aggregateDecl ); 69 virtual Declaration* mutate( TraitDecl *aggregateDecl ); 70 virtual TypeDecl* mutate( TypeDecl *typeDecl ); 71 virtual Declaration* mutate( TypedefDecl *typeDecl ); 72 73 virtual Type * mutate( FunctionType *funcType ); 65 // should not traverse into any of these declarations to find objects 66 // that need to be constructed or destructed 67 virtual Declaration* mutate( StructDecl *aggregateDecl ) { return aggregateDecl; } 68 virtual Declaration* mutate( UnionDecl *aggregateDecl ) { return aggregateDecl; } 69 virtual Declaration* mutate( EnumDecl *aggregateDecl ) { return aggregateDecl; } 70 virtual Declaration* mutate( TraitDecl *aggregateDecl ) { return aggregateDecl; } 71 virtual TypeDecl* mutate( TypeDecl *typeDecl ) { return typeDecl; } 72 virtual Declaration* mutate( TypedefDecl *typeDecl ) { return typeDecl; } 73 74 virtual Type * mutate( FunctionType *funcType ) { return funcType; } 74 75 75 76 protected: 76 bool inFunction; 77 }; 78 79 class HoistArrayDimension : public GenPoly::DeclMutator { 80 public: 81 typedef GenPoly::DeclMutator Parent; 82 83 /// hoist dimension from array types in object declaration so that it uses a single 84 /// const variable of type size_t, so that side effecting array dimensions are only 85 /// computed once. 86 static void hoistArrayDimension( std::list< Declaration * > & translationUnit ); 87 88 private: 89 virtual DeclarationWithType * mutate( ObjectDecl * objectDecl ); 90 virtual DeclarationWithType * mutate( FunctionDecl *functionDecl ); 91 // should not traverse into any of these declarations to find objects 92 // that need to be constructed or destructed 93 virtual Declaration* mutate( StructDecl *aggregateDecl ) { return aggregateDecl; } 94 virtual Declaration* mutate( UnionDecl *aggregateDecl ) { return aggregateDecl; } 95 virtual Declaration* mutate( EnumDecl *aggregateDecl ) { return aggregateDecl; } 96 virtual Declaration* mutate( TraitDecl *aggregateDecl ) { return aggregateDecl; } 97 virtual TypeDecl* mutate( TypeDecl *typeDecl ) { return typeDecl; } 98 virtual Declaration* mutate( TypedefDecl *typeDecl ) { return typeDecl; } 99 100 virtual Type* mutate( FunctionType *funcType ) { return funcType; } 101 102 void hoist( Type * type ); 103 104 DeclarationNode::StorageClass storageclass = DeclarationNode::NoStorageClass; 105 bool inFunction = false; 77 106 }; 78 107 79 108 void genInit( std::list< Declaration * > & translationUnit ) { 80 109 ReturnFixer::makeReturnTemp( translationUnit ); 110 HoistArrayDimension::hoistArrayDimension( translationUnit ); 81 111 CtorDtor::generateCtorDtor( translationUnit ); 82 112 } … … 124 154 } 125 155 156 // precompute array dimension expression, because constructor generation may duplicate it, 157 // which would be incorrect if it is a side-effecting computation. 158 void HoistArrayDimension::hoistArrayDimension( std::list< Declaration * > & translationUnit ) { 159 HoistArrayDimension hoister; 160 hoister.mutateDeclarationList( translationUnit ); 161 } 162 163 DeclarationWithType * HoistArrayDimension::mutate( ObjectDecl * objectDecl ) { 164 storageclass = objectDecl->get_storageClass(); 165 DeclarationWithType * temp = Parent::mutate( objectDecl ); 166 hoist( objectDecl->get_type() ); 167 storageclass = DeclarationNode::NoStorageClass; 168 return temp; 169 } 170 171 void HoistArrayDimension::hoist( Type * type ) { 172 // if in function, generate const size_t var 173 static UniqueName dimensionName( "_array_dim" ); 174 175 // C doesn't allow variable sized arrays at global scope or for static variables, 176 // so don't hoist dimension. 177 if ( ! inFunction ) return; 178 if ( storageclass == DeclarationNode::Static ) return; 179 180 if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) { 181 if ( ! arrayType->get_dimension() ) return; // xxx - recursive call to hoist? 182 183 // don't need to hoist dimension if it's a constexpr - only need to if there's potential 184 // for side effects. 185 if ( isConstExpr( arrayType->get_dimension() ) ) return; 186 187 ObjectDecl * arrayDimension = new ObjectDecl( dimensionName.newName(), storageclass, LinkageSpec::C, 0, SymTab::SizeType->clone(), new SingleInit( arrayType->get_dimension() ) ); 188 arrayDimension->get_type()->set_isConst( true ); 189 190 arrayType->set_dimension( new VariableExpr( arrayDimension ) ); 191 addDeclaration( arrayDimension ); 192 193 hoist( arrayType->get_base() ); 194 return; 195 } 196 } 197 198 DeclarationWithType * HoistArrayDimension::mutate( FunctionDecl *functionDecl ) { 199 bool oldInFunc = inFunction; 200 inFunction = true; 201 DeclarationWithType * decl = Parent::mutate( functionDecl ); 202 inFunction = oldInFunc; 203 return decl; 204 } 126 205 127 206 void CtorDtor::generateCtorDtor( std::list< Declaration * > & translationUnit ) { … … 130 209 } 131 210 132 namespace {133 Expression * makeCtorDtorExpr( std::string name, ObjectDecl * objDecl, std::list< Expression * > args ) {134 UntypedExpr * expr = new UntypedExpr( new NameExpr( name ) );135 expr->get_args().push_back( new AddressExpr( new VariableExpr( objDecl ) ) );136 expr->get_args().splice( expr->get_args().end(), args );137 return expr;138 }139 }140 141 211 DeclarationWithType * CtorDtor::mutate( ObjectDecl * objDecl ) { 142 // hands off if designated or if @=212 // hands off if designated, if @=, or if extern 143 213 if ( tryConstruct( objDecl ) ) { 144 if ( inFunction ) { 145 if ( ArrayType * at = dynamic_cast< ArrayType * >( objDecl->get_type() ) ) { 146 // call into makeArrayFunction from validate.cc to generate calls to ctor/dtor for each element of array 147 // TODO: walk initializer and generate appropriate copy ctor if element has initializer 148 std::list< Expression * > args = makeInitList( objDecl->get_init() ); 149 if ( args.empty() ) { 150 std::list< Statement * > ctor; 151 std::list< Statement * > dtor; 152 153 SymTab::makeArrayFunction( NULL, new VariableExpr( objDecl ), at, "?{}", back_inserter( ctor ) ); 154 SymTab::makeArrayFunction( NULL, new VariableExpr( objDecl ), at, "^?{}", front_inserter( dtor ), false ); 155 156 // Currently makeArrayFunction produces a single Statement - a CompoundStmt 157 // which wraps everything that needs to happen. As such, it's technically 158 // possible to use a Statement ** in the above calls, but this is inherently 159 // unsafe, so instead we take the slightly less efficient route, but will be 160 // immediately informed if somehow the above assumption is broken. In this case, 161 // we could always wrap the list of statements at this point with a CompoundStmt, 162 // but it seems reasonable at the moment for this to be done by makeArrayFunction 163 // itself 164 assert( ctor.size() == 1 && dynamic_cast< ImplicitCtorDtorStmt * >( ctor.front() ) ); 165 assert( dtor.size() == 1 && dynamic_cast< ImplicitCtorDtorStmt * >( dtor.front() ) ); 166 objDecl->set_init( new ConstructorInit( ctor.front(), dtor.front(), objDecl->get_init() ) ); 167 } else { 168 // array came with an initializer list: initialize each element 169 // may have more initializers than elements in the array - need to check at each index that 170 // we haven't exceeded size. This requires precomputing the size because it might be a side-effecting 171 // computation. 172 // may have fewer initializers than eleemnts in the array - need to default construct 173 // remaining elements. 174 // might be able to merge this with the case above. 175 } 176 } else { 177 // it's sufficient to attempt to call the ctor/dtor for the given object and its initializer 178 Expression * ctor = makeCtorDtorExpr( "?{}", objDecl, makeInitList( objDecl->get_init() ) ); 179 Expression * dtor = makeCtorDtorExpr( "^?{}", objDecl, std::list< Expression * >() ); 180 181 // need to remember init expression, in case no ctors exist 182 // if ctor does exist, want to use ctor expression instead of init 183 // push this decision to the resolver 184 ExprStmt * ctorStmt = new ExprStmt( noLabels, ctor ); 185 ExprStmt * dtorStmt = new ExprStmt( noLabels, dtor ); 186 objDecl->set_init( new ConstructorInit( new ImplicitCtorDtorStmt( ctorStmt ), new ImplicitCtorDtorStmt( dtorStmt ), objDecl->get_init() ) ); 187 } 214 // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor 215 // for each constructable object 216 std::list< Statement * > ctor; 217 std::list< Statement * > dtor; 218 219 InitExpander srcParam( objDecl->get_init() ); 220 InitExpander nullParam( (Initializer *)NULL ); 221 SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), "?{}", back_inserter( ctor ), objDecl ); 222 SymTab::genImplicitCall( nullParam, new VariableExpr( objDecl ), "^?{}", front_inserter( dtor ), objDecl, false ); 223 224 // Currently genImplicitCall produces a single Statement - a CompoundStmt 225 // which wraps everything that needs to happen. As such, it's technically 226 // possible to use a Statement ** in the above calls, but this is inherently 227 // unsafe, so instead we take the slightly less efficient route, but will be 228 // immediately informed if somehow the above assumption is broken. In this case, 229 // we could always wrap the list of statements at this point with a CompoundStmt, 230 // but it seems reasonable at the moment for this to be done by genImplicitCall 231 // itself. It is possible that genImplicitCall produces no statements (e.g. if 232 // an array type does not have a dimension). In this case, it's fine to ignore 233 // the object for the purposes of construction. 234 assert( ctor.size() == dtor.size() && ctor.size() <= 1 ); 235 if ( ctor.size() == 1 ) { 236 // need to remember init expression, in case no ctors exist 237 // if ctor does exist, want to use ctor expression instead of init 238 // push this decision to the resolver 239 assert( dynamic_cast< ImplicitCtorDtorStmt * > ( ctor.front() ) && dynamic_cast< ImplicitCtorDtorStmt * > ( dtor.front() ) ); 240 objDecl->set_init( new ConstructorInit( ctor.front(), dtor.front(), objDecl->get_init() ) ); 188 241 } 189 242 } … … 193 246 DeclarationWithType * CtorDtor::mutate( FunctionDecl *functionDecl ) { 194 247 // parameters should not be constructed and destructed, so don't mutate FunctionType 195 bool oldInFunc = inFunction;196 248 mutateAll( functionDecl->get_oldDecls(), *this ); 197 inFunction = true;198 249 functionDecl->set_statements( maybeMutate( functionDecl->get_statements(), *this ) ); 199 inFunction = oldInFunc;200 250 return functionDecl; 201 251 } 202 203 // should not traverse into any of these declarations to find objects204 // that need to be constructed or destructed205 Declaration* CtorDtor::mutate( StructDecl *aggregateDecl ) { return aggregateDecl; }206 Declaration* CtorDtor::mutate( UnionDecl *aggregateDecl ) { return aggregateDecl; }207 Declaration* CtorDtor::mutate( EnumDecl *aggregateDecl ) { return aggregateDecl; }208 Declaration* CtorDtor::mutate( TraitDecl *aggregateDecl ) { return aggregateDecl; }209 TypeDecl* CtorDtor::mutate( TypeDecl *typeDecl ) { return typeDecl; }210 Declaration* CtorDtor::mutate( TypedefDecl *typeDecl ) { return typeDecl; }211 Type* CtorDtor::mutate( FunctionType *funcType ) { return funcType; }212 213 252 } // namespace InitTweak 214 253
Note:
See TracChangeset
for help on using the changeset viewer.