Changes in src/SymTab/Autogen.cc [f30b2610:a4477db]
- File:
-
- 1 edited
-
src/SymTab/Autogen.cc (modified) (19 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/SymTab/Autogen.cc
rf30b2610 ra4477db 43 43 namespace SymTab { 44 44 Type * SizeType = 0; 45 46 /// Data used to generate functions generically. Specifically, the name of the generated function and a function which generates the routine protoype 45 typedef ScopedMap< std::string, bool > TypeMap; 46 47 /// Data used to generate functions generically. Specifically, the name of the generated function, a function which generates the routine protoype, and a map which contains data to determine whether a function should be generated. 47 48 struct FuncData { 48 49 typedef FunctionType * (*TypeGen)( Type * ); 49 FuncData( const std::string & fname, const TypeGen & genType ) : fname( fname ), genType( genType) {}50 FuncData( const std::string & fname, const TypeGen & genType, TypeMap & map ) : fname( fname ), genType( genType ), map( map ) {} 50 51 std::string fname; 51 52 TypeGen genType; 53 TypeMap & map; 52 54 }; 53 55 54 struct AutogenerateRoutines final : public WithDeclsToAdd, public WithVisitorRef<AutogenerateRoutines>, public WithGuards, public WithShortCircuiting , public WithIndexer{56 struct AutogenerateRoutines final : public WithDeclsToAdd, public WithVisitorRef<AutogenerateRoutines>, public WithGuards, public WithShortCircuiting { 55 57 AutogenerateRoutines(); 56 58 … … 68 70 69 71 private: 70 71 72 GenPoly::ScopedSet< std::string > structsDone; 72 73 unsigned int functionNesting = 0; // current level of nested functions 73 74 InitTweak::ManagedTypes managedTypes; 74 /// Note: the following maps could be ScopedSets, but it should be easier to work 75 /// deleted functions in if they are maps, since the value false can be inserted 76 /// at the current scope without affecting outer scopes or requiring copies. 77 TypeMap copyable, assignable, constructable, destructable; 75 78 std::vector< FuncData > data; 76 79 }; … … 78 81 /// generates routines for tuple types. 79 82 struct AutogenTupleRoutines : public WithDeclsToAdd, public WithVisitorRef<AutogenTupleRoutines>, public WithGuards, public WithShortCircuiting { 80 void previsit( FunctionDecl * functionDecl );81 82 void postvisit( TupleType * tupleType );83 84 void previsit( CompoundStmt * compoundStmt );83 void previsit( FunctionDecl *functionDecl ); 84 85 void postvisit( TupleType *tupleType ); 86 87 void previsit( CompoundStmt *compoundStmt ); 85 88 86 89 private: … … 98 101 } 99 102 100 //=============================================================================================101 // FuncGenerator definitions102 //=============================================================================================103 class FuncGenerator {104 public:105 std::list< Declaration * > definitions, forwards;106 107 FuncGenerator( Type * type, const std::vector< FuncData > & data, unsigned int functionNesting, SymTab::Indexer & indexer ) : type( type ), data( data ), functionNesting( functionNesting ), indexer( indexer ) {}108 109 virtual bool shouldAutogen() const = 0;110 void genStandardFuncs();111 virtual void genFieldCtors() = 0;112 protected:113 Type * type;114 const std::vector< FuncData > & data;115 unsigned int functionNesting;116 SymTab::Indexer & indexer;117 118 virtual void genFuncBody( FunctionDecl * dcl ) = 0;119 virtual bool isConcurrentType() const = 0;120 121 void resolve( FunctionDecl * dcl );122 void generatePrototypes( std::list< FunctionDecl * > & newFuncs );123 };124 125 class StructFuncGenerator : public FuncGenerator {126 StructDecl * aggregateDecl;127 public:128 StructFuncGenerator( StructDecl * aggregateDecl, StructInstType * refType, const std::vector< FuncData > & data, unsigned int functionNesting, SymTab::Indexer & indexer ) : FuncGenerator( refType, data, functionNesting, indexer ), aggregateDecl( aggregateDecl) {}129 130 virtual bool shouldAutogen() const override;131 virtual bool isConcurrentType() const override;132 133 virtual void genFuncBody( FunctionDecl * dcl ) override;134 virtual void genFieldCtors() override;135 136 private:137 /// generates a single struct member operation (constructor call, destructor call, assignment call)138 void makeMemberOp( ObjectDecl * dstParam, Expression * src, DeclarationWithType * field, FunctionDecl * func, bool forward = true );139 140 /// generates the body of a struct function by iterating the struct members (via parameters) - generates default ctor, copy ctor, assignment, and dtor bodies, but NOT field ctor bodies141 template<typename Iterator>142 void makeFunctionBody( Iterator member, Iterator end, FunctionDecl * func, bool forward = true );143 144 /// generate the body of a constructor which takes parameters that match fields, e.g.145 /// void ?{}(A *, int) and void?{}(A *, int, int) for a struct A which has two int fields.146 template<typename Iterator>147 void makeFieldCtorBody( Iterator member, Iterator end, FunctionDecl * func );148 };149 150 class UnionFuncGenerator : public FuncGenerator {151 UnionDecl * aggregateDecl;152 public:153 UnionFuncGenerator( UnionDecl * aggregateDecl, UnionInstType * refType, const std::vector< FuncData > & data, unsigned int functionNesting, SymTab::Indexer & indexer ) : FuncGenerator( refType, data, functionNesting, indexer ), aggregateDecl( aggregateDecl) {}154 155 virtual bool shouldAutogen() const override;156 virtual bool isConcurrentType() const override;157 158 virtual void genFuncBody( FunctionDecl * dcl ) override;159 virtual void genFieldCtors() override;160 161 private:162 /// generates a single struct member operation (constructor call, destructor call, assignment call)163 template<typename OutputIterator>164 void makeMemberOp( ObjectDecl * srcParam, ObjectDecl * dstParam, OutputIterator out );165 166 /// generates the body of a struct function by iterating the struct members (via parameters) - generates default ctor, copy ctor, assignment, and dtor bodies, but NOT field ctor bodies167 template<typename Iterator>168 void makeFunctionBody( Iterator member, Iterator end, FunctionDecl * func, bool forward = true );169 170 /// generate the body of a constructor which takes parameters that match fields, e.g.171 /// void ?{}(A *, int) and void?{}(A *, int, int) for a struct A which has two int fields.172 template<typename Iterator>173 void makeFieldCtorBody( Iterator member, Iterator end, FunctionDecl * func );174 };175 176 class EnumFuncGenerator : public FuncGenerator {177 public:178 EnumFuncGenerator( EnumInstType * refType, const std::vector< FuncData > & data, unsigned int functionNesting, SymTab::Indexer & indexer ) : FuncGenerator( refType, data, functionNesting, indexer ) {}179 180 virtual bool shouldAutogen() const override;181 virtual bool isConcurrentType() const override;182 183 virtual void genFuncBody( FunctionDecl * dcl ) override;184 virtual void genFieldCtors() override;185 186 private:187 };188 189 class TypeFuncGenerator : public FuncGenerator {190 TypeDecl * typeDecl;191 public:192 TypeFuncGenerator( TypeDecl * typeDecl, TypeInstType * refType, const std::vector<FuncData> & data, unsigned int functionNesting, SymTab::Indexer & indexer ) : FuncGenerator( refType, data, functionNesting, indexer ), typeDecl( typeDecl ) {}193 194 virtual bool shouldAutogen() const override;195 virtual void genFuncBody( FunctionDecl * dcl ) override;196 virtual bool isConcurrentType() const override;197 virtual void genFieldCtors() override;198 };199 200 //=============================================================================================201 // helper functions202 //=============================================================================================203 void generateFunctions( FuncGenerator & gen, std::list< Declaration * > & declsToAdd ) {204 if ( ! gen.shouldAutogen() ) return;205 206 // generate each of the functions based on the supplied FuncData objects207 gen.genStandardFuncs();208 gen.genFieldCtors();209 210 declsToAdd.splice( declsToAdd.end(), gen.forwards );211 declsToAdd.splice( declsToAdd.end(), gen.definitions );212 }213 214 103 bool isUnnamedBitfield( ObjectDecl * obj ) { 215 return obj != nullptr && obj-> name == "" && obj->bitfieldWidth!= nullptr;104 return obj != nullptr && obj->get_name() == "" && obj->get_bitfieldWidth() != nullptr; 216 105 } 217 106 … … 219 108 void addForwardDecl( FunctionDecl * functionDecl, std::list< Declaration * > & declsToAdd ) { 220 109 FunctionDecl * decl = functionDecl->clone(); 221 delete decl-> statements;222 decl->s tatements = nullptr;110 delete decl->get_statements(); 111 decl->set_statements( nullptr ); 223 112 declsToAdd.push_back( decl ); 224 113 decl->fixUniqueId(); 225 114 } 226 115 227 const std::list< TypeDecl * > getGenericParams( Type * t ) {228 std::list< TypeDecl * > * ret = nullptr;229 if ( StructInstType * inst = dynamic_cast< StructInstType * > ( t ) ) {230 ret = inst->get_baseParameters();231 } else if ( UnionInstType * inst = dynamic_cast< UnionInstType * >( t ) ) {232 ret = inst->get_baseParameters();233 }234 return ret ? *ret : std::list< TypeDecl * >();235 }236 237 116 /// given type T, generate type of default ctor/dtor, i.e. function type void (*) (T *) 238 117 FunctionType * genDefaultType( Type * paramType ) { 239 const auto & typeParams = getGenericParams( paramType );240 118 FunctionType *ftype = new FunctionType( Type::Qualifiers(), false ); 241 cloneAll( typeParams, ftype->forall );242 119 ObjectDecl *dstParam = new ObjectDecl( "_dst", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, new ReferenceType( Type::Qualifiers(), paramType->clone() ), nullptr ); 243 ftype-> parameters.push_back( dstParam );120 ftype->get_parameters().push_back( dstParam ); 244 121 return ftype; 245 122 } … … 249 126 FunctionType *ftype = genDefaultType( paramType ); 250 127 ObjectDecl *srcParam = new ObjectDecl( "_src", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, paramType->clone(), nullptr ); 251 ftype-> parameters.push_back( srcParam );128 ftype->get_parameters().push_back( srcParam ); 252 129 return ftype; 253 130 } … … 257 134 FunctionType *ftype = genCopyType( paramType ); 258 135 ObjectDecl *returnVal = new ObjectDecl( "_ret", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, paramType->clone(), nullptr ); 259 ftype-> returnVals.push_back( returnVal );136 ftype->get_returnVals().push_back( returnVal ); 260 137 return ftype; 261 138 } … … 274 151 } 275 152 276 Type * declToType( Declaration * decl ) { 277 if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * >( decl ) ) { 278 return dwt->get_type(); 279 } 280 return nullptr; 281 } 282 283 Type * declToTypeDeclBase( Declaration * decl ) { 284 if ( TypeDecl * td = dynamic_cast< TypeDecl * >( decl ) ) { 285 return td->base; 286 } 287 return nullptr; 288 } 289 290 //============================================================================================= 291 // FuncGenerator member definitions 292 //============================================================================================= 293 void FuncGenerator::genStandardFuncs() { 294 std::list< FunctionDecl * > newFuncs; 295 generatePrototypes( newFuncs ); 296 297 for ( FunctionDecl * dcl : newFuncs ) { 298 genFuncBody( dcl ); 299 if ( CodeGen::isAssignment( dcl->name ) ) { 300 // assignment needs to return a value 301 FunctionType * assignType = dcl->type; 302 assert( assignType->parameters.size() == 2 ); 303 assert( assignType->returnVals.size() == 1 ); 304 ObjectDecl * dstParam = strict_dynamic_cast< ObjectDecl * >( assignType->parameters.front() ); 305 dcl->statements->push_back( new ReturnStmt( noLabels, new VariableExpr( dstParam ) ) ); 306 } 307 resolve( dcl ); 308 } 309 } 310 311 void FuncGenerator::generatePrototypes( std::list< FunctionDecl * > & newFuncs ) { 312 bool concurrent_type = isConcurrentType(); 313 for ( const FuncData & data : data ) { 314 // generate a function (?{}, ?=?, ^?{}) based on the current FuncData. 315 FunctionType * ftype = data.genType( type ); 316 317 // destructor for concurrent type must be mutex 153 /// inserts base type of first argument into map if pred(funcDecl) is true 154 void insert( FunctionDecl *funcDecl, TypeMap & map, FunctionDecl * (*pred)(Declaration *) ) { 155 // insert type into constructable, etc. map if appropriate 156 if ( pred( funcDecl ) ) { 157 FunctionType * ftype = funcDecl->get_functionType(); 158 assert( ! ftype->get_parameters().empty() ); 159 Type * t = InitTweak::getPointerBase( ftype->get_parameters().front()->get_type() ); 160 assert( t ); 161 map.insert( Mangler::mangleType( t ), true ); 162 } 163 } 164 165 /// using map and t, determines if is constructable, etc. 166 bool lookup( const TypeMap & map, Type * t ) { 167 assertf( t, "Autogenerate lookup was given non-type: %s", toString( t ).c_str() ); 168 if ( dynamic_cast< PointerType * >( t ) ) { 169 // will need more complicated checking if we want this to work with pointer types, since currently 170 return true; 171 } else if ( ArrayType * at = dynamic_cast< ArrayType * >( t ) ) { 172 // an array's constructor, etc. is generated on the fly based on the base type's constructor, etc. 173 return lookup( map, at->get_base() ); 174 } 175 TypeMap::const_iterator it = map.find( Mangler::mangleType( t ) ); 176 if ( it != map.end() ) return it->second; 177 // something that does not appear in the map is by default not constructable, etc. 178 return false; 179 } 180 181 /// using map and aggr, examines each member to determine if constructor, etc. should be generated 182 template<typename Container> 183 bool shouldGenerate( const TypeMap & map, const Container & container ) { 184 for ( Type * t : container ) { 185 if ( ! lookup( map, t ) ) return false; 186 } 187 return true; 188 } 189 190 /// data structure for abstracting the generation of special functions 191 template< typename OutputIterator, typename Container > 192 struct FuncGenerator { 193 const Container & container; 194 Type *refType; 195 unsigned int functionNesting; 196 const std::list< TypeDecl* > & typeParams; 197 OutputIterator out; 198 FuncGenerator( const Container & container, Type *refType, unsigned int functionNesting, const std::list< TypeDecl* > & typeParams, OutputIterator out ) : container( container ), refType( refType ), functionNesting( functionNesting ), typeParams( typeParams ), out( out ) {} 199 200 /// generates a function (?{}, ?=?, ^?{}) based on the data argument and members. If function is generated, inserts the type into the map. 201 void gen( const FuncData & data, bool concurrent_type ) { 202 if ( ! shouldGenerate( data.map, container ) ) return; 203 FunctionType * ftype = data.genType( refType ); 204 318 205 if ( concurrent_type && CodeGen::isDestructor( data.fname ) ) { 319 206 ftype->parameters.front()->get_type()->set_mutex( true ); 320 207 } 321 208 322 newFuncs.push_back( genFunc( data.fname, ftype, functionNesting ) ); 323 } 324 } 325 326 void FuncGenerator::resolve( FunctionDecl * dcl ) { 327 try { 328 ResolvExpr::resolveDecl( dcl, indexer ); 329 if ( functionNesting == 0 ) { 330 // forward declare if top-level struct, so that 331 // type is complete as soon as its body ends 332 // Note: this is necessary if we want structs which contain 333 // generic (otype) structs as members. 334 addForwardDecl( dcl, forwards ); 335 } 336 definitions.push_back( dcl ); 337 indexer.addId( dcl ); 338 } catch ( SemanticError err ) { 339 // okay if decl does not resolve - that means the function should not be generated 340 delete dcl; 341 } 342 } 343 344 bool StructFuncGenerator::shouldAutogen() const { 345 // Builtins do not use autogeneration. 346 return ! aggregateDecl->linkage.is_builtin; 347 } 348 bool StructFuncGenerator::isConcurrentType() const { return aggregateDecl->is_thread() || aggregateDecl->is_monitor(); } 349 350 void StructFuncGenerator::genFuncBody( FunctionDecl * dcl ) { 351 // generate appropriate calls to member ctor, assignment 352 // destructor needs to do everything in reverse, so pass "forward" based on whether the function is a destructor 353 if ( ! CodeGen::isDestructor( dcl->name ) ) { 354 makeFunctionBody( aggregateDecl->members.begin(), aggregateDecl->members.end(), dcl ); 355 } else { 356 makeFunctionBody( aggregateDecl->members.rbegin(), aggregateDecl->members.rend(), dcl, false ); 357 } 358 } 359 360 void StructFuncGenerator::genFieldCtors() { 361 // field ctors are only generated if default constructor and copy constructor are both generated 362 unsigned numCtors = std::count_if( definitions.begin(), definitions.end(), [](Declaration * dcl) { return CodeGen::isConstructor( dcl->name ); } ); 363 364 // Field constructors are only generated if default and copy constructor 365 // are generated, since they need access to both 366 if ( numCtors != 2 ) return; 367 368 // create constructors which take each member type as a parameter. 369 // for example, for struct A { int x, y; }; generate 370 // void ?{}(A *, int) and void ?{}(A *, int, int) 371 FunctionType * memCtorType = genDefaultType( type ); 372 for ( Declaration * member : aggregateDecl->members ) { 373 DeclarationWithType * field = strict_dynamic_cast<DeclarationWithType *>( member ); 374 if ( isUnnamedBitfield( dynamic_cast< ObjectDecl * > ( field ) ) ) { 375 // don't make a function whose parameter is an unnamed bitfield 376 continue; 377 } 378 memCtorType->parameters.push_back( new ObjectDecl( field->name, Type::StorageClasses(), LinkageSpec::Cforall, 0, field->get_type()->clone(), 0 ) ); 379 FunctionDecl * ctor = genFunc( "?{}", memCtorType->clone(), functionNesting ); 380 makeFieldCtorBody( aggregateDecl->members.begin(), aggregateDecl->members.end(), ctor ); 381 resolve( ctor ); 382 } 383 delete memCtorType; 384 } 385 386 void StructFuncGenerator::makeMemberOp( ObjectDecl * dstParam, Expression * src, DeclarationWithType * field, FunctionDecl * func, bool forward ) { 209 cloneAll( typeParams, ftype->forall ); 210 *out++ = genFunc( data.fname, ftype, functionNesting ); 211 data.map.insert( Mangler::mangleType( refType ), true ); 212 } 213 }; 214 215 template< typename OutputIterator, typename Container > 216 FuncGenerator<OutputIterator, Container> makeFuncGenerator( const Container & container, Type *refType, unsigned int functionNesting, const std::list< TypeDecl* > & typeParams, OutputIterator out ) { 217 return FuncGenerator<OutputIterator, Container>( container, refType, functionNesting, typeParams, out ); 218 } 219 220 /// generates a single enumeration assignment expression 221 ApplicationExpr * genEnumAssign( FunctionType * ftype, FunctionDecl * assignDecl ) { 222 // enum copy construct and assignment is just C-style assignment. 223 // this looks like a bad recursive call, but code gen will turn it into 224 // a C-style assignment. 225 // This happens before function pointer type conversion, so need to do it manually here 226 // NOTE: ftype is not necessarily the functionType belonging to assignDecl - ftype is the 227 // type of the function that this expression is being generated for (so that the correct 228 // parameters) are using in the variable exprs 229 assert( ftype->get_parameters().size() == 2 ); 230 ObjectDecl * dstParam = strict_dynamic_cast< ObjectDecl * >( ftype->get_parameters().front() ); 231 ObjectDecl * srcParam = strict_dynamic_cast< ObjectDecl * >( ftype->get_parameters().back() ); 232 233 VariableExpr * assignVarExpr = new VariableExpr( assignDecl ); 234 Type * assignVarExprType = assignVarExpr->get_result(); 235 assignVarExprType = new PointerType( Type::Qualifiers(), assignVarExprType ); 236 assignVarExpr->set_result( assignVarExprType ); 237 ApplicationExpr * assignExpr = new ApplicationExpr( assignVarExpr ); 238 assignExpr->get_args().push_back( new VariableExpr( dstParam ) ); 239 assignExpr->get_args().push_back( new VariableExpr( srcParam ) ); 240 return assignExpr; 241 } 242 243 // E ?=?(E volatile*, int), 244 // ?=?(E _Atomic volatile*, int); 245 void makeEnumFunctions( EnumInstType *refType, unsigned int functionNesting, std::list< Declaration * > &declsToAdd ) { 246 247 // T ?=?(E *, E); 248 FunctionType *assignType = genAssignType( refType ); 249 250 // void ?{}(E *); void ^?{}(E *); 251 FunctionType * ctorType = genDefaultType( refType->clone() ); 252 FunctionType * dtorType = genDefaultType( refType->clone() ); 253 254 // void ?{}(E *, E); 255 FunctionType *copyCtorType = genCopyType( refType->clone() ); 256 257 // add unused attribute to parameters of default constructor and destructor 258 ctorType->get_parameters().front()->get_attributes().push_back( new Attribute( "unused" ) ); 259 dtorType->get_parameters().front()->get_attributes().push_back( new Attribute( "unused" ) ); 260 261 // xxx - should we also generate void ?{}(E *, int) and E ?{}(E *, E)? 262 // right now these cases work, but that might change. 263 264 // xxx - Temporary: make these functions intrinsic so they codegen as C assignment. 265 // Really they're something of a cross between instrinsic and autogen, so should 266 // probably make a new linkage type 267 FunctionDecl *assignDecl = genFunc( "?=?", assignType, functionNesting, true ); 268 FunctionDecl *ctorDecl = genFunc( "?{}", ctorType, functionNesting, true ); 269 FunctionDecl *copyCtorDecl = genFunc( "?{}", copyCtorType, functionNesting, true ); 270 FunctionDecl *dtorDecl = genFunc( "^?{}", dtorType, functionNesting, true ); 271 272 // body is either return stmt or expr stmt 273 assignDecl->get_statements()->get_kids().push_back( new ReturnStmt( noLabels, genEnumAssign( assignType, assignDecl ) ) ); 274 copyCtorDecl->get_statements()->get_kids().push_back( new ExprStmt( noLabels, genEnumAssign( copyCtorType, assignDecl ) ) ); 275 276 declsToAdd.push_back( ctorDecl ); 277 declsToAdd.push_back( copyCtorDecl ); 278 declsToAdd.push_back( dtorDecl ); 279 declsToAdd.push_back( assignDecl ); // assignment should come last since it uses copy constructor in return 280 } 281 282 /// generates a single struct member operation (constructor call, destructor call, assignment call) 283 void makeStructMemberOp( ObjectDecl * dstParam, Expression * src, DeclarationWithType * field, FunctionDecl * func, bool forward = true ) { 387 284 InitTweak::InitExpander srcParam( src ); 388 285 389 286 // assign to destination 390 Expression *dstselect = new MemberExpr( field, new CastExpr( new VariableExpr( dstParam ), strict_dynamic_cast< ReferenceType* >( dstParam->get_type() )->base->clone() ) ); 391 genImplicitCall( srcParam, dstselect, func->name, back_inserter( func->statements->kids ), field, forward ); 392 } 393 287 Expression *dstselect = new MemberExpr( field, new CastExpr( new VariableExpr( dstParam ), strict_dynamic_cast< ReferenceType* >( dstParam->get_type() )->get_base()->clone() ) ); 288 genImplicitCall( srcParam, dstselect, func->get_name(), back_inserter( func->get_statements()->get_kids() ), field, forward ); 289 } 290 291 /// generates the body of a struct function by iterating the struct members (via parameters) - generates default ctor, copy ctor, assignment, and dtor bodies, but NOT field ctor bodies 394 292 template<typename Iterator> 395 void StructFuncGenerator::makeFunctionBody( Iterator member, Iterator end, FunctionDecl * func, bool forward) {293 void makeStructFunctionBody( Iterator member, Iterator end, FunctionDecl * func, bool forward = true ) { 396 294 for ( ; member != end; ++member ) { 397 295 if ( DeclarationWithType *field = dynamic_cast< DeclarationWithType * >( *member ) ) { // otherwise some form of type declaration, e.g. Aggregate … … 403 301 } 404 302 405 if ( type->get_const() && CodeGen::isAssignment( func->name )) {303 if ( type->get_const() && func->get_name() == "?=?" ) { 406 304 // don't assign const members, but do construct/destruct 305 continue; 306 } 307 308 if ( field->get_name() == "" ) { 309 // don't assign to anonymous members 310 // xxx - this is a temporary fix. Anonymous members tie into 311 // our inheritance model. I think the correct way to handle this is to 312 // cast the structure to the type of the member and let the resolver 313 // figure out whether it's valid and have a pass afterwards that fixes 314 // the assignment to use pointer arithmetic with the offset of the 315 // member, much like how generic type members are handled. 407 316 continue; 408 317 } … … 414 323 srcParam = dynamic_cast<ObjectDecl*>( func->get_functionType()->get_parameters().back() ); 415 324 } 416 417 325 // srcParam may be NULL, in which case we have default ctor/dtor 418 326 assert( dstParam ); 419 327 420 328 Expression *srcselect = srcParam ? new MemberExpr( field, new VariableExpr( srcParam ) ) : nullptr; 421 make MemberOp( dstParam, srcselect, field, func, forward );329 makeStructMemberOp( dstParam, srcselect, field, func, forward ); 422 330 } // if 423 331 } // for 424 } // makeFunctionBody 425 332 } // makeStructFunctionBody 333 334 /// generate the body of a constructor which takes parameters that match fields, e.g. 335 /// void ?{}(A *, int) and void?{}(A *, int, int) for a struct A which has two int fields. 426 336 template<typename Iterator> 427 void StructFuncGenerator::makeFieldCtorBody( Iterator member, Iterator end, FunctionDecl * func ) {428 FunctionType * ftype = func-> type;429 std::list<DeclarationWithType*> & params = ftype-> parameters;337 void makeStructFieldCtorBody( Iterator member, Iterator end, FunctionDecl * func ) { 338 FunctionType * ftype = func->get_functionType(); 339 std::list<DeclarationWithType*> & params = ftype->get_parameters(); 430 340 assert( params.size() >= 2 ); // should not call this function for default ctor, etc. 431 341 … … 439 349 // don't make a function whose parameter is an unnamed bitfield 440 350 continue; 351 } else if ( field->get_name() == "" ) { 352 // don't assign to anonymous members 353 // xxx - this is a temporary fix. Anonymous members tie into 354 // our inheritance model. I think the correct way to handle this is to 355 // cast the structure to the type of the member and let the resolver 356 // figure out whether it's valid and have a pass afterwards that fixes 357 // the assignment to use pointer arithmetic with the offset of the 358 // member, much like how generic type members are handled. 359 continue; 441 360 } else if ( parameter != params.end() ) { 442 361 // matching parameter, initialize field with copy ctor 443 362 Expression *srcselect = new VariableExpr(*parameter); 444 make MemberOp( dstParam, srcselect, field, func );363 makeStructMemberOp( dstParam, srcselect, field, func ); 445 364 ++parameter; 446 365 } else { 447 366 // no matching parameter, initialize field with default ctor 448 make MemberOp( dstParam, nullptr, field, func );367 makeStructMemberOp( dstParam, nullptr, field, func ); 449 368 } 450 369 } … … 452 371 } 453 372 454 bool UnionFuncGenerator::shouldAutogen() const { 373 Type * declToType( Declaration * decl ) { 374 if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * >( decl ) ) { 375 return dwt->get_type(); 376 } 377 return nullptr; 378 } 379 380 /// generates struct constructors, destructor, and assignment functions 381 void makeStructFunctions( StructDecl *aggregateDecl, StructInstType *refType, unsigned int functionNesting, std::list< Declaration * > & declsToAdd, const std::vector< FuncData > & data ) { 455 382 // Builtins do not use autogeneration. 456 return ! aggregateDecl->linkage.is_builtin; 457 } 458 459 // xxx - is this right? 460 bool UnionFuncGenerator::isConcurrentType() const { return false; }; 383 if ( LinkageSpec::isBuiltin( aggregateDecl->get_linkage() ) ) { 384 return; 385 } 386 387 // Make function polymorphic in same parameters as generic struct, if applicable 388 const std::list< TypeDecl * > & typeParams = aggregateDecl->get_parameters(); // List of type variables to be placed on the generated functions 389 390 // generate each of the functions based on the supplied FuncData objects 391 std::list< FunctionDecl * > newFuncs; 392 // structure that iterates aggregate decl members, returning their types 393 auto generator = makeFuncGenerator( lazy_map( aggregateDecl->members, declToType ), refType, functionNesting, typeParams, back_inserter( newFuncs ) ); 394 for ( const FuncData & d : data ) { 395 generator.gen( d, aggregateDecl->is_thread() || aggregateDecl->is_monitor() ); 396 } 397 398 // field ctors are only generated if default constructor and copy constructor are both generated 399 unsigned numCtors = std::count_if( newFuncs.begin(), newFuncs.end(), [](FunctionDecl * dcl) { return CodeGen::isConstructor( dcl->get_name() ); } ); 400 401 if ( functionNesting == 0 ) { 402 // forward declare if top-level struct, so that 403 // type is complete as soon as its body ends 404 // Note: this is necessary if we want structs which contain 405 // generic (otype) structs as members. 406 for ( FunctionDecl * dcl : newFuncs ) { 407 addForwardDecl( dcl, declsToAdd ); 408 } 409 } 410 411 for ( FunctionDecl * dcl : newFuncs ) { 412 // generate appropriate calls to member ctor, assignment 413 // destructor needs to do everything in reverse, so pass "forward" based on whether the function is a destructor 414 if ( ! CodeGen::isDestructor( dcl->get_name() ) ) { 415 makeStructFunctionBody( aggregateDecl->get_members().begin(), aggregateDecl->get_members().end(), dcl ); 416 } else { 417 makeStructFunctionBody( aggregateDecl->get_members().rbegin(), aggregateDecl->get_members().rend(), dcl, false ); 418 } 419 if ( CodeGen::isAssignment( dcl->get_name() ) ) { 420 // assignment needs to return a value 421 FunctionType * assignType = dcl->get_functionType(); 422 assert( assignType->get_parameters().size() == 2 ); 423 ObjectDecl * srcParam = strict_dynamic_cast< ObjectDecl * >( assignType->get_parameters().back() ); 424 dcl->get_statements()->get_kids().push_back( new ReturnStmt( noLabels, new VariableExpr( srcParam ) ) ); 425 } 426 declsToAdd.push_back( dcl ); 427 } 428 429 // create constructors which take each member type as a parameter. 430 // for example, for struct A { int x, y; }; generate 431 // void ?{}(A *, int) and void ?{}(A *, int, int) 432 // Field constructors are only generated if default and copy constructor 433 // are generated, since they need access to both 434 if ( numCtors == 2 ) { 435 FunctionType * memCtorType = genDefaultType( refType ); 436 cloneAll( typeParams, memCtorType->get_forall() ); 437 for ( std::list<Declaration *>::iterator i = aggregateDecl->get_members().begin(); i != aggregateDecl->get_members().end(); ++i ) { 438 DeclarationWithType * member = dynamic_cast<DeclarationWithType *>( *i ); 439 assert( member ); 440 if ( isUnnamedBitfield( dynamic_cast< ObjectDecl * > ( member ) ) ) { 441 // don't make a function whose parameter is an unnamed bitfield 442 continue; 443 } else if ( member->get_name() == "" ) { 444 // don't assign to anonymous members 445 // xxx - this is a temporary fix. Anonymous members tie into 446 // our inheritance model. I think the correct way to handle this is to 447 // cast the structure to the type of the member and let the resolver 448 // figure out whether it's valid/choose the correct unnamed member 449 continue; 450 } 451 memCtorType->get_parameters().push_back( new ObjectDecl( member->get_name(), Type::StorageClasses(), LinkageSpec::Cforall, 0, member->get_type()->clone(), 0 ) ); 452 FunctionDecl * ctor = genFunc( "?{}", memCtorType->clone(), functionNesting ); 453 makeStructFieldCtorBody( aggregateDecl->get_members().begin(), aggregateDecl->get_members().end(), ctor ); 454 declsToAdd.push_back( ctor ); 455 } 456 delete memCtorType; 457 } 458 } 461 459 462 460 /// generate a single union assignment expression (using memcpy) 463 461 template< typename OutputIterator > 464 void UnionFuncGenerator::makeMemberOp( ObjectDecl * srcParam, ObjectDecl * dstParam, OutputIterator out ) {462 void makeUnionFieldsAssignment( ObjectDecl * srcParam, ObjectDecl * dstParam, OutputIterator out ) { 465 463 UntypedExpr *copy = new UntypedExpr( new NameExpr( "__builtin_memcpy" ) ); 466 copy-> args.push_back( new AddressExpr( new VariableExpr( dstParam ) ) );467 copy-> args.push_back( new AddressExpr( new VariableExpr( srcParam ) ) );468 copy-> args.push_back( new SizeofExpr( srcParam->get_type()->clone() ) );464 copy->get_args().push_back( new AddressExpr( new VariableExpr( dstParam ) ) ); 465 copy->get_args().push_back( new AddressExpr( new VariableExpr( srcParam ) ) ); 466 copy->get_args().push_back( new SizeofExpr( srcParam->get_type()->clone() ) ); 469 467 *out++ = new ExprStmt( noLabels, copy ); 470 468 } 471 469 472 470 /// generates the body of a union assignment/copy constructor/field constructor 473 void UnionFuncGenerator::genFuncBody( FunctionDecl * funcDecl ) { 474 FunctionType * ftype = funcDecl->type; 475 if ( InitTweak::isCopyConstructor( funcDecl ) || InitTweak::isAssignment( funcDecl ) ) { 476 assert( ftype->parameters.size() == 2 ); 477 ObjectDecl * dstParam = strict_dynamic_cast< ObjectDecl * >( ftype->parameters.front() ); 478 ObjectDecl * srcParam = strict_dynamic_cast< ObjectDecl * >( ftype->parameters.back() ); 479 makeMemberOp( srcParam, dstParam, back_inserter( funcDecl->statements->kids ) ); 480 } else { 481 // default ctor/dtor body is empty - add unused attribute to parameter to silence warnings 482 assert( ftype->parameters.size() == 1 ); 483 ObjectDecl * dstParam = strict_dynamic_cast< ObjectDecl * >( ftype->parameters.front() ); 484 dstParam->attributes.push_back( new Attribute( "unused" ) ); 485 } 486 } 487 488 /// generate the body of a constructor which takes parameters that match fields, e.g. 489 /// void ?{}(A *, int) and void?{}(A *, int, int) for a struct A which has two int fields. 490 void UnionFuncGenerator::genFieldCtors() { 491 // field ctors are only generated if default constructor and copy constructor are both generated 492 unsigned numCtors = std::count_if( definitions.begin(), definitions.end(), [](Declaration * dcl) { return CodeGen::isConstructor( dcl->get_name() ); } ); 493 494 // Field constructors are only generated if default and copy constructor 495 // are generated, since they need access to both 496 if ( numCtors != 2 ) return; 471 void makeUnionAssignBody( FunctionDecl * funcDecl ) { 472 FunctionType * ftype = funcDecl->get_functionType(); 473 assert( ftype->get_parameters().size() == 2 ); 474 ObjectDecl * dstParam = strict_dynamic_cast< ObjectDecl * >( ftype->get_parameters().front() ); 475 ObjectDecl * srcParam = strict_dynamic_cast< ObjectDecl * >( ftype->get_parameters().back() ); 476 477 makeUnionFieldsAssignment( srcParam, dstParam, back_inserter( funcDecl->get_statements()->get_kids() ) ); 478 if ( CodeGen::isAssignment( funcDecl->get_name() ) ) { 479 // also generate return statement in assignment 480 funcDecl->get_statements()->get_kids().push_back( new ReturnStmt( noLabels, new VariableExpr( srcParam ) ) ); 481 } 482 } 483 484 /// generates union constructors, destructors, and assignment operator 485 void makeUnionFunctions( UnionDecl *aggregateDecl, UnionInstType *refType, unsigned int functionNesting, std::list< Declaration * > & declsToAdd ) { 486 // Make function polymorphic in same parameters as generic union, if applicable 487 const std::list< TypeDecl* > & typeParams = aggregateDecl->get_parameters(); // List of type variables to be placed on the generated functions 488 489 // default ctor/dtor need only first parameter 490 // void ?{}(T *); void ^?{}(T *); 491 FunctionType *ctorType = genDefaultType( refType ); 492 FunctionType *dtorType = genDefaultType( refType ); 493 494 // copy ctor needs both parameters 495 // void ?{}(T *, T); 496 FunctionType *copyCtorType = genCopyType( refType ); 497 498 // assignment needs both and return value 499 // T ?=?(T *, T); 500 FunctionType *assignType = genAssignType( refType ); 501 502 cloneAll( typeParams, ctorType->get_forall() ); 503 cloneAll( typeParams, dtorType->get_forall() ); 504 cloneAll( typeParams, copyCtorType->get_forall() ); 505 cloneAll( typeParams, assignType->get_forall() ); 506 507 // add unused attribute to parameters of default constructor and destructor 508 ctorType->get_parameters().front()->get_attributes().push_back( new Attribute( "unused" ) ); 509 dtorType->get_parameters().front()->get_attributes().push_back( new Attribute( "unused" ) ); 510 511 // Routines at global scope marked "static" to prevent multiple definitions is separate translation units 512 // because each unit generates copies of the default routines for each aggregate. 513 FunctionDecl *assignDecl = genFunc( "?=?", assignType, functionNesting ); 514 FunctionDecl *ctorDecl = genFunc( "?{}", ctorType, functionNesting ); 515 FunctionDecl *copyCtorDecl = genFunc( "?{}", copyCtorType, functionNesting ); 516 FunctionDecl *dtorDecl = genFunc( "^?{}", dtorType, functionNesting ); 517 518 makeUnionAssignBody( assignDecl ); 519 520 // body of assignment and copy ctor is the same 521 makeUnionAssignBody( copyCtorDecl ); 497 522 498 523 // create a constructor which takes the first member type as a parameter. … … 500 525 // void ?{}(A *, int) 501 526 // This is to mimic C's behaviour which initializes the first member of the union. 502 FunctionType * memCtorType = genDefaultType( type ); 503 for ( Declaration * member : aggregateDecl->members ) { 504 DeclarationWithType * field = strict_dynamic_cast<DeclarationWithType *>( member ); 505 if ( isUnnamedBitfield( dynamic_cast< ObjectDecl * > ( field ) ) ) { 506 // don't make a function whose parameter is an unnamed bitfield 527 std::list<Declaration *> memCtors; 528 for ( Declaration * member : aggregateDecl->get_members() ) { 529 if ( DeclarationWithType * field = dynamic_cast< DeclarationWithType * >( member ) ) { 530 ObjectDecl * srcParam = new ObjectDecl( "src", Type::StorageClasses(), LinkageSpec::Cforall, 0, field->get_type()->clone(), 0 ); 531 532 FunctionType * memCtorType = ctorType->clone(); 533 memCtorType->get_parameters().push_back( srcParam ); 534 FunctionDecl * ctor = genFunc( "?{}", memCtorType, functionNesting ); 535 536 makeUnionAssignBody( ctor ); 537 memCtors.push_back( ctor ); 538 // only generate a ctor for the first field 507 539 break; 508 540 } 509 memCtorType->parameters.push_back( new ObjectDecl( field->name, Type::StorageClasses(), LinkageSpec::Cforall, nullptr, field->get_type()->clone(), nullptr ) ); 510 FunctionDecl * ctor = genFunc( "?{}", memCtorType->clone(), functionNesting ); 511 ObjectDecl * srcParam = strict_dynamic_cast<ObjectDecl *>( ctor->type->parameters.back() ); 512 srcParam->fixUniqueId(); 513 ObjectDecl * dstParam = InitTweak::getParamThis( ctor->type ); 514 makeMemberOp( srcParam, dstParam, back_inserter( ctor->statements->kids ) ); 515 resolve( ctor ); 516 // only generate one field ctor for unions 517 break; 518 } 519 delete memCtorType; 520 } 521 522 void EnumFuncGenerator::genFuncBody( FunctionDecl * funcDecl ) { 523 // xxx - Temporary: make these functions intrinsic so they codegen as C assignment. 524 // Really they're something of a cross between instrinsic and autogen, so should 525 // probably make a new linkage type 526 funcDecl->linkage = LinkageSpec::Intrinsic; 527 FunctionType * ftype = funcDecl->type; 528 if ( InitTweak::isCopyConstructor( funcDecl ) || InitTweak::isAssignment( funcDecl ) ) { 529 assert( ftype->parameters.size() == 2 ); 530 ObjectDecl * dstParam = strict_dynamic_cast< ObjectDecl * >( ftype->parameters.front() ); 531 ObjectDecl * srcParam = strict_dynamic_cast< ObjectDecl * >( ftype->parameters.back() ); 532 533 // enum copy construct and assignment is just C-style assignment. 534 // this looks like a bad recursive call, but code gen will turn it into 535 // a C-style assignment. 536 // This happens before function pointer type conversion, so need to do it manually here 537 ApplicationExpr * callExpr = new ApplicationExpr( VariableExpr::functionPointer( funcDecl ) ); 538 callExpr->get_args().push_back( new VariableExpr( dstParam ) ); 539 callExpr->get_args().push_back( new VariableExpr( srcParam ) ); 540 funcDecl->statements->push_back( new ExprStmt( noLabels, callExpr ) ); 541 } else { 542 // default ctor/dtor body is empty - add unused attribute to parameter to silence warnings 543 assert( ftype->parameters.size() == 1 ); 544 ObjectDecl * dstParam = strict_dynamic_cast< ObjectDecl * >( ftype->parameters.front() ); 545 dstParam->attributes.push_back( new Attribute( "unused" ) ); 546 } 547 } 548 549 bool EnumFuncGenerator::shouldAutogen() const { return true; } 550 bool EnumFuncGenerator::isConcurrentType() const { return false; } 551 // enums do not have field constructors 552 void EnumFuncGenerator::genFieldCtors() {} 553 554 bool TypeFuncGenerator::shouldAutogen() const { return true; }; 555 556 void TypeFuncGenerator::genFuncBody( FunctionDecl * dcl ) { 557 FunctionType * ftype = dcl->type; 558 assertf( ftype->parameters.size() == 1 || ftype->parameters.size() == 2, "Incorrect number of parameters in autogenerated typedecl function: %zd", ftype->parameters.size() ); 559 DeclarationWithType * dst = ftype->parameters.front(); 560 DeclarationWithType * src = ftype->parameters.size() == 2 ? ftype->parameters.back() : nullptr; 561 // generate appropriate calls to member ctor, assignment 562 UntypedExpr * expr = new UntypedExpr( new NameExpr( dcl->name ) ); 563 expr->args.push_back( new CastExpr( new VariableExpr( dst ), new ReferenceType( Type::Qualifiers(), typeDecl->base->clone() ) ) ); 564 if ( src ) expr->args.push_back( new CastExpr( new VariableExpr( src ), typeDecl->base->clone() ) ); 565 dcl->statements->kids.push_back( new ExprStmt( noLabels, expr ) ); 566 }; 567 568 // xxx - should reach in and determine if base type is concurrent? 569 bool TypeFuncGenerator::isConcurrentType() const { return false; }; 570 571 // opaque types do not have field constructors 572 void TypeFuncGenerator::genFieldCtors() {}; 573 574 //============================================================================================= 575 // Visitor definitions 576 //============================================================================================= 541 } 542 543 declsToAdd.push_back( ctorDecl ); 544 declsToAdd.push_back( copyCtorDecl ); 545 declsToAdd.push_back( dtorDecl ); 546 declsToAdd.push_back( assignDecl ); // assignment should come last since it uses copy constructor in return 547 declsToAdd.splice( declsToAdd.end(), memCtors ); 548 } 549 577 550 AutogenerateRoutines::AutogenerateRoutines() { 578 551 // the order here determines the order that these functions are generated. 579 552 // assignment should come last since it uses copy constructor in return. 580 data.emplace_back( "?{}", genDefaultType );581 data.emplace_back( "?{}", genCopyType );582 data.emplace_back( "^?{}", genDefaultType );583 data.emplace_back( "?=?", genAssignType );553 data.emplace_back( "?{}", genDefaultType, constructable ); 554 data.emplace_back( "?{}", genCopyType, copyable ); 555 data.emplace_back( "^?{}", genDefaultType, destructable ); 556 data.emplace_back( "?=?", genAssignType, assignable ); 584 557 } 585 558 586 559 void AutogenerateRoutines::previsit( EnumDecl * enumDecl ) { 587 // must visit children (enum constants) to add them to the indexer 588 if ( enumDecl->has_body() ) { 589 EnumInstType enumInst( Type::Qualifiers(), enumDecl->get_name() ); 590 enumInst.set_baseEnum( enumDecl ); 591 EnumFuncGenerator gen( &enumInst, data, functionNesting, indexer ); 592 generateFunctions( gen, declsToAddAfter ); 560 visit_children = false; 561 if ( ! enumDecl->get_members().empty() ) { 562 EnumInstType *enumInst = new EnumInstType( Type::Qualifiers(), enumDecl->get_name() ); 563 // enumInst->set_baseEnum( enumDecl ); 564 makeEnumFunctions( enumInst, functionNesting, declsToAddAfter ); 593 565 } 594 566 } … … 596 568 void AutogenerateRoutines::previsit( StructDecl * structDecl ) { 597 569 visit_children = false; 598 if ( structDecl->has_body() ) {570 if ( structDecl->has_body() && structsDone.find( structDecl->name ) == structsDone.end() ) { 599 571 StructInstType structInst( Type::Qualifiers(), structDecl->name ); 572 for ( TypeDecl * typeDecl : structDecl->parameters ) { 573 // need to visit assertions so that they are added to the appropriate maps 574 acceptAll( typeDecl->assertions, *visitor ); 575 structInst.parameters.push_back( new TypeExpr( new TypeInstType( Type::Qualifiers(), typeDecl->name, typeDecl ) ) ); 576 } 600 577 structInst.set_baseStruct( structDecl ); 601 for ( TypeDecl * typeDecl : structDecl->parameters ) { 602 structInst.parameters.push_back( new TypeExpr( new TypeInstType( Type::Qualifiers(), typeDecl->name, typeDecl ) ) ); 603 } 604 StructFuncGenerator gen( structDecl, &structInst, data, functionNesting, indexer ); 605 generateFunctions( gen, declsToAddAfter ); 578 makeStructFunctions( structDecl, &structInst, functionNesting, declsToAddAfter, data ); 579 structsDone.insert( structDecl->name ); 606 580 } // if 607 581 } … … 609 583 void AutogenerateRoutines::previsit( UnionDecl * unionDecl ) { 610 584 visit_children = false; 611 if ( unionDecl->has_body()) {585 if ( ! unionDecl->get_members().empty() ) { 612 586 UnionInstType unionInst( Type::Qualifiers(), unionDecl->get_name() ); 613 587 unionInst.set_baseUnion( unionDecl ); … … 615 589 unionInst.get_parameters().push_back( new TypeExpr( new TypeInstType( Type::Qualifiers(), typeDecl->get_name(), typeDecl ) ) ); 616 590 } 617 UnionFuncGenerator gen( unionDecl, &unionInst, data, functionNesting, indexer ); 618 generateFunctions( gen, declsToAddAfter ); 591 makeUnionFunctions( unionDecl, &unionInst, functionNesting, declsToAddAfter ); 619 592 } // if 593 } 594 595 Type * declToTypeDeclBase( Declaration * decl ) { 596 if ( TypeDecl * td = dynamic_cast< TypeDecl * >( decl ) ) { 597 return td->base; 598 } 599 return nullptr; 620 600 } 621 601 … … 625 605 if ( ! typeDecl->base ) return; 626 606 607 // generate each of the functions based on the supplied FuncData objects 608 std::list< FunctionDecl * > newFuncs; 609 std::list< Declaration * > tds { typeDecl }; 610 std::list< TypeDecl * > typeParams; 627 611 TypeInstType refType( Type::Qualifiers(), typeDecl->name, typeDecl ); 628 TypeFuncGenerator gen( typeDecl, &refType, data, functionNesting, indexer ); 629 generateFunctions( gen, declsToAddAfter ); 612 auto generator = makeFuncGenerator( lazy_map( tds, declToTypeDeclBase ), &refType, functionNesting, typeParams, back_inserter( newFuncs ) ); 613 for ( const FuncData & d : data ) { 614 generator.gen( d, false ); 615 } 616 617 if ( functionNesting == 0 ) { 618 // forward declare if top-level struct, so that 619 // type is complete as soon as its body ends 620 // Note: this is necessary if we want structs which contain 621 // generic (otype) structs as members. 622 for ( FunctionDecl * dcl : newFuncs ) { 623 addForwardDecl( dcl, declsToAddAfter ); 624 } 625 } 626 627 for ( FunctionDecl * dcl : newFuncs ) { 628 FunctionType * ftype = dcl->type; 629 assertf( ftype->parameters.size() == 1 || ftype->parameters.size() == 2, "Incorrect number of parameters in autogenerated typedecl function: %zd", ftype->parameters.size() ); 630 DeclarationWithType * dst = ftype->parameters.front(); 631 DeclarationWithType * src = ftype->parameters.size() == 2 ? ftype->parameters.back() : nullptr; 632 // generate appropriate calls to member ctor, assignment 633 // destructor needs to do everything in reverse, so pass "forward" based on whether the function is a destructor 634 UntypedExpr * expr = new UntypedExpr( new NameExpr( dcl->name ) ); 635 expr->args.push_back( new CastExpr( new VariableExpr( dst ), new ReferenceType( Type::Qualifiers(), typeDecl->base->clone() ) ) ); 636 if ( src ) expr->args.push_back( new CastExpr( new VariableExpr( src ), typeDecl->base->clone() ) ); 637 dcl->statements->kids.push_back( new ExprStmt( noLabels, expr ) ); 638 if ( CodeGen::isAssignment( dcl->get_name() ) ) { 639 // assignment needs to return a value 640 FunctionType * assignType = dcl->type; 641 assert( assignType->parameters.size() == 2 ); 642 ObjectDecl * srcParam = strict_dynamic_cast< ObjectDecl * >( assignType->parameters.back() ); 643 dcl->statements->kids.push_back( new ReturnStmt( noLabels, new VariableExpr( srcParam ) ) ); 644 } 645 declsToAddAfter.push_back( dcl ); 646 } 630 647 } 631 648 … … 648 665 visit_children = false; 649 666 // record the existence of this function as appropriate 650 managedTypes.handleDWT( functionDecl ); 667 insert( functionDecl, constructable, InitTweak::isDefaultConstructor ); 668 insert( functionDecl, assignable, InitTweak::isAssignment ); 669 insert( functionDecl, copyable, InitTweak::isCopyConstructor ); 670 insert( functionDecl, destructable, InitTweak::isDestructor ); 651 671 652 672 maybeAccept( functionDecl->type, *visitor ); … … 657 677 658 678 void AutogenerateRoutines::previsit( CompoundStmt * ) { 659 GuardScope( managedTypes ); 679 GuardScope( constructable ); 680 GuardScope( assignable ); 681 GuardScope( copyable ); 682 GuardScope( destructable ); 660 683 GuardScope( structsDone ); 661 684 }
Note:
See TracChangeset
for help on using the changeset viewer.