Changeset 8984003
- Timestamp:
- Nov 21, 2023, 4:47:58 PM (2 years ago)
- Branches:
- master
- Children:
- 53dac82
- Parents:
- c36a419
- Location:
- src
- Files:
-
- 8 edited
-
InitTweak/FixGlobalInit.cc (modified) (1 diff)
-
InitTweak/FixGlobalInit.h (modified) (1 diff)
-
InitTweak/FixInit.h (modified) (2 diffs)
-
InitTweak/GenInit.cc (modified) (2 diffs)
-
InitTweak/GenInit.h (modified) (1 diff)
-
InitTweak/InitTweak.cc (modified) (9 diffs)
-
InitTweak/InitTweak.h (modified) (1 diff)
-
SymTab/Mangler.cc (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
src/InitTweak/FixGlobalInit.cc
rc36a419 r8984003 27 27 28 28 namespace InitTweak { 29 class GlobalFixer : public ast::WithShortCircuiting {30 public:31 void previsit (const ast::ObjectDecl *);32 void previsit (const ast::FunctionDecl *) { visit_children = false; }33 void previsit (const ast::StructDecl *) { visit_children = false; }34 void previsit (const ast::UnionDecl *) { visit_children = false; }35 void previsit (const ast::EnumDecl *) { visit_children = false; }36 void previsit (const ast::TraitDecl *) { visit_children = false; }37 void previsit (const ast::TypeDecl *) { visit_children = false; }38 29 39 std::list< ast::ptr<ast::Stmt> > initStmts; 40 std::list< ast::ptr<ast::Stmt> > destroyStmts; 41 }; 30 namespace { 42 31 43 void fixGlobalInit(ast::TranslationUnit & translationUnit, bool inLibrary) { 44 ast::Pass<GlobalFixer> fixer; 45 accept_all(translationUnit, fixer); 32 class GlobalFixer : public ast::WithShortCircuiting { 33 public: 34 void previsit(const ast::ObjectDecl *); 35 void previsit(const ast::FunctionDecl *) { visit_children = false; } 36 void previsit(const ast::StructDecl *) { visit_children = false; } 37 void previsit(const ast::UnionDecl *) { visit_children = false; } 38 void previsit(const ast::EnumDecl *) { visit_children = false; } 39 void previsit(const ast::TraitDecl *) { visit_children = false; } 40 void previsit(const ast::TypeDecl *) { visit_children = false; } 46 41 47 // Say these magic declarations come at the end of the file. 48 CodeLocation const & location = translationUnit.decls.back()->location; 42 std::list< ast::ptr<ast::Stmt> > initStmts; 43 std::list< ast::ptr<ast::Stmt> > destroyStmts; 44 }; 49 45 50 if ( !fixer.core.initStmts.empty() ) { 51 std::vector<ast::ptr<ast::Expr>> ctorParams; 52 if (inLibrary) ctorParams.emplace_back(ast::ConstantExpr::from_int(location, 200)); 53 auto initFunction = new ast::FunctionDecl(location, 54 "__global_init__", {}, {}, {}, 55 new ast::CompoundStmt(location, std::move(fixer.core.initStmts)), 56 ast::Storage::Static, ast::Linkage::C, 57 {new ast::Attribute("constructor", std::move(ctorParams))}); 46 void GlobalFixer::previsit(const ast::ObjectDecl * objDecl) { 47 auto mutDecl = mutate(objDecl); 48 assertf(mutDecl == objDecl, "Global object decl must be unique"); 49 auto ctorInit = objDecl->init.as<ast::ConstructorInit>(); 50 if ( nullptr == ctorInit ) return; 58 51 59 translationUnit.decls.emplace_back( initFunction );60 } // if52 // a decision should have been made by the resolver, so ctor and init are not both non-NULL 53 assert( !ctorInit->ctor || !ctorInit->init ); 61 54 62 if ( !fixer.core.destroyStmts.empty() ) { 63 std::vector<ast::ptr<ast::Expr>> dtorParams; 64 if (inLibrary) dtorParams.emplace_back(ast::ConstantExpr::from_int(location, 200)); 65 auto destroyFunction = new ast::FunctionDecl( location, 66 "__global_destroy__", {}, {}, {}, 67 new ast::CompoundStmt(location, std::move(fixer.core.destroyStmts)), 68 ast::Storage::Static, ast::Linkage::C, 69 {new ast::Attribute("destructor", std::move(dtorParams))}); 55 const ast::Stmt * dtor = ctorInit->dtor; 56 if ( dtor && !isIntrinsicSingleArgCallStmt( dtor ) ) { 57 // don't need to call intrinsic dtor, because it does nothing, but 58 // non-intrinsic dtors must be called 59 destroyStmts.push_front( dtor ); 60 } // if 61 if ( const ast::Stmt * ctor = ctorInit->ctor ) { 62 addDataSectionAttribute(mutDecl); 63 initStmts.push_back( ctor ); 64 mutDecl->init = nullptr; 65 } else if ( const ast::Init * init = ctorInit->init ) { 66 mutDecl->init = init; 67 } else { 68 // no constructor and no initializer, which is okay 69 mutDecl->init = nullptr; 70 } 71 } 70 72 71 translationUnit.decls.emplace_back(destroyFunction); 72 } // if 73 } 73 } // namespace 74 74 75 void GlobalFixer::previsit(const ast::ObjectDecl * objDecl) { 76 auto mutDecl = mutate(objDecl); 77 assertf(mutDecl == objDecl, "Global object decl must be unique"); 78 if ( auto ctorInit = objDecl->init.as<ast::ConstructorInit>() ) { 79 // a decision should have been made by the resolver, so ctor and init are not both non-NULL 80 assert( ! ctorInit->ctor || ! ctorInit->init ); 75 void fixGlobalInit(ast::TranslationUnit & translationUnit, bool inLibrary) { 76 ast::Pass<GlobalFixer> fixer; 77 accept_all(translationUnit, fixer); 81 78 82 const ast::Stmt * dtor = ctorInit->dtor; 83 if ( dtor && ! isIntrinsicSingleArgCallStmt( dtor ) ) { 84 // don't need to call intrinsic dtor, because it does nothing, but 85 // non-intrinsic dtors must be called 86 destroyStmts.push_front( dtor ); 87 // ctorInit->dtor = nullptr; 88 } // if 89 if ( const ast::Stmt * ctor = ctorInit->ctor ) { 90 addDataSectionAttribute(mutDecl); 91 initStmts.push_back( ctor ); 92 mutDecl->init = nullptr; 93 // ctorInit->ctor = nullptr; 94 } else if ( const ast::Init * init = ctorInit->init ) { 95 mutDecl->init = init; 96 // ctorInit->init = nullptr; 97 } else { 98 // no constructor and no initializer, which is okay 99 mutDecl->init = nullptr; 100 } // if 101 // delete ctorInit; 102 } // if 103 } 79 // Say these magic declarations come at the end of the file. 80 CodeLocation const & location = translationUnit.decls.back()->location; 81 82 if ( !fixer.core.initStmts.empty() ) { 83 std::vector<ast::ptr<ast::Expr>> ctorParams; 84 if (inLibrary) ctorParams.emplace_back(ast::ConstantExpr::from_int(location, 200)); 85 auto initFunction = new ast::FunctionDecl(location, 86 "__global_init__", {}, {}, {}, 87 new ast::CompoundStmt(location, std::move(fixer.core.initStmts)), 88 ast::Storage::Static, ast::Linkage::C, 89 {new ast::Attribute("constructor", std::move(ctorParams))}); 90 91 translationUnit.decls.emplace_back( initFunction ); 92 } // if 93 94 if ( !fixer.core.destroyStmts.empty() ) { 95 std::vector<ast::ptr<ast::Expr>> dtorParams; 96 if (inLibrary) dtorParams.emplace_back(ast::ConstantExpr::from_int(location, 200)); 97 auto destroyFunction = new ast::FunctionDecl( location, 98 "__global_destroy__", {}, {}, {}, 99 new ast::CompoundStmt(location, std::move(fixer.core.destroyStmts)), 100 ast::Storage::Static, ast::Linkage::C, 101 {new ast::Attribute("destructor", std::move(dtorParams))}); 102 103 translationUnit.decls.emplace_back(destroyFunction); 104 } // if 105 } 104 106 105 107 } // namespace InitTweak -
src/InitTweak/FixGlobalInit.h
rc36a419 r8984003 16 16 #pragma once 17 17 18 #include <list> // for list 19 #include <string> // for string 20 21 #include <AST/Fwd.hpp> 22 23 24 class Declaration; 18 namespace ast { 19 class TranslationUnit; 20 } 25 21 26 22 namespace InitTweak { 27 /// Moves global initialization into an _init function that is unique to the translation unit. 28 /// Sets the priority of the initialization function depending on whether the initialization 29 /// function is for library code. 30 void fixGlobalInit( std::list< Declaration * > & translationUnit, bool inLibrary ); 31 void fixGlobalInit( ast::TranslationUnit & translationUnit, bool inLibrary ); 23 24 /// Moves global initialization into an _init function that is unique to the translation unit. 25 /// Sets the priority of the initialization function depending on whether the initialization 26 /// function is for library code. 27 void fixGlobalInit( ast::TranslationUnit & translationUnit, bool inLibrary ); 28 32 29 } // namespace 33 30 -
src/InitTweak/FixInit.h
rc36a419 r8984003 16 16 #pragma once 17 17 18 #include <list> // for list19 #include <string> // for string20 21 class Declaration;22 18 namespace ast { 23 19 class TranslationUnit; … … 25 21 26 22 namespace InitTweak { 27 /// replace constructor initializers with expression statements and unwrap basic C-style initializers28 void fix( std::list< Declaration * > & translationUnit, bool inLibrary );29 23 30 void fix( ast::TranslationUnit & translationUnit, bool inLibrary); 24 /// Replace constructor initializers with expression statements and unwrap basic C-style initializers. 25 void fix( ast::TranslationUnit & translationUnit, bool inLibrary); 26 31 27 } // namespace 32 28 -
src/InitTweak/GenInit.cc
rc36a419 r8984003 206 206 }; 207 207 208 209 210 211 208 struct ReturnFixer final : 212 209 public ast::WithStmtsToAdd<>, ast::WithGuards, ast::WithShortCircuiting { … … 262 259 } // namespace 263 260 264 void genInit( ast::TranslationUnit & transUnit ) {265 ast::Pass<HoistArrayDimension_NoResolve>::run( transUnit );266 ast::Pass<ReturnFixer>::run( transUnit );267 }268 269 void fixReturnStatements( ast::TranslationUnit & transUnit ) {270 ast::Pass<ReturnFixer>::run( transUnit );271 }272 273 bool ManagedTypes::isManaged( const ast::Type * type ) const {274 // references are never constructed275 if ( dynamic_cast< const ast::ReferenceType * >( type ) ) return false;276 if ( auto tupleType = dynamic_cast< const ast::TupleType * > ( type ) ) {277 // tuple is also managed if any of its components are managed278 for (auto & component : tupleType->types) {279 if (isManaged(component)) return true;280 }281 }282 // need to clear and reset qualifiers when determining if a type is managed283 // ValueGuard< Type::Qualifiers > qualifiers( type->get_qualifiers() );284 auto tmp = shallowCopy(type);285 tmp->qualifiers = {};286 // delete tmp at return287 ast::ptr<ast::Type> guard = tmp;288 // 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)289 return managedTypes.find( Mangle::mangle( tmp, {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) ) != managedTypes.end() || GenPoly::isPolyType( tmp );290 }291 292 bool ManagedTypes::isManaged( const ast::ObjectDecl * objDecl ) const {293 const ast::Type * type = objDecl->type;294 while ( auto at = dynamic_cast< const ast::ArrayType * >( type ) ) {295 // must always construct VLAs with an initializer, since this is an error in C296 if ( at->isVarLen && objDecl->init ) return true;297 type = at->base;298 }299 return isManaged( type );300 }301 302 void ManagedTypes::handleDWT( const ast::DeclWithType * dwt ) {303 // if this function is a user-defined constructor or destructor, mark down the type as "managed"304 if ( ! dwt->linkage.is_overrideable && CodeGen::isCtorDtor( dwt->name ) ) {305 auto & params = GenPoly::getFunctionType( dwt->get_type())->params;306 assert( ! params.empty() );307 // Type * type = InitTweak::getPointerBase( params.front() );308 // assert( type );309 managedTypes.insert( Mangle::mangle( params.front(), {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) );310 }311 }312 313 void ManagedTypes::handleStruct( const ast::StructDecl * aggregateDecl ) {314 // don't construct members, but need to take note if there is a managed member,315 // because that means that this type is also managed316 for ( auto & member : aggregateDecl->members ) {317 if ( auto field = member.as<ast::ObjectDecl>() ) {318 if ( isManaged( field ) ) {319 // generic parameters should not play a role in determining whether a generic type is constructed - construct all generic types, so that320 // polymorphic constructors make generic types managed types321 ast::StructInstType inst( aggregateDecl );322 managedTypes.insert( Mangle::mangle( &inst, {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) );323 break;324 }325 }326 }327 }328 329 void ManagedTypes::beginScope() { managedTypes.beginScope(); }330 void ManagedTypes::endScope() { managedTypes.endScope(); }331 332 ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg) {333 assertf(objDecl, "genCtorDtor passed null objDecl");334 InitExpander srcParam(arg);335 return SymTab::genImplicitCall(srcParam, new ast::VariableExpr(loc, objDecl), loc, fname, objDecl);336 }261 void genInit( ast::TranslationUnit & transUnit ) { 262 ast::Pass<HoistArrayDimension_NoResolve>::run( transUnit ); 263 ast::Pass<ReturnFixer>::run( transUnit ); 264 } 265 266 void fixReturnStatements( ast::TranslationUnit & transUnit ) { 267 ast::Pass<ReturnFixer>::run( transUnit ); 268 } 269 270 bool ManagedTypes::isManaged( const ast::Type * type ) const { 271 // references are never constructed 272 if ( dynamic_cast< const ast::ReferenceType * >( type ) ) return false; 273 if ( auto tupleType = dynamic_cast< const ast::TupleType * > ( type ) ) { 274 // tuple is also managed if any of its components are managed 275 for (auto & component : tupleType->types) { 276 if (isManaged(component)) return true; 277 } 278 } 279 // need to clear and reset qualifiers when determining if a type is managed 280 // ValueGuard< Type::Qualifiers > qualifiers( type->get_qualifiers() ); 281 auto tmp = shallowCopy(type); 282 tmp->qualifiers = {}; 283 // delete tmp at return 284 ast::ptr<ast::Type> guard = tmp; 285 // 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) 286 return managedTypes.find( Mangle::mangle( tmp, {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) ) != managedTypes.end() || GenPoly::isPolyType( tmp ); 287 } 288 289 bool ManagedTypes::isManaged( const ast::ObjectDecl * objDecl ) const { 290 const ast::Type * type = objDecl->type; 291 while ( auto at = dynamic_cast< const ast::ArrayType * >( type ) ) { 292 // must always construct VLAs with an initializer, since this is an error in C 293 if ( at->isVarLen && objDecl->init ) return true; 294 type = at->base; 295 } 296 return isManaged( type ); 297 } 298 299 void ManagedTypes::handleDWT( const ast::DeclWithType * dwt ) { 300 // if this function is a user-defined constructor or destructor, mark down the type as "managed" 301 if ( ! dwt->linkage.is_overrideable && CodeGen::isCtorDtor( dwt->name ) ) { 302 auto & params = GenPoly::getFunctionType( dwt->get_type())->params; 303 assert( ! params.empty() ); 304 // Type * type = InitTweak::getPointerBase( params.front() ); 305 // assert( type ); 306 managedTypes.insert( Mangle::mangle( params.front(), {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) ); 307 } 308 } 309 310 void ManagedTypes::handleStruct( const ast::StructDecl * aggregateDecl ) { 311 // don't construct members, but need to take note if there is a managed member, 312 // because that means that this type is also managed 313 for ( auto & member : aggregateDecl->members ) { 314 if ( auto field = member.as<ast::ObjectDecl>() ) { 315 if ( isManaged( field ) ) { 316 // generic parameters should not play a role in determining whether a generic type is constructed - construct all generic types, so that 317 // polymorphic constructors make generic types managed types 318 ast::StructInstType inst( aggregateDecl ); 319 managedTypes.insert( Mangle::mangle( &inst, {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) ); 320 break; 321 } 322 } 323 } 324 } 325 326 void ManagedTypes::beginScope() { managedTypes.beginScope(); } 327 void ManagedTypes::endScope() { managedTypes.endScope(); } 328 329 ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg) { 330 assertf(objDecl, "genCtorDtor passed null objDecl"); 331 InitExpander srcParam(arg); 332 return SymTab::genImplicitCall(srcParam, new ast::VariableExpr(loc, objDecl), loc, fname, objDecl); 333 } 337 334 338 335 ast::ConstructorInit * genCtorInit( const CodeLocation & loc, const ast::ObjectDecl * objDecl ) { -
src/InitTweak/GenInit.h
rc36a419 r8984003 24 24 25 25 namespace InitTweak { 26 /// Adds return value temporaries and wraps Initializers in ConstructorInit nodes27 void genInit( ast::TranslationUnit & translationUnit );28 26 29 /// Converts return statements into copy constructor calls on the hidden return variable. 30 /// This pass must happen before auto-gen. 31 void fixReturnStatements( ast::TranslationUnit & translationUnit ); 27 /// Adds return value temporaries and wraps Initializers in ConstructorInit nodes 28 void genInit( ast::TranslationUnit & translationUnit ); 32 29 33 /// generates a single ctor/dtor statement using objDecl as the 'this' parameter and arg as the optional argument 34 ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg = nullptr); 30 /// Converts return statements into copy constructor calls on the hidden return variable. 31 /// This pass must happen before auto-gen. 32 void fixReturnStatements( ast::TranslationUnit & translationUnit ); 35 33 36 /// creates an appropriate ConstructorInit node which contains a constructor, destructor, and C-initializer 37 ast::ConstructorInit * genCtorInit( const CodeLocation & loc, const ast::ObjectDecl * objDecl);34 /// generates a single ctor/dtor statement using objDecl as the 'this' parameter and arg as the optional argument 35 ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg = nullptr); 38 36 39 class ManagedTypes final { 40 public: 41 bool isManaged( const ast::ObjectDecl * objDecl ) const ; // determine if object is managed 42 bool isManaged( const ast::Type * type ) const; // determine if type is managed 37 /// creates an appropriate ConstructorInit node which contains a constructor, destructor, and C-initializer 38 ast::ConstructorInit * genCtorInit( const CodeLocation & loc, const ast::ObjectDecl * objDecl ); 43 39 44 void handleDWT( const ast::DeclWithType * dwt ); // add type to managed if ctor/dtor 45 void handleStruct( const ast::StructDecl * aggregateDecl ); // add type to managed if child is managed 40 class ManagedTypes final { 41 public: 42 bool isManaged( const ast::ObjectDecl * objDecl ) const ; // determine if object is managed 43 bool isManaged( const ast::Type * type ) const; // determine if type is managed 46 44 47 void beginScope(); 48 void endScope(); 49 private: 50 GenPoly::ScopedSet< std::string > managedTypes; 51 }; 45 void handleDWT( const ast::DeclWithType * dwt ); // add type to managed if ctor/dtor 46 void handleStruct( const ast::StructDecl * aggregateDecl ); // add type to managed if child is managed 47 48 void beginScope(); 49 void endScope(); 50 private: 51 GenPoly::ScopedSet< std::string > managedTypes; 52 }; 53 52 54 } // namespace 53 55 -
src/InitTweak/InitTweak.cc
rc36a419 r8984003 14 14 // 15 15 16 #include "InitTweak.h" 17 16 18 #include <algorithm> // for find, all_of 17 19 #include <cassert> // for assertf, assert, strict_dynamic_cast … … 30 32 #include "CodeGen/OperatorTable.h" // for isConstructor, isDestructor, isCto... 31 33 #include "Common/SemanticError.h" // for SemanticError 34 #include "Common/ToString.hpp" // for toCString 32 35 #include "Common/UniqueName.h" // for UniqueName 33 #include "Common/utility.h" // for toString, deleteAll, maybeClone34 36 #include "GenPoly/GenPoly.h" // for getFunctionType 35 #include "InitTweak.h"36 37 #include "ResolvExpr/Unify.h" // for typesCompatibleIgnoreQualifiers 37 38 #include "Tuples/Tuples.h" // for Tuples::isTtype 38 39 39 40 namespace InitTweak { 40 namespace { 41 struct HasDesignations : public ast::WithShortCircuiting { 42 bool result = false; 43 44 void previsit( const ast::Node * ) { 45 // short circuit if we already know there are designations 46 if ( result ) visit_children = false; 47 } 48 49 void previsit( const ast::Designation * des ) { 50 // short circuit if we already know there are designations 51 if ( result ) visit_children = false; 52 else if ( ! des->designators.empty() ) { 53 result = true; 54 visit_children = false; 55 } 56 } 57 }; 58 59 struct InitDepthChecker { 60 bool result = true; 61 const ast::Type * type; 62 int curDepth = 0, maxDepth = 0; 63 InitDepthChecker( const ast::Type * type ) : type( type ) { 64 const ast::Type * t = type; 65 while ( auto at = dynamic_cast< const ast::ArrayType * >( t ) ) { 66 maxDepth++; 67 t = at->base; 68 } 69 maxDepth++; 70 } 71 void previsit( ast::ListInit const * ) { 72 curDepth++; 73 if ( curDepth > maxDepth ) result = false; 74 } 75 void postvisit( ast::ListInit const * ) { 76 curDepth--; 77 } 78 }; 79 80 struct InitFlattener : public ast::WithShortCircuiting { 81 std::vector< ast::ptr< ast::Expr > > argList; 82 83 void previsit( const ast::SingleInit * singleInit ) { 84 visit_children = false; 85 argList.emplace_back( singleInit->value ); 86 } 87 }; 88 89 } // anonymous namespace 90 91 bool isDesignated( const ast::Init * init ) { 92 ast::Pass<HasDesignations> finder; 93 maybe_accept( init, finder ); 94 return finder.core.result; 95 } 96 97 bool checkInitDepth( const ast::ObjectDecl * objDecl ) { 98 ast::Pass<InitDepthChecker> checker( objDecl->type ); 99 maybe_accept( objDecl->init.get(), checker ); 100 return checker.core.result; 101 } 102 103 std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init ) { 104 ast::Pass< InitFlattener > flattener; 105 maybe_accept( init, flattener ); 106 return std::move( flattener.core.argList ); 107 } 108 41 42 // Forward declared, because it is used as a parent type. 109 43 class InitExpander::ExpanderImpl { 110 44 public: … … 116 50 117 51 namespace { 52 struct HasDesignations : public ast::WithShortCircuiting { 53 bool result = false; 54 55 void previsit( const ast::Node * ) { 56 // Short circuit if we already know there are designations. 57 if ( result ) visit_children = false; 58 } 59 60 void previsit( const ast::Designation * des ) { 61 // Short circuit if we already know there are designations. 62 if ( result ) visit_children = false; 63 else if ( !des->designators.empty() ) { 64 result = true; 65 visit_children = false; 66 } 67 } 68 }; 69 70 struct InitDepthChecker { 71 bool result = true; 72 const ast::Type * type; 73 int curDepth = 0, maxDepth = 0; 74 InitDepthChecker( const ast::Type * type ) : type( type ) { 75 const ast::Type * t = type; 76 while ( auto at = dynamic_cast< const ast::ArrayType * >( t ) ) { 77 maxDepth++; 78 t = at->base; 79 } 80 maxDepth++; 81 } 82 void previsit( ast::ListInit const * ) { 83 curDepth++; 84 if ( curDepth > maxDepth ) result = false; 85 } 86 void postvisit( ast::ListInit const * ) { 87 curDepth--; 88 } 89 }; 90 91 struct InitFlattener : public ast::WithShortCircuiting { 92 std::vector< ast::ptr< ast::Expr > > argList; 93 94 void previsit( const ast::SingleInit * singleInit ) { 95 visit_children = false; 96 argList.emplace_back( singleInit->value ); 97 } 98 }; 99 118 100 template< typename Out > 119 101 void buildCallExpr( … … 223 205 InitExpander::IndexList & indices 224 206 ) override { 225 if ( ! arg ) return {};207 if ( !arg ) return {}; 226 208 227 209 const CodeLocation & loc = arg->location; 228 210 const ast::Expr * expr = arg; 229 211 for ( auto it = indices.rbegin(); it != indices.rend(); ++it ) { 230 // go through indices and layer on subscript exprs ?[?]212 // Go through indices and layer on subscript exprs ?[?]. 231 213 ++it; 232 214 expr = new ast::UntypedExpr{ … … 242 224 } 243 225 }; 244 } // anonymous namespace245 246 InitExpander::InitExpander( const ast::Init * init )247 : expander( new InitImpl{ init } ), crnt(), indices() {}248 249 InitExpander::InitExpander( const ast::Expr * expr )250 : expander( new ExprImpl{ expr } ), crnt(), indices() {}251 252 std::vector< ast::ptr< ast::Expr > > InitExpander::operator* () { return crnt; }253 254 InitExpander & InitExpander::operator++ () {255 crnt = expander->next( indices );256 return *this;257 }258 259 /// builds statement which has the same semantics as a C-style list initializer (for array260 /// initializers) using callExpr as the base expression to perform initialization261 ast::ptr< ast::Stmt > InitExpander::buildListInit( ast::UntypedExpr * callExpr ) {262 return expander->buildListInit( callExpr, indices );263 }264 265 void InitExpander::addArrayIndex( const ast::Expr * index, const ast::Expr * dimension ) {266 indices.emplace_back( index );267 indices.emplace_back( dimension );268 }269 270 void InitExpander::clearArrayIndices() { indices.clear(); }271 272 bool InitExpander::addReference() {273 for ( ast::ptr< ast::Expr > & expr : crnt ) {274 expr = new ast::AddressExpr{ expr };275 }276 return ! crnt.empty();277 }278 279 const ast::Type * getTypeofThis( const ast::FunctionType * ftype ) {280 assertf( ftype, "getTypeofThis: nullptr ftype" );281 const std::vector<ast::ptr<ast::Type>> & params = ftype->params;282 assertf( !params.empty(), "getTypeofThis: ftype with 0 parameters: %s",283 toString( ftype ).c_str() );284 const ast::ReferenceType * refType =285 params.front().strict_as<ast::ReferenceType>();286 return refType->base;287 }288 289 const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func) {290 assertf( func, "getParamThis: nullptr ftype" );291 auto & params = func->params;292 assertf( ! params.empty(), "getParamThis: ftype with 0 parameters: %s", toString( func ).c_str());293 return params.front().strict_as<ast::ObjectDecl>();294 }295 296 bool tryConstruct( const ast::DeclWithType * dwt ) {297 auto objDecl = dynamic_cast< const ast::ObjectDecl * >( dwt );298 if ( ! objDecl ) return false;299 return (objDecl->init == nullptr ||300 ( objDecl->init != nullptr && objDecl->init->maybeConstructed ))301 && ! objDecl->storage.is_extern302 && isConstructable( objDecl->type );303 }304 305 bool isConstructable( const ast::Type * type ) {306 return ! dynamic_cast< const ast::VarArgsType * >( type ) && ! dynamic_cast< const ast::ReferenceType * >( type )307 && ! dynamic_cast< const ast::FunctionType * >( type ) && ! Tuples::isTtype( type );308 }309 226 310 227 struct CallFinder final { … … 325 242 }; 326 243 327 std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ) { 328 ast::Pass< CallFinder > finder{ std::vector< std::string >{ "?{}", "^?{}" } }; 329 maybe_accept( stmt, finder ); 330 return std::move( finder.core.matches ); 331 } 332 333 namespace { 334 template <typename Predicate> 335 bool allofCtorDtor( const ast::Stmt * stmt, const Predicate & pred ) { 336 std::vector< const ast::Expr * > callExprs = collectCtorDtorCalls( stmt ); 337 return std::all_of( callExprs.begin(), callExprs.end(), pred ); 338 } 339 } 340 341 bool isIntrinsicSingleArgCallStmt( const ast::Stmt * stmt ) { 342 return allofCtorDtor( stmt, []( const ast::Expr * callExpr ){ 343 if ( const ast::ApplicationExpr * appExpr = isIntrinsicCallExpr( callExpr ) ) { 344 const ast::FunctionType * funcType = 345 GenPoly::getFunctionType( appExpr->func->result ); 346 assert( funcType ); 347 return funcType->params.size() == 1; 348 } 349 return false; 350 }); 351 } 352 353 // looks like some other such codegen uses UntypedExpr and does not create fake function. should revisit afterwards 354 // following passes may accidentally resolve this expression if returned as untyped... 355 ast::Expr * createBitwiseAssignment (const ast::Expr * dst, const ast::Expr * src) { 356 static ast::ptr<ast::FunctionDecl> assign = nullptr; 357 if (!assign) { 358 auto td = new ast::TypeDecl(CodeLocation(), "T", {}, nullptr, ast::TypeDecl::Dtype, true); 359 assign = new ast::FunctionDecl(CodeLocation(), "?=?", {td}, 360 { new ast::ObjectDecl(CodeLocation(), "_dst", new ast::ReferenceType(new ast::TypeInstType("T", td))), 361 new ast::ObjectDecl(CodeLocation(), "_src", new ast::TypeInstType("T", td))}, 362 { new ast::ObjectDecl(CodeLocation(), "_ret", new ast::TypeInstType("T", td))}, nullptr, {}, ast::Linkage::Intrinsic); 363 } 364 if (dst->result.as<ast::ReferenceType>()) { 365 for (int depth = dst->result->referenceDepth(); depth > 0; depth--) { 366 dst = new ast::AddressExpr(dst); 367 } 368 } else { 369 dst = new ast::CastExpr(dst, new ast::ReferenceType(dst->result, {})); 370 } 371 if (src->result.as<ast::ReferenceType>()) { 372 for (int depth = src->result->referenceDepth(); depth > 0; depth--) { 373 src = new ast::AddressExpr(src); 374 } 375 } 376 auto var = ast::VariableExpr::functionPointer(dst->location, assign); 377 auto app = new ast::ApplicationExpr(dst->location, var, {dst, src}); 378 // Skip the resolver, just set the result to the correct type. 379 app->result = ast::deepCopy( src->result ); 380 return app; 244 template <typename Predicate> 245 bool allofCtorDtor( const ast::Stmt * stmt, const Predicate & pred ) { 246 std::vector< const ast::Expr * > callExprs = collectCtorDtorCalls( stmt ); 247 return std::all_of( callExprs.begin(), callExprs.end(), pred ); 381 248 } 382 249 383 250 struct ConstExprChecker : public ast::WithShortCircuiting { 384 // most expressions are not const expr251 // Most expressions are not const-expr. 385 252 void previsit( const ast::Expr * ) { result = false; visit_children = false; } 386 253 … … 389 256 const ast::Expr * arg = addressExpr->arg; 390 257 391 // address of a variable or member expression is constexpr392 if ( ! dynamic_cast< const ast::NameExpr * >( arg )393 && !dynamic_cast< const ast::VariableExpr * >( arg )394 && !dynamic_cast< const ast::MemberExpr * >( arg )395 && !dynamic_cast< const ast::UntypedMemberExpr * >( arg ) ) result = false;396 } 397 398 // these expressions may be const expr, depending on their children258 // Address of a variable or member expression is const-expr. 259 if ( !dynamic_cast< const ast::NameExpr * >( arg ) 260 && !dynamic_cast< const ast::VariableExpr * >( arg ) 261 && !dynamic_cast< const ast::MemberExpr * >( arg ) 262 && !dynamic_cast< const ast::UntypedMemberExpr * >( arg ) ) result = false; 263 } 264 265 // These expressions may be const expr, depending on their children. 399 266 void previsit( const ast::SizeofExpr * ) {} 400 267 void previsit( const ast::AlignofExpr * ) {} … … 423 290 bool result = true; 424 291 }; 425 426 bool isConstExpr( const ast::Expr * expr ) { 427 if ( expr ) { 428 ast::Pass<ConstExprChecker> checker; 429 expr->accept( checker ); 430 return checker.core.result; 431 } 432 return true; 433 } 434 435 bool isConstExpr( const ast::Init * init ) { 436 if ( init ) { 437 ast::Pass<ConstExprChecker> checker; 438 init->accept( checker ); 439 return checker.core.result; 440 } // if 441 // for all intents and purposes, no initializer means const expr 442 return true; 443 } 292 } // namespace 444 293 445 294 bool isAssignment( const ast::FunctionDecl * decl ) { … … 470 319 } 471 320 472 #if defined( __x86_64 ) || defined( __i386 ) // assembler comment to prevent assembler warning message 473 #define ASM_COMMENT "#" 474 #else // defined( __ARM_ARCH ) 475 #define ASM_COMMENT "//" 476 #endif 477 static const char * const data_section = ".data" ASM_COMMENT; 478 static const char * const tlsd_section = ".tdata" ASM_COMMENT; 479 480 void addDataSectionAttribute( ast::ObjectDecl * objDecl ) { 481 const bool is_tls = objDecl->storage.is_threadlocal_any(); 482 const char * section = is_tls ? tlsd_section : data_section; 483 objDecl->attributes.push_back(new ast::Attribute("section", { 484 ast::ConstantExpr::from_string(objDecl->location, section) 485 })); 486 } 321 const ast::Type * getTypeofThis( const ast::FunctionType * ftype ) { 322 assertf( ftype, "getTypeofThis: nullptr ftype" ); 323 const std::vector<ast::ptr<ast::Type>> & params = ftype->params; 324 assertf( !params.empty(), "getTypeofThis: ftype with 0 parameters: %s", 325 toCString( ftype ) ); 326 const ast::ReferenceType * refType = 327 params.front().strict_as<ast::ReferenceType>(); 328 return refType->base; 329 } 330 331 const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func) { 332 assertf( func, "getParamThis: nullptr ftype" ); 333 auto & params = func->params; 334 assertf( !params.empty(), "getParamThis: ftype with 0 parameters: %s", toCString( func )); 335 return params.front().strict_as<ast::ObjectDecl>(); 336 } 337 338 // looks like some other such codegen uses UntypedExpr and does not create fake function. should revisit afterwards 339 // following passes may accidentally resolve this expression if returned as untyped... 340 ast::Expr * createBitwiseAssignment(const ast::Expr * dst, const ast::Expr * src) { 341 static ast::ptr<ast::FunctionDecl> assign = nullptr; 342 if (!assign) { 343 auto td = new ast::TypeDecl(CodeLocation(), "T", {}, nullptr, ast::TypeDecl::Dtype, true); 344 assign = new ast::FunctionDecl(CodeLocation(), "?=?", {td}, 345 { new ast::ObjectDecl(CodeLocation(), "_dst", new ast::ReferenceType(new ast::TypeInstType("T", td))), 346 new ast::ObjectDecl(CodeLocation(), "_src", new ast::TypeInstType("T", td))}, 347 { new ast::ObjectDecl(CodeLocation(), "_ret", new ast::TypeInstType("T", td))}, nullptr, {}, ast::Linkage::Intrinsic); 348 } 349 if (dst->result.as<ast::ReferenceType>()) { 350 for (int depth = dst->result->referenceDepth(); depth > 0; depth--) { 351 dst = new ast::AddressExpr(dst); 352 } 353 } else { 354 dst = new ast::CastExpr(dst, new ast::ReferenceType(dst->result, {})); 355 } 356 if (src->result.as<ast::ReferenceType>()) { 357 for (int depth = src->result->referenceDepth(); depth > 0; depth--) { 358 src = new ast::AddressExpr(src); 359 } 360 } 361 auto var = ast::VariableExpr::functionPointer(dst->location, assign); 362 auto app = new ast::ApplicationExpr(dst->location, var, {dst, src}); 363 // Skip the resolver, just set the result to the correct type. 364 app->result = ast::deepCopy( src->result ); 365 return app; 366 } 367 368 std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init ) { 369 ast::Pass< InitFlattener > flattener; 370 maybe_accept( init, flattener ); 371 return std::move( flattener.core.argList ); 372 } 373 374 bool tryConstruct( const ast::DeclWithType * dwt ) { 375 auto objDecl = dynamic_cast< const ast::ObjectDecl * >( dwt ); 376 if ( !objDecl ) return false; 377 return (objDecl->init == nullptr || 378 ( objDecl->init != nullptr && objDecl->init->maybeConstructed )) 379 && !objDecl->storage.is_extern 380 && isConstructable( objDecl->type ); 381 } 382 383 bool isConstructable( const ast::Type * type ) { 384 return !dynamic_cast< const ast::VarArgsType * >( type ) && !dynamic_cast< const ast::ReferenceType * >( type ) 385 && !dynamic_cast< const ast::FunctionType * >( type ) && !Tuples::isTtype( type ); 386 } 387 388 bool isDesignated( const ast::Init * init ) { 389 // return ( init ) ? ast::Pass<HasDesignations>::read( init ) : false; 390 ast::Pass<HasDesignations> finder; 391 maybe_accept( init, finder ); 392 return finder.core.result; 393 } 394 395 bool checkInitDepth( const ast::ObjectDecl * objDecl ) { 396 // return ( objDecl->init ) ? ast::Pass<InitDepthChecker::read( objDecl->init, objDecl->type ) : true; 397 ast::Pass<InitDepthChecker> checker( objDecl->type ); 398 maybe_accept( objDecl->init.get(), checker ); 399 return checker.core.result; 400 } 401 402 bool isIntrinsicSingleArgCallStmt( const ast::Stmt * stmt ) { 403 return allofCtorDtor( stmt, []( const ast::Expr * callExpr ){ 404 if ( const ast::ApplicationExpr * appExpr = isIntrinsicCallExpr( callExpr ) ) { 405 const ast::FunctionType * funcType = 406 GenPoly::getFunctionType( appExpr->func->result ); 407 assert( funcType ); 408 return funcType->params.size() == 1; 409 } 410 return false; 411 }); 412 } 413 414 std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ) { 415 ast::Pass< CallFinder > finder{ std::vector< std::string >{ "?{}", "^?{}" } }; 416 maybe_accept( stmt, finder ); 417 return std::move( finder.core.matches ); 418 } 419 420 bool isConstExpr( const ast::Expr * expr ) { 421 return ( expr ) ? ast::Pass<ConstExprChecker>::read( expr ) : true; 422 } 423 424 bool isConstExpr( const ast::Init * init ) { 425 // for all intents and purposes, no initializer means const expr 426 return ( init ) ? ast::Pass<ConstExprChecker>::read( init ) : true; 427 } 428 429 #if defined( __x86_64 ) || defined( __i386 ) // assembler comment to prevent assembler warning message 430 #define ASM_COMMENT "#" 431 #else // defined( __ARM_ARCH ) 432 #define ASM_COMMENT "//" 433 #endif 434 static const char * const data_section = ".data" ASM_COMMENT; 435 static const char * const tlsd_section = ".tdata" ASM_COMMENT; 436 437 void addDataSectionAttribute( ast::ObjectDecl * objDecl ) { 438 const bool is_tls = objDecl->storage.is_threadlocal_any(); 439 const char * section = is_tls ? tlsd_section : data_section; 440 objDecl->attributes.push_back(new ast::Attribute("section", { 441 ast::ConstantExpr::from_string(objDecl->location, section) 442 })); 443 } 444 445 InitExpander::InitExpander( const ast::Init * init ) 446 : expander( new InitImpl{ init } ), crnt(), indices() {} 447 448 InitExpander::InitExpander( const ast::Expr * expr ) 449 : expander( new ExprImpl{ expr } ), crnt(), indices() {} 450 451 std::vector< ast::ptr< ast::Expr > > InitExpander::operator* () { return crnt; } 452 453 InitExpander & InitExpander::operator++ () { 454 crnt = expander->next( indices ); 455 return *this; 456 } 457 458 /// builds statement which has the same semantics as a C-style list initializer (for array 459 /// initializers) using callExpr as the base expression to perform initialization 460 ast::ptr< ast::Stmt > InitExpander::buildListInit( ast::UntypedExpr * callExpr ) { 461 return expander->buildListInit( callExpr, indices ); 462 } 463 464 void InitExpander::addArrayIndex( const ast::Expr * index, const ast::Expr * dimension ) { 465 indices.emplace_back( index ); 466 indices.emplace_back( dimension ); 467 } 468 469 void InitExpander::clearArrayIndices() { indices.clear(); } 470 471 bool InitExpander::addReference() { 472 for ( ast::ptr< ast::Expr > & expr : crnt ) { 473 expr = new ast::AddressExpr{ expr }; 474 } 475 return !crnt.empty(); 476 } 487 477 488 478 } // namespace InitTweak -
src/InitTweak/InitTweak.h
rc36a419 r8984003 25 25 // helper functions for initialization 26 26 namespace InitTweak { 27 bool isAssignment( const ast::FunctionDecl * decl );28 bool isDestructor( const ast::FunctionDecl * decl );29 bool isDefaultConstructor( const ast::FunctionDecl * decl );30 bool isCopyConstructor( const ast::FunctionDecl * decl );31 bool isCopyFunction( const ast::FunctionDecl * decl );32 27 33 /// returns the base type of the first parameter to a constructor/destructor/assignment function 34 const ast::Type * getTypeofThis( const ast::FunctionType * ftype ); 28 bool isAssignment( const ast::FunctionDecl * decl ); 29 bool isDestructor( const ast::FunctionDecl * decl ); 30 bool isDefaultConstructor( const ast::FunctionDecl * decl ); 31 bool isCopyConstructor( const ast::FunctionDecl * decl ); 32 bool isCopyFunction( const ast::FunctionDecl * decl ); 35 33 36 /// returns the first parameter ofa constructor/destructor/assignment function37 const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func);34 /// returns the base type of the first parameter to a constructor/destructor/assignment function 35 const ast::Type * getTypeofThis( const ast::FunctionType * ftype ); 38 36 39 /// generate a bitwise assignment operation. 40 ast::Expr * createBitwiseAssignment( const ast::Expr * dst, const ast::Expr * src);37 /// returns the first parameter of a constructor/destructor/assignment function 38 const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func); 41 39 42 /// transform Initializer into an argument list that can be passed to a call expression 43 std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init);40 /// generate a bitwise assignment operation. 41 ast::Expr * createBitwiseAssignment( const ast::Expr * dst, const ast::Expr * src); 44 42 45 /// True if the resolver should try to construct dwt 46 bool tryConstruct( const ast::DeclWithType * dwt );43 /// transform Initializer into an argument list that can be passed to a call expression 44 std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init ); 47 45 48 /// True if the type can have a user-defined constructor 49 bool isConstructable( const ast::Type *t );46 /// True if the resolver should try to construct dwt 47 bool tryConstruct( const ast::DeclWithType * dwt ); 50 48 51 /// True if the Initializer contains designations 52 bool isDesignated( const ast::Init * init );49 /// True if the type can have a user-defined constructor 50 bool isConstructable( const ast::Type * t ); 53 51 54 /// True if the ObjectDecl's Initializer nesting level is not deeper than the depth of its 55 /// type, where the depth of its type is the number of nested ArrayTypes + 1 56 bool checkInitDepth( const ast::ObjectDecl * objDecl ); 52 /// True if the Initializer contains designations 53 bool isDesignated( const ast::Init * init ); 57 54 58 /// True if stmt is a call statement where the function called is intrinsic and takes one parameter. 59 /// Intended to be used for default ctor/dtor calls, but might have use elsewhere. 60 /// Currently has assertions that make it less than fully general. 61 bool isIntrinsicSingleArgCallStmt( const ast::Stmt * stmt ); 55 /// True if the ObjectDecl's Initializer nesting level is not deeper than the depth of its 56 /// type, where the depth of its type is the number of nested ArrayTypes + 1 57 bool checkInitDepth( const ast::ObjectDecl * objDecl ); 62 58 63 /// get all Ctor/Dtor call expressions from a Statement 64 std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ); 59 /// True if stmt is a call statement where the function called is intrinsic and takes one parameter. 60 /// Intended to be used for default ctor/dtor calls, but might have use elsewhere. 61 /// Currently has assertions that make it less than fully general. 62 bool isIntrinsicSingleArgCallStmt( const ast::Stmt * stmt ); 65 63 66 /// returns true if expr is trivially a compile-time constant 67 bool isConstExpr( const ast::Expr * expr ); 68 bool isConstExpr( const ast::Init * init ); 64 /// get all Ctor/Dtor call expressions from a Statement 65 std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ); 69 66 70 /// Modifies objDecl to have: 71 /// __attribute__((section (".data#"))) 72 /// which makes gcc put the declared variable in the data section, 73 /// which is helpful for global constants on newer gcc versions, 74 /// so that CFA's generated initialization won't segfault when writing it via a const cast. 75 /// The trailing # is an injected assembly comment, to suppress the "a" in 76 /// .section .data,"a" 77 /// .section .data#,"a" 78 /// to avoid assembler warning "ignoring changed section attributes for .data" 79 void addDataSectionAttribute( ast::ObjectDecl * objDecl ); 67 /// returns true if expr is trivially a compile-time constant 68 bool isConstExpr( const ast::Expr * expr ); 69 bool isConstExpr( const ast::Init * init ); 80 70 81 class InitExpander final { 82 public: 83 using IndexList = std::vector< ast::ptr< ast::Expr > >; 84 class ExpanderImpl; 71 /// Modifies objDecl to have: 72 /// __attribute__((section (".data#"))) 73 /// which makes gcc put the declared variable in the data section, 74 /// which is helpful for global constants on newer gcc versions, 75 /// so that CFA's generated initialization won't segfault when writing it via a const cast. 76 /// The trailing # is an injected assembly comment, to suppress the "a" in 77 /// .section .data,"a" 78 /// .section .data#,"a" 79 /// to avoid assembler warning "ignoring changed section attributes for .data" 80 void addDataSectionAttribute( ast::ObjectDecl * objDecl ); 85 81 86 private: 87 std::shared_ptr< ExpanderImpl > expander; 88 std::vector< ast::ptr< ast::Expr > > crnt; 89 // invariant: list of size 2N (elements come in pairs [index, dimension]) 90 IndexList indices; 82 class InitExpander final { 83 public: 84 using IndexList = std::vector< ast::ptr< ast::Expr > >; 85 class ExpanderImpl; 91 86 92 public: 93 /// Expand by stepping through init to get each list of arguments 94 InitExpander( const ast::Init * init ); 87 private: 88 std::shared_ptr< ExpanderImpl > expander; 89 std::vector< ast::ptr< ast::Expr > > crnt; 90 // invariant: list of size 2N (elements come in pairs [index, dimension]) 91 IndexList indices; 95 92 96 /// Always expand to expression 97 InitExpander( const ast::Expr * expr ); 93 public: 94 /// Expand by stepping through init to get each list of arguments 95 InitExpander( const ast::Init * init ); 98 96 99 std::vector< ast::ptr< ast::Expr > > operator* ();100 InitExpander & operator++ ();97 /// Always expand to expression 98 InitExpander( const ast::Expr * expr ); 101 99 102 /// builds statement which has the same semantics as a C-style list initializer (for array 103 /// initializers) using callExpr as the base expression to perform initialization. 104 /// Mutates callExpr 105 ast::ptr< ast::Stmt > buildListInit( ast::UntypedExpr * callExpr ); 100 std::vector< ast::ptr< ast::Expr > > operator* (); 101 InitExpander & operator++ (); 106 102 107 void addArrayIndex( const ast::Expr * index, const ast::Expr * dimension ); 103 /// builds statement which has the same semantics as a C-style list initializer (for array 104 /// initializers) using callExpr as the base expression to perform initialization. 105 /// Mutates callExpr 106 ast::ptr< ast::Stmt > buildListInit( ast::UntypedExpr * callExpr ); 108 107 109 void clearArrayIndices();108 void addArrayIndex( const ast::Expr * index, const ast::Expr * dimension ); 110 109 111 bool addReference(); 112 }; 110 void clearArrayIndices(); 111 112 bool addReference(); 113 }; 114 113 115 } // namespace InitTweak 114 116 -
src/SymTab/Mangler.cc
rc36a419 r8984003 341 341 } 342 342 343 } // namespace343 } // namespace 344 344 345 345 std::string mangle( const ast::Node * decl, Mangle::Mode mode ) {
Note:
See TracChangeset
for help on using the changeset viewer.